MyTT 是一个简单易用的 Python 库,它将通达信、同花顺、文华麦语言等指标公式最简化移植到了 Python 中,实现的常见指标包括 MACD、RSI、BOLL、ATR、KDJ、CCI、PSY 等。MyTT 全部基于 numpy 和 pandas 的函数进行封装。
为了方便用户在 DolphinDB 中计算这些技术指标,我们使用 DolphinDB 脚本实现了 MyTT 中包含的指标函数,并封装在 DolphinDB mytt module (mytt.dos)中。 相比于 Python 中的 MyTT 库,DolphinDB mytt module 中的计算函数不仅在批处理中性能有大幅提升,而且支持 DolphinDB 的流式增量计算引擎,可以直接用于实时流计算场景。
因为 DolphinDB mytt module 是基于 DolphinDB V1.30.18 和 DolphinDB V2.00.6 开发的,所以建议用户使用 DolphinDB V1.30.18 和 DolphinDB V2.00.6 及以上版本运行 mytt 指标库中的函数。
1. 函数及参数的命名与用法规范
- Python MyTT 库中所有函数名大写,所有参数名大写,为适应使用者的使用习惯,DolphinDB mytt module 中的函数名、参数、参数默认值均与 MyTT 保持一致。
- 为得到有意义的计算结果,mytt 中函数的参数表示时间跨度的参数均要求至少是 2。
- 由于 LAST 函数与 DolphinDB 中内置关键字冲突,mytt 中将此函数命名为 LAST_。
2. 环境配置
把附件的 mytt.dos 放在节点的 [home]/modules 目录下,[home] 目录由系统配置参数 home 决定,可以通过 getHomeDir()
函数查看。初次使用模块文件时,[home]目录没有 modules 目录,手动创建 modules 目录,然后把 mytt.dos 模块文件放入该目录即可。
DolphinDB 模块使用的教程文档:DolphinDB 教程:模块
3. 使用范例
3.1 脚本中直接使用指标函数
对一个向量直接使用 mytt 模块中的 EMA
函数(指数平滑法)进行计算:
// 如果未设置自动加载 mytt module,新会话需要手动加载一次 mytt module
use mytt
close = 7.2 6.97 7.08 6.74 6.49 5.9 6.26 5.9 5.35 5.63
x = EMA(close, 5)
3.2 在 SQL 语句中分组使用
用户经常需要在数据表中对多组数据在每组内进行计算。在以下例子中,先构造了一个包含 2 个股票的数据表:
use mytt
close = 7.2 6.97 7.08 6.74 6.49 5.9 6.26 5.9 5.35 5.63 3.81 3.935 4.04 3.74 3.7 3.33 3.64 3.31 2.69 2.72
date = (2020.03.02 + 0..4 join 7..11).take(20)
symbol = take(`F,10) join take(`GPRO,10)
t = table(symbol, date, close)
对其中每只股票使用 mytt 模块中的 EMA
函数进行计算:
update t set EMA = EMA(close, 5) context by symbol
3.3 返回多个列的结果
某些函数会返回多个列的结果,例如函数 BIAS
(乘离率指标)。
直接使用的例子:
use mytt
close = 7.2 6.97 7.08 6.74 6.49 5.9 6.26 5.9 5.35 5.63
bias1, bias2, bias3 = BIAS(close, L1 = 2, L2 = 4, L3 = 6)
在 SQL 语句中使用的例子:
use mytt
close = 7.2 6.97 7.08 6.74 6.49 5.9 6.26 5.9 5.35 5.63 3.81 3.935 4.04 3.74 3.7 3.33 3.64 3.31 2.69 2.72
date = (2020.03.02 + 0..4 join 7..11).take(20)
symbol = take(`F,10) join take(`GPRO,10)
t = table(symbol, date, close)
select *, BIAS(close, L1 = 2, L2 = 4, L3 = 6) as `bias1`bias2`bias3 from t context by symbol
symbol date close bias1 bias2 bias3
------ ---------- ----- -------- -------- --------
F 2020.03.02 7.2
F 2020.03.03 6.97 -1.623
F 2020.03.04 7.08 0.783
F 2020.03.05 6.74 -2.46 -3.68
F 2020.03.06 6.49 -1.89 -4.839
F 2020.03.09 5.9 -4.762 -9.958 -12.333
F 2020.03.10 6.26 2.961 -1.378 -4.767
F 2020.03.11 5.9 -2.961 -3.87 -7.74
F 2020.03.12 5.35 -4.889 -8.586 -12.391
F 2020.03.13 5.63 2.55 -2.679 -4.925
GPRO 2020.03.02 3.81
GPRO 2020.03.03 3.935 1.614
GPRO 2020.03.04 4.04 1.317
GPRO 2020.03.05 3.74 -3.856 -3.639
GPRO 2020.03.06 3.7 -0.538 -3.99
GPRO 2020.03.09 3.33 -5.263 -10.061 -11.417
GPRO 2020.03.10 3.64 4.448 1.041 -2.435
GPRO 2020.03.11 3.31 -4.748 -5.293 -8.732
GPRO 2020.03.12 2.69 -10.333 -17.039 -20.921
GPRO 2020.03.13 2.72 0.555 -11.974 -15.833
4. 函数计算性能
本节将以 AVEDEV
函数为例做直接使用的性能对比,同时使用真实股票日频数据对所有函数进行分组使用性能对比。
4.1 直接使用性能对比
在 DolphinDB 中:
use mytt
close = 7.2 6.97 7.08 6.74 6.49 5.9 6.26 5.9 5.35 5.63
close = take(close, 100000)
timer x = mytt::AVEDEV(close, 100)
对一个长度为 100000 的向量直接使用 mytt 模块中的 AVEDEV
函数,耗时为 25ms。
与之对应的 Python 代码如下:
import numpy as np
from MyTT import *
import time
close = np.array([7.2,6.97,7.08,6.74,6.49,5.9,6.26,5.9,5.35,5.63])
close = np.tile(close,10000)
start_time = time.time()
x = AVEDEV(close, 100)
print("--- %s seconds ---" % (time.time() - start_time))
Python MyTT 库中的 AVEDEV
函数耗时为 25000ms,是 DolphinDB mytt module 中的 AVEDEV
函数的 1000 倍。测试数据量越大,性能差异越显著。
4.2 分组使用性能对比
- 测试数据为上海证券交易所 2020 年,全年 2919 个证券(筛选交易日大于 120)日频交易数据,总记录数为 686,104 条。
- 计算逻辑为按照股票代码进行分组计算各指标。
- 为了测试函数计算性能,DolphinDB 和 Python 测试代码都是单线程运行。
- DolphinDB 测试代码
- Python 测试代码
- 测试数据
- Python MyTT 库
测试结果如下表所示:
从测试结果分析可知:
- DolphinDB mytt module 中的函数计算性能远远超过 Python MyTT 库,最大的性能差距达到 5520 倍,普遍性能差距在 30 倍左右。
**Python pandas 测试核心代码 **
data.groupby("symbol").apply(lambda x: RSI(np.array(x.close), N = 24))
DolphinDB 测试核心代码
RSI = select symbol, tradedate, mytt::RSI(close, N=24) as `RSI from data context by symbol
5. 正确性验证
基于 4.2 分组使用性能对比中的测试数据和代码,验证 DolphinDB mytt module 中函数的计算结果是否和 Python MyTT 库一致。
5.1 浮点数精度问题
结果有差异的函数
CROSS, LONGCROSS
原因
- 浮点数精度问题
- 对于 CROSS 和 LONGCROSS 函数,在浮点数比较上,DolphinDB mytt module 中的处理比 Python MyTT 库更加严谨。DolphinDB mytt module 中首先会对浮点数 round 保留小数点后 6 位,然后再进行大小判断,而 MyTT 中并没有类似处理,因此对于相同大小的浮点数,Python 的判别可能会出错,如下图所示:
5.2 NULL 值的处理
结果有差异的函数
SUM, DMI, EMV, MASS, MFI, ASI
原因
- 若输入向量开始包含空值,则从第一个非空位置开始计算。DolphinDB mytt module 与 Python MyTT 库的计算规则一致。
- 对一个滚动 / 累积窗口长度为 k 的函数,每组最初的 (k-1) 个位置的结果均为空。DolphinDB mytt module 与 Python MyTT 库的计算规则一致。
- 对一个滚动 / 累积窗口长度为 k 的函数,若一组中第一个非空值之后再有空值,Python MyTT 库会对包含 nan 的窗口计算结果都处理为 nan。DolphinDB mytt module 会对窗口内非 NULL 的元素按计算规则计算,得到一个非 NULL 的计算结果。
DolphinDB 代码与结果:
close = [99.9, NULL, 84.69, 31.38, 60.9, 83.3, 97.26, 98.67]
mytt::SUM(close, 5);
[,,,,276.87, 260.27, 357.53, 371.51]
Python 代码与结果:
close = np.array([99.9, np.nan, 84.69, 31.38, 60.9, 83.3, 97.26, 98.67])
MyTT.SUM(close,5)
array([nan, nan, nan, nan, nan, nan, 357.53, 371.51])
以滑动窗口求和为例,close 向量的第 2 个元素为空值,DolphinDB mytt module 在计算第 5 个元素(60.9)时,回看过去 5 个窗口内的数据 [99.9, NULL, 84.69, 31.38, 60.9]
,对非 NULL 的元素求和,所以结果向量的第 5 个元素为 276.87。
Python MyTT 库会对包含 nan 的窗口计算结果都处理为 nan,所以结果向量的前 6 个元素都为 nan。
除上述因为浮点数精度问题和 NULL 值的处理问题导致计算结果存在差异外,其余函数计算结果的百分比误差均小于 1e-10。
6. 实时流计算案例
在 DolphinDB V1.30.3 中发布的响应式状态引擎(Reactive State Engine)是许多金融场景流批统一计算中的重要构件,DolphinDB mytt module 在开发时就对其做了适配,使得 mytt 模块中的大部分函数可以在响应式状态引擎中实现增量计算。
- 当前无法在响应式状态引擎中使用的指标函数:
RET, CONST, BARSLAST, BARSLASTCOUNT
,已经规划开发。 - 所有 mytt 中的 技术指标函数 均支持增量计算。
示例代码如下:
def cleanEnvironment(){
try{unsubscribeTable(tableName="snapshotStream",actionName="aggr1min") } catch(ex){ print(ex) }
try{dropStreamEngine("myttReactiveStateEngine") } catch(ex){ print(ex) }
try{dropStreamEngine("aggr1min") } catch(ex){ print(ex) }
try{dropStreamTable(`snapshotStream) } catch(ex){ print(ex) }
try{dropStreamTable(`outputTable) } catch(ex){ print(ex) }
undef all
}
cleanEnvironment()
go
//load modules
use mytt
//define stream table
name = `tradetime`SecurityID`high`low`open`close`vol
type = `TIMESTAMP`SYMBOL`DOUBLE`DOUBLE`DOUBLE`DOUBLE`INT
share streamTable(100:0, name, type) as snapshotStream
name = `SecurityID`tradetime`K`D`J`DIF`DEA`MACD`UPPER`MID`LOWER`ROC`MAROC
type = `SYMBOL`TIMESTAMP`DOUBLE`DOUBLE`DOUBLE`DOUBLE`DOUBLE`DOUBLE`DOUBLE`DOUBLE`DOUBLE`DOUBLE`DOUBLE
share streamTable(1000000:0, name, type) as outputTable
//register stream computing engine
reactiveStateMetrics=<[ tradetime, mytt::KDJ(close, high, low, N=9, M1=3, M2=3) as `K`D`J, mytt::MACD(close, SHORT_=12, LONG_=26, M=9) as `DIF`DEA`MACD, mytt::KTN(close, high, low, N=20, M=10) as `UPPER`MID`LOWER, mytt::ROC(close, N=12, M=6) as `ROC`MAROC]>
createReactiveStateEngine("myttReactiveStateEngine", metrics=reactiveStateMetrics, dummyTable=snapshotStream, outputTable=outputTable, keyColumn=`SecurityID, keepOrder=true)
createTimeSeriesEngine(name="aggr1min", windowSize=60000, step=60000, metrics=<[first(open),max(high),min(low),last(close),sum(vol)]>, dummyTable=snapshotStream, outputTable=getStreamEngine("myttReactiveStateEngine"), timeColumn=`tradetime, useWindowStartTime=true, keyColumn=`SecurityID)
subscribeTable(tableName="snapshotStream", actionName="aggr1min", offset=-1, handler=getStreamEngine("aggr1min"), msgAsTable=true, batchSize=2000, throttle=1, hash=0, reconnect=true)
7. DolphinDB mytt 指标列表
7.1 核心工具函数
7.2 应用层函数 (通过核心工具函数实现)
7.3 技术指标函数 (全部通过核心工具和应用函数实现)
8. 路线图(Road Map)
- 优化当前无法在响应式状态引擎中使用的指标函数,包括
RET, CONST, BARSLAST, BARSLASTCOUNT
,预计在 DolphinDB V1.30.19 和 DolphinDB V2.00.7 支持上述函数的增量计算和在响应式状态引擎中的使用。 - 长期保持对 Python MyTT 包的同步更新。
附件
计算性能测试环境
- CPU 类型:Intel(R) Core(TM) i7-7700 CPU @ 3.60GHz 3.60 GHz
- 逻辑 CPU 总数:8
- 内存:32GB
- OS:Windows 10