MyTT 指标库

MyTT(My麦语言 T通达信 T同花顺)是一个简单易用的Python库,它将通达信、同花顺、文华麦语言等指标公式最简化移植到了Python中,实现的常见指标包括MACD、RSI、BOLL、ATR、KDJ、CCI、PSY等。MyTT全部基于numpy和pandas的函数进行封装。

为了方便用户在DolphinDB中计算这些技术指标,我们使用DolphinDB脚本实现了MyTT中包含的指标函数,并封装在DolphinDB mytt module中。 相比于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指标库中的函数。在DolphinDB V1.30.19和DolphinDB V2.00.7支持了BARSLAST, BARSLASTCOUNT, TOPRANGE, LOWRANGE函数在流式增量计算引擎中的使用。在DolphinDB V1.30.21和DolphinDB V2.00.9中CROSS函数与DolphinDB内置变量名冲突,函数名修改为CROSS_

匹配不同DolphinDB版本的mytt module:

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模块文件放入该目录即可。

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库

测试结果如下表所示:

序号函数Python(ms)DolphinDB(ms)运行时间比
1RD2961618
2RET2431318
3ABS2291515
4LN2532510
5POW3113010
6SQRT2481913
7MAX3903411
8MIN3732912
9IF2822113
10REF7401743
11DIFF6622230
12STD1,2632498
13SUM1,2972258
14CONST2582211
15HHV1,2073040
16LLV1,2183139
17HHVBARS2,9524172
18LLVBARS2,8783875
19MA1,2202450
20EMA1,1712645
21SMA1,1992842
22WMA4,32220216
23DMA1,1232741
24AVEDEV176,652325,520
25SLOPE53,703291,851
26FORCAST60,321381,587
27LAST4,13238108
28COUNT1,2492062
29EVERY1,2672845
30EXIST1,4902267
31BARSLAST5591831
32BARSLASTCOUNT6071735
33CROSS_2,0888026
34LONGCROSS6,0199464
35VALUEWHEN9682735
36BETWEEN4894211
37TOPRANGE3,6473799
38LOWRANGE3,70336103
39MACD3,0608635
40KDJ4,70514432
41RSI2,53910324
42WR5,63216633
43BIAS5,31813539
44BOLL3,0679034
45PSY2,5968231
46CCI163,681762,153
47ATR2,28110122
48BBI3,6676655
49DMI6,18125024
50TAQ2,2926435
51KTN3,17016419
52TRIX4,3299744
53VR2,73211723
54EMV4,43713233
55DPO2,4555941
56BRAR4,90915631
57DFMA2,8905255
58MTM1,6594338
59MASS4,6029946
60ROC2,0006331
61EXPMA1,9004938
62OBV1,7909419
63MFI3,48815822
64ASI4,17331613

从测试结果分析可知:

  • 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. 正确性验证

基于分组使用性能对比中的测试数据和代码,验证 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。

5.3. TOPRANGE、LOWRANGE 计算结果差异问题

TOPRANGE函数是统计S序列的某个元素是近多少周期内的最大值,TOPRANGE(High)表示创多少日新高。

mytt模块中的TOPRANGE函数与MyTT中的TOPRANGE函数在头部数据的计算中有差异,如下图所示,High序列16.95, 17.31, 17.34其TOPRANGE分别为创0日新高,1日新高,2日新高。MyTT在数据先下降再上升之后才开始统计创多少日新高,而mytt模块则从数据头部就开始统计创多少日新高。从而造成数据头部的计算结果会有差异。



LOWRANGE函数与上述情况相同。

6. 实时流计算案例

在DolphinDB V1.30.3 中发布的响应式状态引擎(createReactiveStateEngine)是许多金融场景流批统一计算中的重要构件,DolphinDB mytt module在开发时就对其做了适配,使得mytt模块中的大部分函数可以在响应式状态引擎中实现增量计算。

  • 无需支持在响应式状态引擎的中使用的函数:RET, CONST

  • 所有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. 核心工具函数

函数语法解释
RDRN(N, D = 3)四舍五入取3位小数
RETRET(S, N = 1)返回序列倒数第N个值,默认返回最后一个
ABSABS(S)返回序列或数值S的绝对值
LNLN(S)求序列S底是e的自然对数
POWPOW(S, N)求序列S的N次方
SQRTSQRT(S)求序列S的平方根
MAXMAX(S1, S2)配对比较两个序列,给出比较以后大的序列
MINMIN(S1, S2)配对比较两个序列,给出比较以后小的序列
IFIF(S, A, B)序列布尔判断,if S == True return A else B
REFREF(S, N = 1)对序列整体下移动N个单位,返回平移后的序列,会产生NAN
DIFFDIFF(S, N = 1)序列S的前一个值减后一个值,序列头部会产生NAN
STDSTD(S, N)求序列S的滚动N日标准差,返回滚动标准差序列
SUMSUM(S, N)对序列S求滚动N日总和
CONSTCOUNT(S)返回序列S最后一个值组成常量序列
HHVHHV(S, N)求序列S的滚动N日最大值,返回滚动最大值序列
LLVLLV(S, N)求序列S的滚动N日最小值,返回滚动最小值序列
HHVBARSHHVBARS(S, N)求序列S的滚动N期内最高值到当前的天数, 返回距离天数序列
LLVBARSLLVBARS(S, N)求序列S的滚动N期内最低值到当前的天数, 返回距离天数序列
MAMA(S, N)求序列S的N日简单移动平均值,返回移动平均序列
EMAEMA(S, N)求序列S的指数移动平均,为了精度,S>4*N,EMA至少需要120周期alpha = 2/(span+1)
SMASMA(S, N, M = 1)中国式的SMA,至少需要120周期才精确 (雪球180周期),alpha = 1/(1+N)
WMAWMA(S, N)求S序列S的N日加权移动平均,Yn = (1*X1+2*X2+3*X3+...+n*Xn)/(1+2+3+...+n)
DMADMA(S, A)求S的动态移动平均,A作平滑因子,必须 0 < A < 1
AVEDEVAVEDEV(S, N)求序列S的滚动平均绝对偏差
SLOPESLOPE(S, N)求序列S的滚动N周期内的线性回归模型的斜率
FORCASTFORCAST(S, N)求序列S的滚动N周期内的线性回归模型的预测值
LAST_LAST_(S, A, B)BOOL型判断,从前A日到前B日一直满足BOOL条件,要求A > B & A > 0 & B >= 0

