# xg_tdx_func **Repository Path**: fctz/xg_tdx_func ## Basic Information - **Project Name**: xg_tdx_func - **Description**: 通达信函数转化器 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2024-09-16 - **Last Updated**: 2024-09-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # xg_tdx_func #### 介绍 xg_tdx_func是一个用于将通达信公式转换为Python代码的库,来自网络的整合,自己的二次开发,学习使用,不做商业用途。通达信是一款流行的股票分析软件,其内置了丰富的公式语言,用于编写股票分析和策略。然而,有时候用户可能需要将这些公式应用到其他平台或环境中,例如Python数据分析和机器学习项目。这时,xg_tdx_func库就派上了用场。 xg_tdx_func库的主要功能是将通达信公式转换为Python代码,以便在Python环境中执行。它支持多种通达信公式函数,包括技术指标、条件判断、数学运算等。通过使用xg_tdx_func库,用户可以方便地将通达信公式移植到Python项目中,实现更灵活的数据分析和策略开发。 #### 软件架构 模型来自实盘交易系统综合交易模型 ``` print('操作方式,登录qmt,选择行情加交易选,择极简模式') print('作者:小果') print('作者微信:15117320079,开实盘qmt可以联系我,开户也可以') print('作者微信公众号:数据分析与运用') print('公众号链接:https://mp.weixin.qq.com/s/rxGJpZYxdUIHitjvI-US1A') print("作者知识星球:金融量化交易研究院 https://t.zsxq.com/19VzjjXNi") ``` #### 安装教程 python 建议使用3.9 下载xg_tdx)func当作第三方库使用就可以 可能需要这个安装vscode++2022,如果不行我后面我剔除一下不需要的内容 ![输入图片说明](image.png) ![输入图片说明](image2image.png) #### 使用说明 ### **一使用例子** ### 例子1通达信波段BS买卖指标 ``` from xg_tdx_func.xg_tdx_func import * import pandas as pd import akshare as ak class band_bs_trading: def __init__(self,df): ''' 波段BS买卖 ''' self.df=df def band_bs_trading(self): ''' 输出MA5:收盘价的5日简单移动平均 输出MA10:收盘价的10日简单移动平均,画黄色 输出MA20:收盘价的20日简单移动平均 输出MA30:收盘价的30日简单移动平均,画白色 输出MA120:收盘价的120日简单移动平均,画绿色,POINTDOT 输出MA240:收盘价的240日简单移动平均,画红色,POINTDOT A1赋值:如果收盘价>=MA5,返回1,否则返回-1 A2赋值:如果收盘价>=MA10,返回1,否则返回-1 A3赋值:如果收盘价>=MA20,返回1,否则返回-1 A4赋值:如果MA5>=1日前的MA5,返回1,否则返回-1 A5赋值:如果MA10>=1日前的MA10,返回1,否则返回-1 A6赋值:如果MA20>=1日前的MA20,返回1,否则返回-1 QUSHIX赋值:(A1+A2+A3+A4+A5+A6)/6*100,画青色,线宽为3 X1赋值:(收盘价+最低价+最高价)/3 X2赋值:X1的6日指数移动平均 X3赋值:X2的5日指数移动平均 当满足条件X2上穿X3时,在最低价*0.98位置书写文字 当满足条件X3上穿X2时,在最高价*1.02位置书写文字 当满足条件X2>=X3时,在最低价和最高价位置之间画柱状线,宽度为0,0不为0则画空心柱.,画红色 当满足条件X2>=X3时,在收盘价和开盘价位置之间画柱状线,宽度为3,1不为0则画空心柱.,画红色 当满足条件X2=100ANDMA5>1日前的MA5AND(收盘价-开盘价)/开盘价*100>5ANDCLOSE>MA5时,在最低价*0.99位置书写文字,画洋红色 ''' data=pd.DataFrame() data['date']=self.df['date'] C=self.df['close'] CLOSE=self.df['close'] L=self.df['low'] LOW=self.df['low'] H=self.df['high'] HIGH=self.df['high'] OPEN=self.df['open'] MA5=MA(C,5) MA10=MA(C,10) MA20=MA(C,20) MA30=MA(C,30) MA120=MA(C,120) MA240=MA(C,240) A1=IF(C>=MA5,1,-1) A2=IF(C>=MA10,1,-1) A3=IF(C>=MA20,1,-1) A4=IF(MA5>=REF(MA5,1),1,-1) A5=IF(MA10>=REF(MA10,1),1,-1) A6=IF(MA20>=REF(MA20,1),1,-1) QUSHIX=(A1+A2+A3+A4+A5+A6)/6*100#,COLORCYAN,LINETHICK3 X1=(C+L+H)/3 X2=EMA(X1,6) X3=EMA(X2,5) #DRAWTEXT(CROSS(X2,X3),L*0.98,'B'); data['B']=IF(CROSS(X2,X3),'B',None) #DRAWTEXT(CROSS(X3,X2),H*1.02,'S'); data['S']=IF(CROSS(X3,X2),'S',None) ''' STICKLINE(X2>=X3,LOW,HIGH,0,0),COLORRED; STICKLINE(X2>=X3,CLOSE,OPEN,3,1),COLORRED; ''' data['多头持续']=IF(X2>=X3,'多头持续',None) ''' STICKLINE(X2=100,MA5>REF(MA5,1)) ,(CLOSE-OPEN)/OPEN*100>5),CLOSE>MA5) return data if __name__=='__main__': df=ak.stock_zh_a_daily(symbol='sz002600',start_date='20230101',end_date='20500101') models=band_bs_trading(df=df) df=models.band_bs_trading() print(df) ``` ### 例子2蛟龙出海 ``` from trader_tool.tdx_indicator import * import akshare as ak def get_user_def_func(df): ''' 自定义通达信函数 DIFF:=EMA(CLOSE,12)-EMA(CLOSE,26); DEA:=EMA(DIFF,9); MACD:=2*(DIFF-DEA);{微信公众号:尊重市场} 尊重市场:=BARSLAST(DEA<0); 股民指标:=IF(REF(DIFF,1)>0 AND REF(DEA,1)>0,CROSS(DIFF,DEA),0); 指标营地:=SUM(股民指标,尊重市场)=2 AND 股民指标=1; 操作线:EMA(CLOSE,21),DOTLINE,LINETHICK1; 主力线:EMA(CLOSE,55),LINETHICK2;{微信公众号:尊重市场} 尊重市场1:=CROSS(CLOSE,主力线) AND VOL>REF(SUM(VOL,3)/3*1.5,1); STICKINE(尊重市场1=1,CLOSE,OPEN,3.1,0),COLORFF40FF; STICKLINE(尊重市场1=1,HIGH,LOW,0.0000000001,0),COLORFF40FF; DRAWTEXT(尊重市场1=1,LOW,{微信公众号:尊重市场}' ★蛟龙出海'),COLORFF40FF; DRAWICON(尊重市场1=1,L,9); ''' OPEN=df['open'] CLOSE=df['close'] C=df['close'] LOW=df['low'] L=df['low'] HIGH=df['high'] H=df['high'] VOL=df['volume'] DIFF=EMA(CLOSE,12)-EMA(CLOSE,26) DEA=EMA(DIFF,9) MACD=2*(DIFF-DEA) 尊重市场=BARSLAST(DEA<0) 股民指标=IF(AND(REF(DIFF,1)>0, REF(DEA,1)>0),CROSS(DIFF,DEA),0) #指标营地=AND(SUM(股民指标,尊重市场)==2, 股民指标==1) 操作线=EMA(CLOSE,21) 主力线=EMA(CLOSE,55) 尊重市场1=AND(CROSS(CLOSE,主力线)[1:], VOL>REF(SUM(VOL,3)/3*1.5,1)) data=pd.DataFrame() data['date']=df['date'] data['操作线']=操作线 data['主力线']=主力线 data['蛟龙出海']=尊重市场1 return data df=ak.stock_zh_a_daily(symbol='sh600171',start_date='20210101',end_date='20500101') result=get_user_def_func(df=df) print(result) ``` ### 例子3 波段bs交易系统 ``` from xg_tdx_func.xg_tdx_func import * import pandas as pd import akshare as ak class band_bs_trading: def __init__(self,df): ''' 波段BS买卖 ''' self.df=df def band_bs_trading(self): ''' 输出MA5:收盘价的5日简单移动平均 输出MA10:收盘价的10日简单移动平均,画黄色 输出MA20:收盘价的20日简单移动平均 输出MA30:收盘价的30日简单移动平均,画白色 输出MA120:收盘价的120日简单移动平均,画绿色,POINTDOT 输出MA240:收盘价的240日简单移动平均,画红色,POINTDOT A1赋值:如果收盘价>=MA5,返回1,否则返回-1 A2赋值:如果收盘价>=MA10,返回1,否则返回-1 A3赋值:如果收盘价>=MA20,返回1,否则返回-1 A4赋值:如果MA5>=1日前的MA5,返回1,否则返回-1 A5赋值:如果MA10>=1日前的MA10,返回1,否则返回-1 A6赋值:如果MA20>=1日前的MA20,返回1,否则返回-1 QUSHIX赋值:(A1+A2+A3+A4+A5+A6)/6*100,画青色,线宽为3 X1赋值:(收盘价+最低价+最高价)/3 X2赋值:X1的6日指数移动平均 X3赋值:X2的5日指数移动平均 当满足条件X2上穿X3时,在最低价*0.98位置书写文字 当满足条件X3上穿X2时,在最高价*1.02位置书写文字 当满足条件X2>=X3时,在最低价和最高价位置之间画柱状线,宽度为0,0不为0则画空心柱.,画红色 当满足条件X2>=X3时,在收盘价和开盘价位置之间画柱状线,宽度为3,1不为0则画空心柱.,画红色 当满足条件X2=100ANDMA5>1日前的MA5AND(收盘价-开盘价)/开盘价*100>5ANDCLOSE>MA5时,在最低价*0.99位置书写文字,画洋红色 ''' data=pd.DataFrame() data['date']=self.df['date'] C=self.df['close'] CLOSE=self.df['close'] L=self.df['low'] LOW=self.df['low'] H=self.df['high'] HIGH=self.df['high'] OPEN=self.df['open'] MA5=MA(C,5) MA10=MA(C,10) MA20=MA(C,20) MA30=MA(C,30) MA120=MA(C,120) MA240=MA(C,240) A1=IF(C>=MA5,1,-1) A2=IF(C>=MA10,1,-1) A3=IF(C>=MA20,1,-1) A4=IF(MA5>=REF(MA5,1),1,-1) A5=IF(MA10>=REF(MA10,1),1,-1) A6=IF(MA20>=REF(MA20,1),1,-1) QUSHIX=(A1+A2+A3+A4+A5+A6)/6*100#,COLORCYAN,LINETHICK3 X1=(C+L+H)/3 X2=EMA(X1,6) X3=EMA(X2,5) #DRAWTEXT(CROSS(X2,X3),L*0.98,'B'); data['B']=IF(CROSS(X2,X3),'B',None) #DRAWTEXT(CROSS(X3,X2),H*1.02,'S'); data['S']=IF(CROSS(X3,X2),'S',None) ''' STICKLINE(X2>=X3,LOW,HIGH,0,0),COLORRED; STICKLINE(X2>=X3,CLOSE,OPEN,3,1),COLORRED; ''' data['多头持续']=IF(X2>=X3,'多头持续',None) ''' STICKLINE(X2=100,MA5>REF(MA5,1)) ,(CLOSE-OPEN)/OPEN*100>5),CLOSE>MA5) return data if __name__=='__main__': df=ak.stock_zh_a_daily(symbol='sz002600',start_date='20230101',end_date='20500101') models=band_bs_trading(df=df) df=models.band_bs_trading() print(df) ``` ### **二函数说明** ### 一基础函数 ### 1 RD 四舍五入取3位小数 源代码 ``` def RD(N,D=3): #四舍五入取3位小数 return np.round(N,D) ``` 例子 ``` from xg_tdx_func.xg_tdx_func import * import akshare as ak df=ak.stock_zh_a_daily(symbol='sh600031',start_date='20240101') rd=RD(N=df['close'],D=2) print(rd) ``` 调用的数据 ``` 0 13.76 1 13.63 2 13.49 3 13.41 4 13.25 ... 162 16.31 163 16.38 164 16.35 165 16.43 166 16.13 Name: close, Length: 167, dtype: float64 ``` ### 2RET 返回序列倒数第N个值,默认返回最后一个 ``` def RET(S,N=1): ''' 返回序列倒数第N个值,默认返回最后一个 ''' return np.array(S)[-N] ``` ### 3ABS 返回N的绝对值 ``` def ABS(S): ''' 返回N的绝对值 ''' return np.abs(S) ``` ### 4MIN 序列min ``` def MIN(S1,S2): ''' 序列min ''' return np.minimum(S1,S2) ``` ### 5IF 序列布尔判断 return=A if S==True else B ``` def IF(S,A,B): ''' 序列布尔判断 return=A if S==True else B ''' return np.where(S,A,B) ``` ### 6REF 对序列整体下移动N,返回序列(shift后会产生NAN) ``` def REF(S, N=1): ''' 对序列整体下移动N,返回序列(shift后会产生NAN) ''' return pd.Series(S).shift(N).values ``` ### 7DIFF 前一个值减后一个值,前面会产生nan np.diff(S)直接删除nan,会少一行 ``` def DIFF(S, N=1): ''' 前一个值减后一个值,前面会产生nan np.diff(S)直接删除nan,会少一行 ''' return pd.Series(S).diff(N).values ``` ### 8STD 求序列的N日标准差,返回序列 ``` def STD(S,N): ''' 求序列的N日标准差,返回序列 ''' return pd.Series(S).rolling(N).std(ddof=0).values ``` ### 9SUM 对序列求N天累计和,返回序列 N=0对序列所有依次求和 ``` def SUM(S, N): ''' 对序列求N天累计和,返回序列 N=0对序列所有依次求和 ''' return pd.Series(S).rolling(N).sum().values if N>0 else pd.Series(S).cumsum().values ``` ### 10CONST 返回序列S最后的值组成常量序列 ``` def CONST(S): ''' 返回序列S最后的值组成常量序列 ''' return np.full(len(S),S[-1]) ``` ### 11AND and函数 ``` def AND(S1,S2): #and return np.logical_and(S1,S2) ``` ### 12 OR or选择函数 ``` def OR(S1,S2): #or return np.logical_or(S1,S2) ``` ### 13 NOT not函数 ``` def NOT(S1,S2): ''' not ''' return np.logical_not(S1,S2) ``` ### 14 RANGE 期间函数 B<=A<=C ``` def RANGE(A,B,C): ''' 期间函数 B<=A<=C ''' df=pd.DataFrame() df['select']=A.tolist() df['select']=df['select'].apply(lambda x: True if (x>=B and x<=C) else False) return df['select'] ``` ### 15 HHV HHV(C, 5) 最近5天收盘最高价 ``` def HHV(S,N): ''' HHV(C, 5) 最近5天收盘最高价 ''' return pd.Series(S).rolling(N).max().values ``` ### 16LLV LLV(C, 5) 最近5天收盘最低价 ``` def LLV(S,N): ''' LLV(C, 5) 最近5天收盘最低价 ''' return pd.Series(S).rolling(N).min().values ``` ### 17HHVBARS 求N周期内S最高值到当前周期数, 返回序列 ``` def HHVBARS(S,N): ''' 求N周期内S最高值到当前周期数, 返回序列 ''' return pd.Series(S).rolling(N).apply(lambda x: np.argmax(x[::-1]),raw=True).values ``` ### 18LLVBARS 求N周期内S最低值到当前周期数, 返回序列 ``` def LLVBARS(S,N): ''' 求N周期内S最低值到当前周期数, 返回序列 ''' return pd.Series(S).rolling(N).apply(lambda x: np.argmin(x[::-1]),raw=True).values ``` ### 19MA 求序列的N日简单移动平均值,返回序 ``` def MA(S,N): ''' 求序列的N日简单移动平均值,返回序列 ''' return pd.Series(S).rolling(N).mean().values ``` ### 20EMA 指数移动平均,为了精度 S>4*N EMA至少需要120周期 alpha=2/(span+1) ``` def EMA(S,N): ''' 指数移动平均,为了精度 S>4*N EMA至少需要120周期 alpha=2/(span+1) ''' retur ``` ### 21 SMA SMA,至少需要120周期才精确 (雪球180周期) alpha=1/(1+com) ``` def SMA(S, N, M=1): ''' SMA,至少需要120周期才精确 (雪球180周期) alpha=1/(1+com) ''' return pd.Series(S).ewm(alpha=M/N,adjust=False).mean().values #com=N-M/M ``` ### 22DMA 求S的动态移动平均,A作平滑因子,必须 0B & A>0 & B>=0 ``` def LAST(S, A, B): ''' 从前A日到前B日一直满足S_BOOL条件, 要求A>B & A>0 & B>=0 ''' return np.array(pd.Series(S).rolling(A+1).apply(lambda x:np.all(x[::-1][B:]),raw=True),dtype=bool) ``` ### 28COUNT COUNT(CLOSE>O, N): 最近N天满足S_BOO的天数 True的天数 ``` def COUNT(S, N): ''' # COUNT(CLOSE>O, N): 最近N天满足S_BOO的天数 True的天数 ''' return SUM(S,N) ``` ### 29EVERY EVERY(CLOSE>O, 5) 最近N天是否都是True ``` def EVERY(S, N): ''' EVERY(CLOSE>O, 5) 最近N天是否都是True ''' return IF(SUM(S,N)==N,True,False) ``` ### 30EXIST EXIST(CLOSE>3010, N=5) n日内是否存在一天大于3000点 ``` def EXIST(S, N): ''' EXIST(CLOSE>3010, N=5) n日内是否存在一天大于3000点 ''' return IF(SUM(S,N)>0,True,False) ``` ### 31FILTER FILTER函数,S满足条件后,将其后N周期内的数据置为0, FILTER(C==H,5) ``` def FILTER(S, N): ''' FILTER函数,S满足条件后,将其后N周期内的数据置为0, FILTER(C==H,5) ''' for i in range(len(S)): S[i+1:i+1+N]=0 if S[i] else S[i+1:i+1+N] return S ``` ### 32BARSLAST 上一次条件成立到当前的周期, BARSLAST(C/REF(C,1)>=1.1) 上一次涨停到今天的天数 ``` def BARSLAST(S): ''' 上一次条件成立到当前的周期, BARSLAST(C/REF(C,1)>=1.1) 上一次涨停到今天的天数 ''' M=np.concatenate(([0],np.where(S,1,0))) for i in range(1, len(M)): M[i]=0 if M[i] else M[i-1]+1 return M[1:] ``` ### 33BARSLASTCOUNT 统计连续满足S条件的周期数 BARSLASTCOUNT(CLOSE>OPEN)表示统计连续收阳的周期数 ``` def BARSLASTCOUNT(S): ''' 统计连续满足S条件的周期数 ''' rt = np.zeros(len(S)+1) for i in range(len(S)): rt[i+1]=rt[i]+1 if S[i] else rt[i+1] return rt[1:] ``` ### 34 BARSSINCEN N周期内第一次S条件成立到现在的周期数,N为常量 ``` def BARSSINCEN(S, N): ''' ''' return pd.Series(S).rolling(N).apply(lambda x:N-1-np.argmax(x) if np.argmax(x) or x[0] else 0,raw=True).fillna(0).values.astype(int) ``` ### 35 CROSS 判断向上金叉穿越 CROSS(MA(C,5),MA(C,10)) 判断向下死叉穿越 CROSS(MA(C,10),MA(C,5)) ``` def CROSS(S1, S2): ''' 判断向上金叉穿越 CROSS(MA(C,5),MA(C,10)) 判断向下死叉穿越 CROSS(MA(C,10),MA(C,5)) ''' return np.concatenate(([False], np.logical_not((S1>S2)[:-1]) & (S1>S2)[1:])) ``` ### 36CROSS_UP 判断向上金叉穿越 CROSS(MA(C,5),MA(C,10)) 判断向下死叉穿越 CROSS(MA(C,10),MA(C,5)) ``` def CROSS_UP(S1, S2): ''' #判断向上金叉穿越 CROSS(MA(C,5),MA(C,10)) 判断向下死叉穿越 CROSS(MA(C,10),MA(C,5)) ''' return np.concatenate(([False], np.logical_not((S1>S2)[:-1]) & (S1>S2)[1:])) ``` ### 37 CROSS_DOWN 判断向上死叉穿越 CROSS(MA(C,5),MA(C,10)) 判断向下死叉穿越 CROSS(MA(C,5),MA(C,10)) ``` def CROSS_DOWN(S1, S2): ''' 判断向上死叉穿越 CROSS(MA(C,5),MA(C,10)) 判断向下死叉穿越 CROSS(MA(C,5),MA(C,10)) ''' return np.concatenate(([False], np.logical_not((S1S2)),dtype=bool) # ``` ### 39 VALUEWHEN 当S条件成立时,取X的当前值,否则取VALUEWHEN的上个成立时的X值 ``` def VALUEWHEN(S, X): ''' 当S条件成立时,取X的当前值,否则取VALUEWHEN的上个成立时的X值 ''' return pd.Series(np.where(S,X,np.nan)).ffill().values ``` ### 40BACKSET 属于未来函数,将当前位置到若干周期前的数据设为1. 用法: BACKSET(X,N),若X非0,则将当前位置到N周期前的数值设为1. 例如: BACKSET(CLOSE>OPEN,2)若收阳则将该周期及前一周期数值设为1,否则为0 ``` def BACKSET(X, N): ''' 属于未来函数,将当前位置到若干周期前的数据设为1. 用法: BACKSET(X,N),若X非0,则将当前位置到N周期前的数值设为1. 例如: BACKSET(CLOSE>OPEN,2)若收阳则将该周期及前一周期数值设为1,否则为0 ''' # 创建一个与X相同形状的全零数组 result = np.zeros_like(X) # 遍历X的元素,根据条件设置result的值 for i in range(len(X)): if X[i] != 0: start_index = max(0, i - N + 1) result[start_index:i+1] = 1 return result ``` ### 41 ALIGNRIGHT 有效数据右对齐. 用法: ALIGNRIGHT(X)有效数据向右移动,左边空出来的周期填充无效值 例如:TC:=IF(CURRBARSCOUNT=2 || CURRBARSCOUNT=5,DRAWNULL,C);XC:ALIGNRIGHT(TC);删除了两天的收盘价,并将剩余数据右移 ``` def ALIGNRIGHT(X): ''' 有效数据右对齐. 用法: ALIGNRIGHT(X)有效数据向右移动,左边空出来的周期填充无效值 例如:TC:=IF(CURRBARSCOUNT=2 || CURRBARSCOUNT=5,DRAWNULL,C);XC:ALIGNRIGHT(TC);删除了两天的收盘价,并将剩余数据右移 ''' # 获取有效数据的索引 valid_indices = np.where(X != np.nan)[0] # 计算需要填充的无效数据的数量 invalid_count = len(X) - len(valid_indices) # 创建一个新的数组,将有效数据向右移动,左边填充无效值 result = np.empty_like(X) result[:] = np.nan result[invalid_count:len(valid_indices)+invalid_count] = X[valid_indices] return result ``` ### 42BARSCOUNT 有效数据周期数. 用法: BARSCOUNT(X)第一个有效数据到当前的间隔周期数 注意:判断范围为指标或条件选股计算时公式使用的数据, 如果给画线指标的数据少(比如没有按下箭头取更多K线)或给条件选股给的数据少,这个有效值也可能少 ``` def BARSCOUNT(X): ''' 有效数据周期数. 用法: BARSCOUNT(X)第一个有效数据到当前的间隔周期数 注意:判断范围为指标或条件选股计算时公式使用的数据, 如果给画线指标的数据少(比如没有按下箭头取更多K线)或给条件选股给的数据少,这个有效值也可能少 ''' # 获取有效数据的索引 valid_indices = np.where(~np.isnan(X))[0] # 如果数组中没有有效数据,返回0 if len(valid_indices) == 0: return 0 # 计算第一个有效数据到当前位置的间隔周期数 first_valid_index = valid_indices[0] current_index = len(X) - 1 bars_count = current_index - first_valid_index + 1 return bars_count ``` ### 43BARSLASTS 倒数第N次成立时距今的周期数. 用法: BARSLASTS(X,N):X倒数第N满足到现在的周期数,N支持变量 ``` def BARSLASTS(X, N): ''' 倒数第N次成立时距今的周期数. 用法: BARSLASTS(X,N):X倒数第N满足到现在的周期数,N支持变量 ''' # 获取有效数据的索引 valid_indices = np.where(~np.isnan(X))[0] # 如果数组中没有有效数据,返回-1 if len(valid_indices) == 0: return -1 # 计算倒数第N次满足条件到现在的周期数 last_n_indices = valid_indices[-N:] if len(last_n_indices) < N: return -1 current_index = len(X) - 1 bars_since_last_n = current_index - last_n_indices[-1] + 1 return bars_since_last_n ``` 44 zig ``` def cacal_zig_data(self,x=0.05): ''' 计算之字转向 x=5%之子转向 :return: ''' ZIG_STATE_START = 0 ZIG_STATE_RISE = 1 ZIG_STATE_FALL = 2 df=self.df # print(list(df["close"])) df = df[::-1] df = df.reset_index(drop=True) # df = df.iloc[-100:] x = x k = df["close"] d = df["date"] peer_i = 0 candidate_i = None scan_i = 0 peers = [0] z = np.zeros(len(k)) state = ZIG_STATE_START while True: scan_i += 1 if scan_i == len(k) - 1: # 扫描到尾部 if candidate_i is None: peer_i = scan_i peers.append(peer_i) else: if state == ZIG_STATE_RISE: if k[scan_i] >= k[candidate_i]: peer_i = scan_i peers.append(peer_i) else: peer_i = candidate_i peers.append(peer_i) peer_i = scan_i peers.append(peer_i) elif state == ZIG_STATE_FALL: if k[scan_i] <= k[candidate_i]: peer_i = scan_i peers.append(peer_i) else: peer_i = candidate_i peers.append(peer_i) peer_i = scan_i peers.append(peer_i) break if state == ZIG_STATE_START: if k[scan_i] >= k[peer_i] * (1 + x): candidate_i = scan_i state = ZIG_STATE_RISE elif k[scan_i] <= k[peer_i] * (1 - x): candidate_i = scan_i state = ZIG_STATE_FALL elif state == ZIG_STATE_RISE: if k[scan_i] >= k[candidate_i]: candidate_i = scan_i elif k[scan_i] <= k[candidate_i] * (1 - x): peer_i = candidate_i peers.append(peer_i) state = ZIG_STATE_FALL candidate_i = scan_i elif state == ZIG_STATE_FALL: if k[scan_i] <= k[candidate_i]: candidate_i = scan_i elif k[scan_i] >= k[candidate_i] * (1 + x): peer_i = candidate_i peers.append(peer_i) state = ZIG_STATE_RISE candidate_i = scan_i for i in range(len(peers) - 1): peer_start_i = peers[i] peer_end_i = peers[i + 1] start_value = k[peer_start_i] end_value = k[peer_end_i] a = (end_value - start_value) / (peer_end_i - peer_start_i) # 斜率 for j in range(peer_end_i - peer_start_i + 1): z[j + peer_start_i] = start_value + a * j df['结果']=z return df ``` ### 45WINNER 计算某价位的盈利盘比例 ``` def WINNER(HIGH:Iterable,LOW:Iterable,VOL:Iterable,Turnrate:Iterable,price,avg:Union[Iterable,str]='hlavg')->Optional[np.ndarray]: '''计算某价位的盈利盘比例 :HIGH-最高价[序列值] :LOW-最低价[序列值] :VOL-成交量[序列值],单位是手,万股等不重要,只要统一就行 :Turnrate[换手率]:取值范围0-1,注意50%的换手应写作0.5 *换手率由于流通股变动问题,故不能简单使用“成交量/流通股”的方式计算,这也是本函数保留输入换手率的原因 :price-某价格的盈利比例中的价格,可以是具体数值(如:99.98),也可以是序列(如收盘价、开盘价等) :avg-三角分部顶点:默认取每日最高价和最低价的平均值,某些算法中使用“成交额/成交量”的计算方法 *使用“成交额/成交量”的计算方法的话,注意这个平均位置也要复权,否则会出现平均位置出现在当日最高价和最低价之外的情况 返回一组获利比例的序列值,范围0-1,如0.1即当前股价的盈利比例为10% *此函数专用于T+1交易,不适用于可转债或者非日线周期等换手率超过100的情况 ''' return pyML.WINNER(HIGH,LOW,VOL,Turnrate,price,avg) ``` ### 46COST 计算某盈利比例对应的股价 ``` def COST(HIGH:Iterable,LOW:Iterable,VOL:Iterable,Turnrate:Iterable,winpercent:Iterable,radio:float=0.01,avg:Union[Iterable,str]='hlavg')->Optional[np.ndarray]: '''计算某盈利比例对应的股价 :HIGH-最高价[序列值] :LOW-最低价[序列值] :VOL-成交量[序列值],单位是手,万股等不重要,只要统一就行 :Turnrate[换手率]:取值范围0-1,注意50%的换手应写作0.5 *换手率由于流通股变动问题,故不能简单使用“成交量/流通股”的方式计算,这也是本函数保留输入换手率的原因 :winpercent-指定获利比例,应为0-100之间的数值(如winpercent=90,即返回盈利90%的股价) :avg-三角分部顶点:默认取每日最高价和最低价的平均值,某些算法中使用“成交额/成交量”的计算方法 *使用“成交额/成交量”的计算方法的话,注意这个平均位置也要复权,否则会出现平均位置出现在当日最高价和最低价之外的情况 :radio-精确度:如股票等使用0.01,ETF,Reits等使用0.001 返回一组指定获利比例的股价。 *此函数专用于T+1交易,不适用于可转债或者非日线周期等换手率超过100的情况''' return pyML.COST(HIGH,LOW,VOL,Turnrate,winpercent,radio,avg) ``` ### 47LLVBARS 求上一低点到当前的周期数. ``` def LLVBARS(S:Iterable,N:int)->Optional[np.ndarray]: '''求上一低点到当前的周期数. 用法: LLVBARS(S,N):求N周期内X最低值到当前周期数,N=0表示从第一个有效值开始统计''' return pyML.LLVBARS(S,N) ``` ### 49 HHVBARS 求上一高点到当前的周期数. ``` def HHVBARS(S:Iterable,N:int)->Optional[np.ndarray]: '''求上一高点到当前的周期数. 用法: HHVBARS(S,N):求N周期内X最高值到当前周期数,N=0表示从第一个有效值开始统计''' return pyML.HHVBARS(S,N) ``` ### 50 SAR ``` def SAR(cls, ohlc: DataFrame, af: int = 0.02, amax: int = 0.2) -> Series: """SAR stands for “stop and reverse,” which is the actual indicator used in the system. SAR trails price as the trend extends over time. The indicator is below prices when prices are rising and above prices when prices are falling. In this regard, the indicator stops and reverses when the price trend reverses and breaks above or below the indicator.""" high, low = ohlc.high, ohlc.low # Starting values sig0, xpt0, af0 = True, high[0], af _sar = [low[0] - (high - low).std()] for i in range(1, len(ohlc)): sig1, xpt1, af1 = sig0, xpt0, af0 lmin = min(low[i - 1], low[i]) lmax = max(high[i - 1], high[i]) if sig1: sig0 = low[i] > _sar[-1] xpt0 = max(lmax, xpt1) else: sig0 = high[i] >= _sar[-1] xpt0 = min(lmin, xpt1) if sig0 == sig1: sari = _sar[-1] + (xpt1 - _sar[-1]) * af1 af0 = min(amax, af1 + af) if sig0: af0 = af0 if xpt0 > xpt1 else af1 sari = min(sari, lmin) else: af0 = af0 if xpt0 < xpt1 else af1 sari = max(sari, lmax) else: af0 = af sari = xpt0 _sar.append(sari) return pd.Series(_sar, index=ohlc.index) ``` ### **二通达信函数** ### 一超卖超买类 ### 1CCI商品路劲指标 ``` def CCI(CLOSE,HIGH,LOW,N=14): ''' 超卖超买类 CCI商品路劲指标 TYP赋值:(最高价+最低价+收盘价)/3 输出CCI:(TYP-TYP的N日简单移动平均)*1000/(15*TYP的N日平均绝对偏差) ''' TYP=(HIGH+LOW+CLOSE)/3 result=(TYP-MA(TYP,N))*1000/(15*AVEDEV(TYP,N)) return result ``` ### 2KDJ ``` def KDJ(CLOSE,HIGH,LOW, N=9,M1=3,M2=3): ''' 超卖超买类 RSV赋值:(收盘价-N日内最低价的最低值)/(N日内最高价的最高值-N日内最低价的最低值)*100 输出K:RSV的M1日[1日权重]移动平均 输出D:K的M2日[1日权重]移动平均 输出J:3*K-2*D ''' RSV=(CLOSE-LLV(LOW,N))/(HHV(HIGH,N)-LLV(LOW,N))*100 K=SMA(RSV,M1,1) D=SMA(K,M2,1) J=3*K-2*D return K,D,J ``` ### 3MFI最近流量指标 ``` def MFI(CLOSE,HIGH,LOW,VOL,N=14): ''' 最近流量指标 超卖超买类 赋值: (最高价 + 最低价 + 收盘价)/3 V1赋值:如果TYP>1日前的TYP,返回TYP*成交量(手),否则返回0的N日累和/如果TYP<1日前的TYP,返回TYP*成交量(手),否则返回0的N日累和 输出资金流量指标:100-(100/(1+V1)) ''' TYP = (HIGH + LOW + CLOSE)/3 V1=SUM(IF(TYP>REF(TYP,1),TYP*VOL,0),N)/SUM(IF(TYP=0,返回DIF,否则返回0 VD赋值:如果DIF<0,返回-DIF,否则返回0 MAU1赋值:VU的M1日平滑移动平均 MAD1赋值:VD的M1日平滑移动平均 MAU2赋值:VU的M2日平滑移动平均 ''' DIF=CLOSE-REF(CLOSE,1) VU=IF(DIF>=0,DIF,0) VD=IF(DIF<0,-DIF,0) MAU1=MEMA(VU,M1) MAD1=MEMA(VD,M1) MAU2=MEMA(VU,M2) MAD2=MEMA(VD,M2) RSI1=MA(100*MAU1/(MAU1+MAD1),M1) RSI2=MA(100*MAU2/(MAU2+MAD2),M2) return RSI1,RSI2 ``` ### 16BIAS_QL乖离率-传统版 ``` def BIAS_QL(CLOSE,N=6,M=6): ''' 乖离率-传统版 输出乖离率 :(收盘价-收盘价的N日简单移动平均)/收盘价的N日简单移动平均*100 输出BIASMA :乖离率的M日简单移动平均 ''' BIAS=(CLOSE-MA(CLOSE,N))/MA(CLOSE,N)*100 BIASMA=MA(BIAS,M) return BIAS,BIASMA ``` #### 参与贡献 1. Fork 本仓库 2. 新建 Feat_xxx 分支 3. 提交代码 4. 新建 Pull Request #### 特技 1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md 2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) 3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) 6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)