Skip to content

Latest commit

 

History

History
60 lines (54 loc) · 4.23 KB

加速.md

File metadata and controls

60 lines (54 loc) · 4.23 KB

加速

  1. 使用C语言等替代关键函数。如指标库TA-Lib就是用C语言实现的
  2. 减少跨语言调用次数。循环调用talib.SMA,还不如调用一次bottleneck.move_mean
  3. 易用性上,numba优于Cython。因为Cython对不同Python版本不同操作系统要分别编译,过于复杂

长表与宽表

  1. 长表
    1. 如同数据库,每一列为一个字段,如开高低收。必定有两个关键的列做为索引,一列表示股票代码,另一表示时间
    2. 两个索引中有大量重复值,如果只存一个字段利用率只有1/3,得存多个字段才经济
    3. 两个关键字段最好如同数据库一样建B+树索引,否则这两个字段可能因数据太多无法加载到内存
    4. 两个索引的排序先后也对速度有影响。
      1. 先时间分组。真实场景。数据也是按时间生成的。适合做横截面,比如同一天所有股票的涨跌幅排序
      2. 先股票分组,组内时间排序。适合历史分析。可以快速将一指股票取出,NaN也提前就drop了,计算技术指标也方便
    5. 复合索引存一个文件,其它每个字段一个文件,添加新字段时速度快
  2. 宽表
    1. 整表为一个字段,例如都为收盘价,列头为股票代码,索引为时间
    2. 由于上市时间有先后,二维矩阵会出现大量NaN,停牌也会出现NaN,空间利用率低
    3. 停牌中段出现的空值对talib这类的指标计算有影响,必须特别处理才行
    4. 整块存储时,一支股票为一列,这一列均匀分布在文件中,为了加载这列股票,整个文件都必须加载,超大文件时根本不可行
    5. 列式存储时,按整表取出,底层4000多支股票合并会占用大量空间和时间
    6. 两个索引一个文件,其它二维数据一个文件

技术指标计算难点

  1. 股票支数太多4000多支,talib至少要调用4000多次,单核很难在3s内下次行情推送过来前计算完成
  2. 由于GIL的原因,IO密集型可以用多线程,而计算密集型只能用多进程
    1. 多进程最大的问题是数据跨进程。数据序列化和反序列化才能传给子进程,而数据通常几个G,序列化不现实
    2. 共存内存和内存文件映射是一个不错的方案
      1. 宽表。大文件会被全量加载,内存吃紧
      2. 长表。索引需要一个好的机制
  3. 无论哪种方案都对大数据量都比较麻烦

方案

  1. 由于NaN处理实在麻烦
  2. 二维计算对各种指标库要求太高。

所以还是用长表,然后配合groupby比较方便,

  1. 算指标时按股票代码分组,按时间排序。为了加速,最好每天收盘后就做好排序整理
  2. 算横截面时按时间分组

指标计算简单了,但只利用到了单核,计算还是慢。文件还大。多进程时又受限于数据序列化

分治法

  1. 水平品种分割
    1. 4000支股票放在一个进程中处理不过来,放在4000多个文件也打开处理很慢。应当分组存放
    2. 通过股票代码后一位,可以均匀分布10个文件,10个进程分别处理
    3. 根据数据量的大小和CPU核数,可以最后两位分成100个,或100%5分成20个,需要进行取舍
  2. 垂直时序分割
    1. 数据长计算久,历史数据可以长数据,但对实时性要求高的部分则最好能计算最新部分的一小段
    2. 日线可以按年划分,分钟线可以按月划分
    3. 由于指标需要预加载部分数据,所以数据需要一段前一时段的行情
  3. 横截面处理
    1. 在4000支股票的长表数据分割到10个文件前可以进行基于基础行情的横载面的指标
    2. 如果已经划分到10个文件了,只能合并10个文件才能进行横载面计算,横截面处理的机会目前不多

数据处理流程

  1. 按天下载全部A股数据,比按支下载4000多次要快。所以数据原始格式为按天排序的长表
  2. 按年将表加载,然后统一表头,为今后可能切换数据源做预留
  3. 可以进行初步的横截面计算
  4. 股票按股票代码最后的数字进行分成10个文件,可以同时做一下
  5. 多进程对10个文件进行时序指标的计算
  6. 再考虑是否要合并计算横截面