7.2. 应用层函数(通过核心工具函数实现)

函数语法解释
COUNTCOUNT(S, N)序列S是BOOL型,求最滚动N天内满足BOOL为True的天数
EVERYEVERY(S, N)序列S是BOOL型,求最滚动N天内全部满足BOOL为True的天数
EXISTEXIST(S, N)序列S是BOOL型,判断最滚动N天内是否存在满足BOOL为True
BARSLASTBARSLAST(S)序列S是BOOL型,统计上一次条件成立到当前的周期
BARSLASTCOUNTBARSLASTCOUNT(S)序列S是BOOL型,统计连续满足条件的周期数
BARSSINCENBARSSINCEN(S, N)序列S是BOOL型,统计滚动周期N内第一次满足条件到当前的周期数
CROSS_CROSS_(S1, S2)判断两个序列是否交叉的函数,判断向上金叉穿越 CROSS_(MA(C,5),MA(C,10)) ,判断向下死叉穿越 CROSS_(MA(C,10),MA(C,5))
LONGCROSSLONGCROSS(S1, S2, N)判断两个序列是否在个持一定周期后再交叉的函数,判断两个序列是否再个持N周期后再交叉,N = 1时等同于CROSS_(S1, S2)
VALUEWHENVALUEWHEN(S, X)解决当S条件成立时,取X的当前值,否则取S的上个成立时对应的X值
BETWEENBETWEEN(S, A, B)判断S序列是否介于A和B之间的函数,当S处于A和B之间时为真,包括 A<S<B 或 A>S>B
TOPRANGETOPRANGE(S)统计S序列的某个元素是近多少周期内的最大值
LOWRANGELOWRANGE(S)统计S序列的某个元素是近多少周期内的最小值

7.3. 技术指标函数(全部通过核心工具和应用函数实现)

函数语法解释
MACDMACD(CLOSE, SHORT = 12, LONG = 26, M = 9)平滑异同平均线
KDJKDJ(CLOSE, HIGH, LOW, N = 9, M1 = 3, M2 = 3)KDJ指标
RSIRSI(CLOSE, N = 24)RSI指标,和通达信小数点2位相同
WRWR(CLOSE, HIGH, LOW, N = 10, N1 = 6)W&R 威廉指标
BIASBIAS(CLOSE, L1 = 6, L2 = 12, L3 = 24)BIAS乖离率
BOLLBOLL(CLOSE, N = 20, P = 2)BOLL指标,布林带
PSYPSY(CLOSE, N = 12, M = 6)PSY指标,心理线
CCICCI(CLOSE, HIGH, LOW, N = 14)CCI指标,顺势线
ATRATR(CLOSE, HIGH, LOW, N = 20)真实波动N日平均值
BBIBBI(CLOSE, M1 = 3, M2 = 6, M3 = 12, M4 = 20)BBI多空指标
DMIDMI(CLOSE, HIGH, LOW, M1 = 14, M2 = 6)DMI动向指标
TAQTAQ(HIGH, LOW, N)唐安奇通道(海龟)交易指标
KTNKTN(CLOSE, HIGH, LOW, N = 20, M = 10)肯特纳交易通道
TRIXTRIX(CLOSE, M1 = 12, M2 = 20)三重指数平滑平均线
VRVR(CLOSE, VOL, M1 = 26)VR容量比率
EMVEMV(HIGH, LOW, VOL, N = 14, M = 9)EMV简易波动指标
DPODPO(CLOSE, M1 = 20, M2 = 10, M3 = 6)区间震荡线
BRARBRAR(OPEN, CLOSE, HIGH, LOW, M1 = 26)BRAR-ARBR 情绪指标
DFMADFMA(CLOSE, N1 = 10, N2 = 50, M = 10)DFMA平行线差指标
MTMMTM(CLOSE, N = 12, M = 6)MTM动量指标
MASSMASS(HIGH, LOW, N1 = 9, N2 = 25, M = 6)梅斯线
ROCROC(CLOSE, N = 12, M = 6)变动率指标
EXPMAEXPMA(CLOSE, N1 = 12, N2 = 50)指数平均数指标
OBVOBV(CLOSE, VOL)能量潮指标
MFIMFI(CLOSE, HIGH, LOW, VOL, N = 14)MFI资金流量
ASIASI(OPEN, CLOSE, HIGH, LOW, M1 = 26, M2 = 10)振动升降指标

8. 路线图(Road Map)

  • 长期保持对Python MyTT包的同步更新。