量化交易初识
量化交易分类:
策略信号:
多因子策略
均值回归策略
动量效益策略
二八轮动策略
海归策略
机器学习策略
量化交易开发流程
数据获取
数据清洗
策略编写(核心)
策略回测
策略优化(重点)
模拟盘交易
实盘交易(真金白银)
数据获取
内容:行情数据、宏观数据、财务数据、舆情数据
方式:网站下载、客户端、三方api、爬虫
数据清洗
场景:垃圾数据清除、空值填充、格式转换、数据对齐
类库:numpy、pandas
策略编写
建仓:买;平仓:卖;策略要判断出交易信号
1 2 3 4 graph LR; A[信号捕捉] --> B[交易]; B --> C[建仓]; B --> D[平仓];
策略回测
1 2 3 4 5 6 graph LR; A[回测参数设置] --> B[策略实例化]; B --> C[历史数据加载]; C --> D[回测执行]; D --> E[计算统计指标]; E --> F[生成回测报告];
量化策略优化
重视交易费
重视风险,重视退出(止盈线、止损线)
优化无止境(不要无休止得)
模拟盘交易
过去的表现并不表示未来结果(事后诸葛亮)
至少半年以上
模拟盘交易稳定收益100%以上在考虑实盘交易
实盘交易
做好第一年会输的准备
不要急于扩大投资,增加杠杆(控制风险)
心态最重要
量化交易分类体系 交易产品分类 交易产品、盈利模式
股票策略,股票——股价波动盈利
期权策略,期权——期权合约差价(常用)、到期行权收益
CTA策略,期货——关注价格趋势获取利差
FOF策略,FOF
盈利模式分类
单边多空策略——低价买 进,带股价出现单边下跌时卖出,赚取利差
套利策略——金融产品价格与收益略暂时不一致 的机会收益
对冲策略——指特以减低另一项投资风险的投资 。同时进行两笔行情相同、方向相关、数量相当、盈亏相抵 的交易
策略信号分类 策略信号就是交易信号
多因子——找到某些和收益率最相关的指标,并根据该指标,建一个股票组合,期望该组合在未来的一段时间跑赢(做多)或跑输(做空)指数
例:因子项:资产负债率、资产回报率、每股净收益、净利润增长率、市盈率等
交易模型——具有普遍性、可盈利可量化可执行的交易系统
机器学习——从大规模数据中找到某种规律,包括但不限于文本数据、图像数据 等,找到可盈利、可量化、可执行的策略信号。
股票 股票的交易价格 与股票的价值 是相对的概念。股票价值的真实含义是企业资产的价值 。而股票的价值就等于每股收益 。
影响因素:
经济因素——经济繁荣,股价上涨;经济衰退,股价下跌
政治因素
行业因素
企业自身因素
市场因素
心理因素
股票的基础知识:自己拿真金白银才能在股市中试出来,通过各种指标读懂散户与主力的情绪、市场和其中的博弈。
量化选股 选股是股票投资的第一步,选好赚钱选坏亏钱
方法:基本面选股
基本面:通过分析一家上市公司在发展过程中所面临的外部因素 及自身的因素 ,来预测其未来的发展前景,并以此来判断该上市公司的股票是否值得购买。
外部因素:经济增长、财政策略、利率变化(贷款等)
内部因素:经营状况、行业地位、财务状况
科学的分析方法:估值
股票估值 基本面选股的核心方法 。股票估值能够帮助投资者发现价值被低估的股票,让他们低买高卖,从而获利。
常用指标:
每股收益 :越高越好 ,代表公司盈利水平
市盈率 :14~30倍正常,大于30属于高估,50倍以上存在泡沫
毛利率 :越高越好,大于50%不错
净资产收益率 :代表公司盈利能力,ROE长期保持在20%以上就是白马股
资产负债率 :适中为好,最好在10%~40% 。过高,易暴雷;过低,太保守
净利润增速 :代表公司未来成长能力,近三年20以上属优质企业,大于50%属于成长股
择时 即买入股票 和卖出股票 的时机
作用:择时的好坏,决定能够赚到多少钱
方法:技术分析——K线、成交量、均线、柏林带、MACD、KDJ等反应股价变化 的指标
量化交易平台 joinQuant、掘金量化、BigQuant、RiceQuant等
Numpy实战 股价分析 一些指标
极差:股价近期最高价的最大值和最小值的插值,
成交量加权平均价格
收益率:简单收益率;对数收益率——之所有价格取对数后两两之间的差值
波动率:波动率:是对价格变动的一种衡量,计算历史波动率需要用到对数收益率
年波动率:对数波动率的标准差除以其均值,再乘以交易日倒数的平方根,通常为250
月波动率:对数收益率的标准差除以其均值,再乘以交易月的平方根,通常为12
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 import unittestimport numpy as npclass TestNumpyStock (unittest.TestCase): """ 读取指定列 numpy.loadtxt需要传入4个关键字参数: 1.fname是文件名,数据类型为字符串str; 2.delimiter是分隔符,数据类型为字符串str; 3.usecols是读取的列数,数据类型为元组tuple,其中元素个数有多少个,则选出多少列; 4.unpack是是否解包,数据类型为布尔bool。 """ def testReadFile (self ): file_name = "./demo_tushare.csv" end_price,volumn = np.loadtxt( fname=file_name, delimiter=',' , usecols=(5 ,6 ), unpack=True , skiprows=1 ) def testMaxAndMin (self ): file_name = "./demo_tushare.csv" high_price,low_price = np.loadtxt( fname=file_name, delimiter=',' , usecols=(3 , 4 ), skiprows=1 , unpack=True ) print (f'max_price = {high_price.max ()} ' ) print (f'min_price = {low_price.min ()} ' ) def testPtp (self ): file_name = "./demo_tushare.csv" high_price, low_price = np.loadtxt( fname=file_name, delimiter=',' , usecols=(3 , 4 ), dtype=float , skiprows=1 , unpack=True ) print (f'max - min of high_price = {np.ptp(high_price)} ' ) print (f'max - min of low_price = {np.ptp(low_price)} ' ) def testAVG (self ): file_name = "./demo_tushare.csv" end_price, volume = np.loadtxt( fname=file_name, delimiter=',' , usecols=(5 , 6 ), dtype=float , skiprows=1 , unpack=True ) print (f'vg_price = {np.average(end_price)} ' ) print (f"VWAD = {np.average(end_price,weights=volume)} " ) def testMedian (self ): file_name = "./demo_tushare.csv" end_price, volumn = np.loadtxt( fname=file_name, delimiter=',' , usecols=(5 , 6 ), skiprows=1 , unpack=True ) print (f"median = {np.median(end_price)} " ) def testVar (self ): file_name = "./demo_tushare.csv" end_price, volumn = np.loadtxt( fname=file_name, delimiter=',' , usecols=(5 , 6 ), skiprows=1 , unpack=True ) print (f"var = {np.var(end_price)} " ) def testVolatility (self ): file_name = "./demo_tushare.csv" end_price, volumn = np.loadtxt( fname=file_name, delimiter=',' , usecols=(5 , 6 ), skiprows=1 , unpack=True ) log_return = np.diff(np.log(end_price)) annual_volatility = log_return.std() / log_return.mean() * np.sqrt(250 ) monthly_volatility = log_return.std() / log_return.mean() * np.sqrt(12 ) print (f'log_return = {log_return} ' ) print (f'annual_volatility = {annual_volatility} ' ) print (f'monthly_volatility = {monthly_volatility} ' ) if __name__ == '__main__' : unittest.main()
股价均线 卷积:可用于描述过去左右对当前的影响。卷积是时空相应的叠加,可用作计算“滑动平均”
numpy.convolve(a, v, mode=’full’),这是numpy函数中的卷积函数。
参数:
简单移动均线 :一般用于分析时间序列上的股价趋势 计算股价与权重的指标函数的卷积。通过将一段时间内的股票收盘价相加,然后除以时间段的天数来计算。简单移动平均线可以平滑价格波动,显示出长期趋势。
1 2 3 flowchart LR A[生成权重] --> B[卷积运算] B --> C[均线可视化]
指标移动均线 :历史数据的权重 以指标速度衰减 ,计算股价与权重衰减的指标函数的卷积。对近期价格给予更高的权重,反映了市场更近期的变化。计算指数移动平均线时,当前价格会根据选定的时间段和权重系数,与之前的移动平均线值相结合。
1 2 3 4 flowchart LR A[权重初始化] --> B[权重衰减] B --> C[卷积运算] C --> D[均线可视化]
应用 :
确定趋势 :投资者可以使用不同期限的移动平均线来确定趋势的强度和方向。
交叉信号 :移动平均线的交叉可以提供买入或卖出的信号。
支撑与阻力线 :移动平均线经常被用作支撑和阻力线的参考。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 import unittestimport numpy as npimport matplotlibimport matplotlib.pyplot as pltfrom unittest import TestCaseclass TestNumpyMA (TestCase ): def testSMA (self ): file_name = "./demo_tushare.csv" end_price = np.loadtxt( fname=file_name, delimiter="," , skiprows=1 , usecols=(5 ), unpack=True ) print (end_price) N=5 weights = np.ones(N) / N print (weights) sma = np.convolve(weights,end_price)[N-1 :-N+1 ] print (sma) plt.plot(sma,linewidth=5 ) def testEXP (self ): x = np.arange(5 ) y = np.arange(10 ) print ("x" ,x) print ("y" ,y) print (f"""Exp x : {np.exp(x)} """ ) print (f'''Exp y : {np.exp(y)} ''' ) print (f"""LineSpace : {np.linspace(-1 ,0 ,5 )} """ ) def testEMA (self ): file_name = "./demo_tushare.csv" end_price,volumn = np.loadtxt( fname=file_name, delimiter="," , skiprows=1 , usecols=(5 ,6 ), unpack=True ) print (end_price) N = 5 weighs = np.exp(np.linspace(-1 ,0 ,N)) weighs /= weighs.sum () print (weighs) ema = np.convolve(weighs,end_price)[N-1 :-N+1 ] print (ema) t = np.arange(N-1 ,len (end_price)) plt.plot(t,end_price[N-1 :],lw=1.0 ) plt.plot(t,ema,lw=2.0 ) plt.show() print ("++++++++=============++++++++" ) if __name__ == '__main__' : unittest.main()
Pandas实战 股票时间序列 时间序列 :金融领域最重要的数据类型之一,股价、汇率为常见的时间序列数据
趋势分析 :**主要分析时间序列在某一方向上持续运动。**在量化交易领域,我们通过统计手段对投资品的收益率进行时间序列建模,以此来预测未来的收益率并产生交易信号。
序列相关性 :金融时间序列的一个最重要特征是序列相关性。 以投资品的收益率序列为例,我们会经常观察到一段时间内的收益率呈现一定的相关性。
pandas时间序列函数:
datetime——时间序列最常用的数据类型,方便进行各种时间类型运算
loc——Pandas中对DataFrame进行筛选的函数,相当于SQL中的where
groupby——Pandas中对数据分组函数,相当于SQL中的GroupBy
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 import pandas as pdimport matplotlib.pyplot as pltfrom unittest import TestCaseclass TestPandasStock (TestCase ): def testPandasFile (self ): file_name = "./demo_tushare.csv" df = pd.read_csv(file_name) print (df.info()) print ("-----------" ) print (df.describe()) def testTime (self ): file_name = "./demo_tushare.csv" df = pd.read_csv(file_name) df.columns = ['ts_code' , 'trade_date' , 'open' , 'high' , 'low' , 'close' , 'vol' ] df['trade_date' ] = pd.to_datetime(df['trade_date' ]) df["year" ] = df["trade_date" ].dt.year df["month" ] = df["trade_date" ].dt.month print (df) def testCloseMin (self ): file_name = "./demo_tushare.csv" df = pd.read_csv(file_name) df.columns = ['ts_code' , 'trade_date' , 'open' , 'high' , 'low' , 'close' , 'col' ] print (f"""close min : {df['close' ].min ()} """ ) print (f"""close min index : {df['close' ].idxmin()} """ ) print (f"""close min frame : {df.loc[df['close' ].idxmin()]} """ ) def testMean (self ): file_name = "./demo_tushare.csv" df = pd.read_csv(file_name) df.columns = ['ts_code' , 'trade_date' , 'open' , 'high' , 'low' , 'close' , 'col' ] df['trade_date' ] = pd.to_datetime(df['trade_date' ]) df["month" ] = df["trade_date" ].dt.month print (f"""month close mean : {df.groupby("month" )['close' ].mean()} """ ) print (f"""month open mean : {df.groupby("month" )['open' ].mean()} """ ) def testRipples_ratio (self ): file_name = "./demo_tushare.csv" df = pd.read_csv(file_name) df.columns = ['ts_code' , 'trade_date' , 'open' , 'high' , 'low' , 'close' , 'col' ] df['trade_date' ] = pd.to_datetime(df['trade_date' ]) df["rise" ] = df["close" ].diff() df["rise_ratio" ] = df["rise" ] / df.shift(1 )["close" ] print (df)
K线图 三种K线图:K线图、K线图带交易量、K线图带交易量和均线5和10日
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 import pandas as pdimport matplotlib.pyplot as pltfrom mplfinance.original_flavor import candlestick2_ohlcimport mplfinance as mpffrom unittest import TestCaseclass TestPandasKLine (TestCase ): def testKLineChart (self ): file_name = "./demo_tushare.csv" df = pd.read_csv(file_name) df.columns = ['ts_code' , 'trade_date' , 'open' , 'high' , 'low' , 'close' , 'vol' ] fig = plt.figure() axes = fig.add_subplot(111 ) candlestick2_ohlc(ax=axes, opens=df["open" ].values,closes=df["close" ].values,highs=df["high" ].values, lows=df["low" ].values,width=0.75 ,colorup='red' , colordown='green' ) plt.xticks(range (len (df.index.values)), df.index.values, rotation=30 ) axes.grid(True ) plt.title("K-Line" ) plt.show() def testKLineByVolume (self ): file_name = "./demo_tushare.csv" df = pd.read_csv(file_name) df.columns = ['ts_code' , 'trade_date' , 'open' , 'high' , 'low' , 'close' , 'volume' ] df = df[["trade_date" , "open" , "high" , "low" , "close" ,"volume" ]] df['trade_date' ] = pd.to_datetime(df['trade_date' ]) df = df.set_index('trade_date' ) my_color = mpf.make_marketcolors( up = 'red' , down = 'green' , wick = 'i' , volume = {'up' :'red' , 'down' :'green' }, ohlc = 'i' ) my_style = mpf.make_mpf_style( marketcolors=my_color, gridaxis='both' , gridstyle='-.' , rc = {'font.family' :'STSong' } ) mpf.plot( df, type = 'candle' , title = 'K-Line' , ylabel = 'price' , style = my_style, show_nontrading = False , volume = True , ylabel_lower = 'volume' , datetime_format = '%Y-%m-%d' , xrotation = 45 , linecolor = '#00ff00' , tight_layout = False , ) def testKLineByMA (self ): file_name = "./demo_tushare.csv" df = pd.read_csv(file_name) df.columns = ['ts_code' , 'trade_date' , 'open' , 'high' , 'low' , 'close' , 'volume' ] df = df[["trade_date" , "open" , "high" , "low" , "close" , "volume" ]] df['trade_date' ] = pd.to_datetime(df['trade_date' ]) df = df.set_index('trade_date' ) my_color = mpf.make_marketcolors( up = 'red' , down = 'green' , wick = 'i' , volume = {'up' :'red' , 'down' :'green' }, ohlc = 'i' ) my_style = mpf.make_mpf_style( marketcolors=my_color, gridaxis='both' , gridstyle='-.' , rc = {'font.family' :'STSong' } ) mpf.plot( df, type = 'candle' , mav = [5 ,10 ], title = 'K-Line' , ylabel = 'price' , style = my_style, show_nontrading = False , volume = True , ylabel_lower = 'volume' , datetime_format = '%Y-%m-%d' , xrotation = 45 , linecolor = '#00ff00' , tight_layout = False , )
Matplotlib实战 MACD MACD意为异同移动平均线。它刻画的是股价变化速率
构成:白色线代表快线DIF,黄色线代表慢线DEA,零轴,红色柱体,绿色柱体
指标
含义
公式
短期EMA
短期收益率指标移动均线(12天)
前一日EMA(12)11/13 + 今日收益率 2/13
长期EMA
长期收益率指标移动均线(26天)
前一日EMA(26)25/27 + 今日收益率 2/27
DIF
短期EMA与长期EMA差值
EMA(12) - EMA(26)
DEA
DIF线的M日指数移动均线
前一日DEA*8/10 + 今日
MACD
DIF线与DEA线的差 * 2
(DIF - DEA) * 2
**ewm:**Pandas中指数加权移动窗口函数,采用ewm函数+mean()快捷计算MACD
**bar:**Matplotlib柱状图函数,高校绘制MACD中的柱状图
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 import pandas as pdimport matplotlib.pyplot as pltfrom matplotlib import colors as mycolorsfrom matplotlib.collections import LineCollection,PolyCollectionfrom unittest import TestCaseclass TestMatplotlibMACD (TestCase ): def cal_macd (self,df,fastperiod=12 , slowperiod=26 , signalperiod=9 ): ewma12 = df['close' ].ewm(span=fastperiod, adjust=False ).mean() ewma26 = df['close' ].ewm(span=slowperiod, adjust=False ).mean() df['dif' ] = ewma12 - ewma26 df['dea' ] = df['dif' ].ewm(span=signalperiod, adjust=False ).mean() df['bar' ] = (df['dif' ] - df['dea' ]) * 2 return df def test_macd (self ): file_name = "./demo_tushare.csv" df = pd.read_csv(file_name) df.columns = ['ts_code' , 'trade_date' , 'open' , 'high' , 'low' , 'close' , 'volume' ] df = df[['trade_date' , 'open' , 'high' , 'low' , 'close' , 'volume' ]] df["trade_date" ] = pd.to_datetime(df["trade_date" ]) df_macd = self .cal_macd(df) print (df_macd) plt.figure() df_macd['dea' ].plot(color='red' ,label='dea' ) df_macd['dif' ].plot(color='blue' ,label='dif' ) plt.legend(loc='best' ) pos_bar = [] pos_index = [] neg_bar = [] neg_index = [] for index,row in df_macd.iterrows(): if (row['bar' ] > 0 ): pos_bar.append(row['bar' ]) pos_index.append(index) else : neg_bar.append(row['bar' ]) neg_index.append(index) plt.bar(pos_index,pos_bar,width=0.5 ,color='red' ) plt.bar(neg_index,neg_bar,width=0.5 ,color='green' ) major_index = df_macd.index[df_macd.index] major_xtics = df_macd['trade_date' ][df_macd.index] plt.xticks(major_index,major_xtics) plt.setp(plt.gca().get_xticklabels(), rotation=30 ) plt.grid(linestyle='-.' ) plt.title('MACD' ) plt.rcParams['axes.unicode_minus' ] = False plt.rcParams['font.sans-serif' ] = ['SimHei' ] plt.show()
KDJ KDJ叫随机指标 。通过价格波动的真实波幅来反映价格走势的强弱和超买超卖现象 。在价格尚上涨或下降之前,发出买信号的一种技术分析指标,适用于短期行情 走势分析。
指标
含义
公式
RSV
未成熟随机指标值
(Cn - Ln) / (Hn - Ln) × 100 (N日)
K
当天K值
2/3×前一日K值 + 1/3×当日RSV
D
当天D值
2/3×前一日D值 + 1/3×当日K值
J
当天J值
3当日K值 - 2 当日D值
备注
若无前一日K值与D值,则可分别用50来代替
**rolloing:**Pandas中移动窗口函数,每个窗口都是指定的固定大小,快捷计算Ln与Hn
expanding : 在Pandas中扩展窗口函数,只设置最小的观察值数量,不固定窗口大小,实现累积计算,即不断扩展,使用expanding().max()
可以创建新的高度。
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 import pandas as pdimport matplotlib.pyplot as pltfrom matplotlib import colors as mycolorsfrom matplotlib.collections import LineCollection,PolyCollectionfrom unittest import TestCaseclass TestKDJ (TestCase ): def cal_kdj (self,df ): low_list = df['low' ].rolling(9 , min_periods=9 ).min () low_list.fillna(value=df['low' ].expanding().min (),inplace=True ) high_list = df['high' ].rolling(9 , min_periods=9 ).max () high_list.fillna(value=df['high' ].expanding().max (),inplace=True ) rsv = (df['close' ] - low_list)/(high_list - low_list)*100 df['k' ] = pd.DataFrame(rsv).ewm(com=2 ).mean() df['d' ] = df['k' ].ewm(com=2 ).mean() df['j' ] = 3 *df['k' ] - 2 *df['d' ] return df def test_kdj (self ): file_name = "./demo_tushare.csv" df = pd.read_csv(file_name) df.columns = ['ts_code' , 'trade_date' , 'open' , 'high' , 'low' , 'close' , 'volume' ] df = df[['trade_date' , 'open' , 'high' , 'low' , 'close' , 'volume' ]] df["trade_date" ] = pd.to_datetime(df["trade_date" ]) df_kdj = self .cal_kdj(df) print (df_kdj) plt.figure() df_kdj['k' ].plot(color='red' ,label='k' ) df_kdj['d' ].plot(color='yellow' ,label='d' ) df_kdj['j' ].plot(color='blue' ,label='j' ) plt.legend(loc='best' ) major_index = df_kdj.index[df_kdj.index] major_xtics = df_kdj['trade_date' ][df_kdj.index] plt.xticks(major_index,major_xtics) plt.setp(plt.gca().get_xticklabels(), rotation=30 ) plt.grid(linestyle='-.' ) plt.title('KDJ' ) plt.rcParams['axes.unicode_minus' ] = False plt.rcParams['font.sans-serif' ] = ['SimHei' ] plt.show()
量化交易策略框架 主力做局散户没法准确知道,但可以一招破解:(图中白色均线为MA5,紫红色均线为MA20,你对照一下上面的图线)只买MA20上涨+MA5在MA20以上的+MA5上涨的股票,凡是买入后某天开盘后下跌3.8%的一律不计条件出局,或者MA5跌到MA20以下一律出局,或者MA20向下运动一律出局。这样每一只股总能吃到主体利润,下跌只有轻微损失,不会上主力的当!淋过雨的人,才会想到别人淋雨的感受,切记!
策略框架 **框架:**初始化+策略函数(周期循环)
初始化:通过初始化函数设置基准。初始化函数在整个回测或者实盘操作中只被运行一次,用于 初始化全局变量
函数:initialize(context)
context : Context对象,存放有当前的账户/股票持仓信息
示例:
1 2 3 def initialize : g.security = "000001.XSHE"
策略函数:策略开始后,随着时间周期 重复执行你的交易策略
1 2 3 4 5 def handle_data (context,data ): order(g.security, 1000 ) order(g.security, -800 )
order()聚宽的api
示例:
初始化中要有股票和策略运行周期
策略函数:
如果上一时间点价格高出五天平均价1%,则全仓买入
如果上一时间点价格低于五天平均价,则空仓卖入(画出上一时间点价格)
基础框架:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 from jqdata import * def initialize (context ): g.security = "000001.XSHE" run_daily(market_open, time='every_bar' ) def market_open (context ): security = g.security close_data = attribute_history(security, 5 , '1d' , ['close' ]) MA5 = close_data['close' ].mean() current_price = close_data['close' ][-1 ] cash = context.portfolio.available_cash if current_price > 1.01 * MA5: order_value(security, cash) log.info("买入 %s" % security) elif current_price < MA5 and context.portfolio.positions[security].closeable_amount > 0 : order_target(security, 0 ) log.info("卖出 %s" % security) record(stock_price=current_price)
这个策略则垃圾不要随便用
设置函数 策略设置函数
基准:设定业绩比较基准:set_benchmark(security)
佣金/印花税:set_order_cost(cost,type,ref=None)
滑点:真是成交价格与下单时预期的价格偏差,set_slippage(object,type=None,ref=None)
成交量比例:根据实际行情限制每个订单的成交量,set_option(‘order_volume_ratio’,value)
动态复权模式:设置真实价格,建议开启,set_option(‘use_real_option’,value)
这几个函数的使用
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 from jqdata import * def initialize (context ): set_benchmark('000300.XSHG' ) g.security = "000001.XSHE" run_daily(market_open, time='10:30' ) set_order_cost(OrderCost(open_commission=0.03 ,close_commission=0.03 ,close_tax=0.001 ),type ='stock' ) set_slippage(PriceRelatedSlippage(0.002 ),type ='stock' ) set_option('order_volume_ratio' ,0.5 ) set_option('use_real_price' ,True ) def market_open (context ): security = g.security close_data = attribute_history(security, 5 , '1d' , ['close' ]) MA5 = close_data['close' ].mean() current_price = close_data['close' ][-1 ] cash = context.portfolio.available_cash if current_price > 1.01 * MA5: order_value(security, cash) log.info("买入 %s" % security) elif current_price < MA5 and context.portfolio.positions[security].closeable_amount > 0 : order_target(security, 0 ) log.info("卖出 %s" % security) record(stock_price=current_price)
定时函数 作用:设定回测 和模拟交易 中运行时间及频率
月度:run_monthly(func,monthday,time=’open’,reference_security)
周度:run_weekly(func,weekday,time=’open’,reference_security)
日度:run_daily(func,time=’open’,reference_security)
参数
介绍
func
用户自定义接受 context
参数的函数,必须是全局函数
monthday
指定每月的第几个交易日执行函数。当值为负数时,表示在月末第几个交易日执行函数
time
字符串格式,支持 time
表达式,例如:‘9:30’
reference_security
表示时间的参照指标。如按照 “000001.XSHE” 交易时间
交易函数 交易函数:order(security,amount,style=None,side='long',pindex=0)
security:股票代码
amount:交易数量(负数表示卖出)
styple:下单类型
side:short空(一般不允许)/ long多
pindex:仓位号,默认为0
股票价值:order_value(security,value,style=None,side='long',pindex=0)
security:股票代码
value:交易数量(负数表示卖出)
styple:下单类型
side:short空(一般不允许)/ long多
pindex:仓位号,默认为0
目标数量:order(security,amount,style=None,side='long',pindex=0,close_today=False)
security:股票代码
amount:交易数量(负数表示卖出)
styple:下单类型
side:short空(一般不允许)/ long多
pindex:仓位号,默认为0
成交订单:get_orders(order_id=None,security=None,status=None)
get_orders(order_id=’123’) 订单id查询订单号为’123’的订单
get_orders(security=’000001.XSHE’) 查询所有标的为000001.XSHE的订单
未完成订单:get_open_orders()
在每天交易结束后获取当天所有未完成订单
1 2 3 4 def after_market_close (context ): orders = get_open_orders() for _order in orders: log.info(_order.order_id)
撤单函数:cancel_order(order)
在每天交易结束后对当天所有未完成订单撤单
1 2 3 4 def after_market_close (context ): orders = get_open_orders() for _order in orders: cancel_order(_order)
账户出入金(充钱):inout_cash(cash,pindex=0)
cash:浮点数,负数表示出金
pindex:仓位号,默认为0
向账户增加10000元,inout_cash(10000,pindex=0)
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 from jqdata import * def initialize (context ): set_benchmark('000300.XSHG' ) g.security = "000001.XSHE" run_daily(market_open, time='9:30' ) run_daily(after_market_close, time='15:30' ) def market_open (context ): inout_cash(10000 , pindex=0 ) log.info("""资金:{}""" .format (context.portfolio.subportfolios[0 ].available_cash)) cash = context.portfolio.available_cash if g.security not in context.portfolio.positions: order(g.security,1000 ) else : order(g.security,-500 ) def after_market_close (context ): orders = get_open_orders() for _order in orders: log.info(f"""未完成订单:{_order} """ ) for _order in orders: cancel_order(_order) log.info(f"""撤单:{_order} """ )
交易对象 **order对象:**订单处理流程
订单创建–>订单检查–>报单–>确认委托–>撮合
cummission:交易费用
is_buy:bool值,买还是卖
status:状态,一个OrderStatus值
price:平均成交价的
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 from jqdata import *def initialize (context ): set_benchmark('000300.XSHG' ) g.security = "000001.XSHE" run_weekly(market_open,1 ,time='open' ) def market_open (context ): if g.security not in context.portfolio.positions: orders = order(g.security,100 ) print (orders) if orders is None : print ("创建订单失败..." ) else : print (f"""交易费用:{orders.commission} """ ) print (f"""是否买单:{orders.is_buy} """ ) print (f"""订单状态:{orders.status} """ ) print (f"""订单平均成交价:{orders.price} """ ) else : order(g.security,-800 )
**trade对象:**订单成交相关信息
time:交易时间,[datetime.datetime]对象
security:标的代码
amount:交易数量
price:交易价格
trade_id:交易记录id
order_id:对应的订单id
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 from jqdata import *def initialize (context ): set_benchmark('000300.XSHG' ) g.security = "000001.XSHE" run_daily(market_open,time='9:30' ) run_daily(after_market_close, time='15:30' ) def market_open (context ): if g.security not in context.portfolio.positions: orders = order(g.security,100 ) else : order(g.security,-800 ) def after_market_close (context ): print (f"""闭市后""" ) trades = get_trades() for _trade in trades.values(): print (f"""成交记录:{_trade} """ ) print (f"""成交时间:{_trade.time} """ ) print (f"""对应的订单id:{_trade.order_id} """ )
策略信息 **Context对象:**策略信息总览,包含账户、时间等信息
subportfolios : 当前单个操作仓位的资金、标的信息,是一个 SubPortfolio
的数组。
portfolio : 账户信息,即 subportfolios
的汇总信息,Portfolio
对象,单个操作仓位时,portfolio
指向 subportfolios[0]
。
current_dt : 当前单位时间的开始时间,[datetime.datetime] 对象。
previous_date : 前一个交易日,[datetime.date] 对象,注意这是一个日期,是 date
,而不是 datetime
。
universe : 查询 set_universe()
设置的股票池,比如: ['000001.XSHE', '600000.XSHG']
。
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 from jqdata import *def initialize (context ): set_benchmark('000300.XSHG' ) g.security = "000001.XSHE" def handle_data (context, data ): context.portfolio = 1 log.info(context.portfolio) del context.portfolio log.info(context.portfolio.total_value) ------------------------------------------------------ from jqdata import *def initialize (context ): set_benchmark('000300.XSHG' ) g.security = "000001.XSHE" def handle_data (context, data ): log.info(context.portfolio.total_value) log.info(context.portfolio.positions_value) log.info(context.current_dt.day) log.info(context.portfolio.returns) log.info(context.subportfolios[0 ].available_cash)
**Position对象:**输出持有的标的信息
security : 标的的代码。
price : 最新行情价格。
total_amount : 总合计,不包括挂单冻结仓位。
init_time : 建仓时间,格式为 datetime.datetime
。
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 from jqdata import *def initialize (context ): set_benchmark('000300.XSHG' ) g.security = "000001.XSHE" def handle_data (context, data ): if g.security not in context.portfolio.positions: order(g.security,1000 ) else : order(g.security,-800 ) print (type (context.portfolio.long_positions)) long_positions_dict = context.portfolio.long_positions for position in list (long_positions_dict.values()): print (f"""标:{position.security} ,总仓位:{position.total_amount} ,标的价值:{position.value} ,建仓时间:{position.init_time} """ )
账户信息 **portfolio对象:**总帐户信息
long_positions : 多单的仓位,一个字典,key 是证券代码,value 是 [Position] 对象。
short_positions : 空单的仓位,一个字典,key 是证券代码,value 是 [Position] 对象。
total_value : 总的权益,包括现金、保证金(期货)或者仓位(股票)的总价值,可用于计算收益。
returns : 总权益的累计收益;(当前总资产 + 今日出入金 - 昨日总资产)/ 昨日总资产。
starting_cash : 初始资金,现在等于 inout_cash
。
positions_value : 持仓价值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from jqdata import *def initialize (context ): set_benchmark('000300.XSHG' ) g.security = "000001.XSHE" def handle_data (context, data ): if g.security not in context.portfolio.positions: order(g.security,1000 ) else : order(g.security,-800 ) print ("""多单的仓位:{}""" ,format (context.portfolio.long_positions)) print ("""空单的仓位:{}""" ,format (context.portfolio.short_positions)) print ("""总权益:{}""" ,format (context.portfolio.total_value)) print ("""总权益的累计收益:{}""" ,format (context.portfolio.returns)) print ("""初始资金:{}""" ,format (context.portfolio.starting_cash)) print ("""持仓价值:{}""" ,format (context.portfolio.positions_value))
**subportfolio对象:**子账户信息
inout_cash : 累计出入金,如初始资金 1000,后面转移出去 100,则这个值是 1000 - 100。
available_cash : 可用资金,可以用来购买证券的资金。
transferable_cash : 可取资金,即可以提取的资金,不包括今日卖出证券所得资金。
locked_cash : 挂单锁住资金。
type : 账号所属类型。
code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 from jqdata import *def initialize (context ): set_benchmark('000300.XSHG' ) g.security = "000001.XSHE" def handle_data (context, data ): if g.security not in context.portfolio.positions: order(g.security,1000 ) else : order(g.security,-800 ) print ("""累计出入金:{}""" ,format (context.subportfolios[0 ].inout_cash)) print ("""可用资金:{}""" ,format (context.subportfolios[0 ].available_cash)) print ("""可取资金:{}""" ,format (context.subportfolios[0 ].transferable_cash)) print ("""挂单锁住资金:{}""" ,format (context.subportfolios[0 ].locked_cash)) print ("""账户所属类型:{}""" ,format (context.subportfolios[0 ].type ))
量化交易数据获取 个股K线数据可以直接通过同花顺,聚宽等直接下载
财务数据 **get_fundamentals(query_object,date=None,statDate=None):**查询财务数据
注意 : date
和 statDate
参数只能传入一个。
传入 date
时,查询指定日期后能看到的最近(除市值表外为最近一个季度,市值为最近一天)的数据。
传入 statDate
时,查询 statDate
指定的季度或年份的财务数据。
date/statdate : 获取一个字符串(格式类似 ‘2015-10-15’)或 datetime
对象。
query_object : 一个 sqlalchemy.orm.query.Query
对象,可以通过全局的 query
函数获取。
query_object():查询数据API,可以是 整张表,也可以是标准的多个字段或计算结果
filter : 填写过滤条件,可以使用逗号分隔多个条件,或使用 and
、or
。
order_by : 填写排序条件。
limit : 限制返回的个数。
group_by : 进行分组统计。
示例:
1 query(valuation).filter (valuation.code == '000001.XSHE' )
**get_fundamentals_continuously(query_object,end_date=None,count=None,panel=True):**查询多日的财务数据
end_date : 获取一个字符串(格式类似于 ‘2015-10-15’)或 datetime 对象。
count : 获取 end_date
前的 count
个日期的数据,count
应小于 500。
panel : 默认 panel=True
,返回一个 pandas.Panel
;建议设置 panel=False
,返回更有效的 DataFrame。
1 2 3 4 5 6 7 8 9 10 11 from jqdata import *q = query( valuation ).filter ( valuation.code == '000001.XSHE' ) df = get_fundamentals(q,'2022-09-01' ) print (df['market_cap' ][0 ])
量化选股 量化选股概况
量化选股 : 利用数量化的方法选择股票组合 ,期望该组合能够获得超越基准的投资行为。
技术面选股 : 利用各种技术理论或技术指标 来分析和预测股票的未来价格走势。
基本面选股 : 通过对上市公司在发展过程中面临的外部因素 和自身因素 进行分析,判断该公司的股票是否值得购买。
量化选股注意事项
分配多股,减少单股重仓的情况
全面研究个股基本面,增强个股判断逻辑和支撑
主动投资而非被动投资
只是提高胜率的工具之一
白马股选股
一、筛选条件:
总市值>50亿(市值较大的公司,流动性好,竞争力强)
上市天数>750(抛开3年以内的次新)
流通盘比例>95%(要全流通,避免解禁压力)
销售毛利率>20%(毛利率要高)
扣非净资产收益率>20%(ROE要高)
二、排名条件:
总市值从大到小排列
按照上面的策略code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 from jqdata import *import datetimedef initialize (context ): set_benchmark('000300.XSHG' ) set_option('use_real_price' ,True ) set_option('order_volume_ratio' ,1 ) set_order_cost(OrderCost(open_tax=0 ,close_tax=0.001 , open_commission=0.0003 ,close_commission=0.0003 , close_today_commission=0 ,min_commission=5 ),type ='stock' ) g.stocknum = 20 g.days = 20 g.refresh_rate = 100 run_daily(trade, 'every_bar' ) def check_stocks (context ): q = query( indicator.code, valuation.capitalization, indicator.roe, indicator.gross_profit_margin, ).filter ( valuation.capitalization > 50 , valuation.circulating_market_cap > valuation.market_cap*0.95 , indicator.gross_profit_margin > 20 , indicator.roe > 20 , ).order_by( valuation.market_cap.desc() ).limit( 100 ) df = get_fundamentals(q,statDate=str (context.current_dt)[:4 ]) buylist = list (df['code' ]) buylist = delect_stock(buylist,context.current_dt,750 ) buylist = filter_paused_stock(buylist)[:20 ] return buylist def filter_paused_stock (stock_list ): current_date = get_current_data() return [stock for stock in stock_list if not current_date[stock].paused] def delect_stock (stocks,begin,n=180 ): stockList=[] for stock in stocks: start_date = get_security_info(stock).start_date if start_date < (begin - timedelta(days=n)).date(): stockList.append(stock) return stockList def trade (context ): if g.days % g.refresh_rate == 0 : stockList = check_stocks(context) print ("""stockList:{}""" ,format (stockList)) sell_list = list (context.portfolio.positions.keys()) sells = list (set (sell_list).difference(set (stockList))) for stock in sells: order_target_value(stock,0 ) if len (context.portfolio.positions) < g.stocknum: num = g.stocknum - len (context.portfolio.positions) cash = context.portfolio.cash / num else : cash = 0 for stock in stockList: if len (context.portfolio.positions) < g.stocknum and stock not in context.portfolio.positions: order_value(stock,cash) g.days = 1 else : g.days += 1
营收因子
财务因素 : 通常包括成长类因素、价值类因素以及质量类因素。
成长类因素 : 在财务因素选股中,常用的方法是选择成长类因素进行选股,包括营收因素与利润因素。
规模类因素 : 反映公司规模情况,主要用于体现市场价值大小,对投资收益产生影响,包括总市值和流通市值
价值类因素 : 价值投资是一种长期的投资策略,通常是购买那些相对低估的股票,主要基于基本面标准。价值类因素包括市净率、市销率,以及市盈率等指标。
质量类因素 : 质量类因素与股票的财务质量、资本结构相关,主要用于评估公司整体的财务健康状态。质量类因素包括净资产收益率,以及总资产净利率等指标。
量化择时 概述:采用量化的方式判断买点和卖点
趋势量化择时 ——基本思想基于技术分析 ,前提时你得承认有一定的规律(那三个假设)
市场情绪量化择时 ——利用投资者的热情程度来判断大势方向
后者舍去(一堆散户在哪里他能涨吗)
前者:通过考虑市场的多个方面建立一个数学模型,并给出完整的数学公式
技术趋势指标是识别和追踪有趋势的图形类指标,其特点是不试图捕捉顶底 ,如均线指标、MACD指标等。
反趋势指标又称为振荡指标 ,是识别和追踪趋势运行的转折点的图形类指标,其特点是具有强烈的顶底 的意义,对市场转折点较敏感,如随机指标KDJ、强弱指标RSI等。
压力支撑指标,又称通道指标,是通过顶部轨道线和底部轨道线,试图捕捉行情的顶部和底部的图形类指标,其特点是具有明显的压力线,也有明显的支撑线 ,如布林带 BOLL 指标、XS 藤斯通道指标。
量价指标就是通过成交量变动来分析价格未来走势的图形类指标,其特点是分析成交量与价格波动的关系 ,如 OBV 能量潮指标、VOL 成交量指标等。
趋势指标 MACD 即平滑异同移动平均线,是由美国投资家杰拉尔德·阿佩尔在 20 世纪 70 年代末提出的,主要表示经过平滑处理后线的差异程度。一般用来判断股票价格变化的方向、强度和趋势 。
快线 DIFF 上穿慢线 DEA,红柱出现的第一天 ,称为金叉 ,是买进持有的时机;
快线 DIFF 下穿慢线 DEA,绿柱出现的第一天 ,称为死叉 ,是卖出空仓的时机。
MACD(security_list, check_date, SHORT = 12, LONG = 26, MID = 9)
参数:
security_list:标的列表
check_date:要查询数据的日期
SHORT:统计的天数 SHORT
LONG:统计的天数 LONG
MID:统计的天数 MID
unit:统计周期,默认为 ‘1d’, 支持如下周期: ‘1m’, ‘5m’, ‘15m’, ‘30m’, ‘60m’, ‘120m’, ‘1d’, ‘1w’, ‘1M’. ‘1w’ 表示一周, ‘1M’ 表示一月
include_now:是否包含当前周期,默认为 True
fq_ref_date:复权基准日,默认为 None
返回:
返回结果类型:
字典(dict):键(key)为标的代码,值(value)为数据。
如:({‘000001.XSHE’: 0.024474457964069884, ‘603177.XSHG’: nan, ‘000002.XSHE’: 1.9534717416190936, ‘601211.XSHG’: -0.13735007291032986}, {‘000001.XSHE’: 0.031674925444633864, ‘603177.XSHG’: nan, ‘000002.XSHE’: 1.4784672678080988, ‘601211.XSHG’: -0.020490844872792721}, {‘000001.XSHE’: -0.014400934961127959, ‘603177.XSHG’: nan, ‘000002.XSHE’: 0.95000894762198973, ‘601211.XSHG’: -0.23371845607507427})
备注:
用法注释:
DIFF线 收盘价短期、长期指数平滑移动平均线间的差 DEA线 DIFF线的M日指数平滑移动平均线 MACD线 DIFF线与DEA线的差,彩色柱状线 参数:SHORT(短期)、LONG(长期)、M 天数,一般为12、26、9
用法: 1.DIFF、DEA均为正,DIFF向上突破DEA,买入信号。 2.DIFF、DEA均为负,DIFF向下跌破DEA,卖出信号。 3.DEA线与K线发生背离,行情反转信号。 4.分析MACD柱状线,由红变绿(正变负),卖出信号;由绿变红,买入信号
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 security_list1 = '000001.XSHE' security_list2 = ['000001.XSHE' ,'000002.XSHE' ,'601211.XSHG' ,'603177.XSHG' ] macd_dif, macd_dea, macd_macd = MACD(security_list1,check_date='2017-01-04' , SHORT = 12 , LONG = 26 , MID = 9 ) print macd_dif[security_list1]print macd_dea[security_list1]print macd_macd[security_list1]macd_dif, macd_dea, macd_macd = MACD(security_list2,check_date='2017-01-04' , SHORT = 12 , LONG = 26 , MID = 9 ) for stock in security_list2: print macd_dif[stock] print macd_dea[stock] print macd_macd[stock]
UOS 即终极波动指标。UOS指标是一种多功能的指标,除了超买超卖方面的作用之外,它的“突破”讯号不仅可以提供最适当的交易时机之外,更可以进一步强化指标的可靠度。
TH = 今日最高价和昨日收盘价的较大值
TL = 今日最低价和昨日收盘价的较小值
ACCC1 = (收盘价 - TL) 的 N1 日累和 / (TH - TL) 的 N1 日累和 ACCC2 = (收盘价 - TL) 的 N2 日累和 / (TH - TL) 的 N2 日累和 ACCC3 = (收盘价 - TL) 的 N3 日累和 / (TH - TL) 的 N3 日累和
UOS = (ACCC1 * N2 * N3 + ACCC2 * N1 * N3 + ACCC3 * N1 * N2) * 100 / (N1 * N2 + N1 * N3 + N2 * N3)
MAUOS = UOS 的 M 日指数平滑移动平均
参考 N1 = 7, N2 = 14, N3 = 28, M = 6
UOS短线拐底:UOS上穿50
UOS短线卖顶:UOS下穿65
UOS中长期拐底:UOS上穿35
UOS中长期卖顶:UOS下穿70
参考代码
MA 均线——葛兰碧法则
平均线从下下降逐渐转为走平,而价格从下方突破平均线,为买进信号
价格虽然跌破平均线,但是又立刻回升到平均线上,此时平均线仍然持续上涨,仅为买进信号
价格趋势走在平均线上,价格下跌并未跌破平均线且立刻反转上升,为买进信号
价格突然暴跌,跌破平均线,且远离平均线,则有可能反弹上升,为买进时机
平均线从上升逐渐转为盘局或下跌,而价格向下跌破平均线,为卖出信号
价格虽然向上突破平均线,但是又立刻回跌至平均线下,此时平均线仍然持续的下降,仅为卖出信号
价格趋势走在平均线下,价格上升并未突破平均线且立刻反转下跌,也是卖出信号
价格突然暴涨,突破平均线,且远离平均线,则有可能反弹回调,也为卖出时机
看看就好
MA(security_list, check_date, timeperiod=5, unit = '1d', include_now = True, fq_ref_date = None)
参数:
security_list:标的列表
check_date:要查询数据的日期
timeperiod:统计的天数timeperiod
unit:统计周期,默认为 ‘1d’, 支持如下周期: ‘1m’, ‘5m’, ‘15m’, ‘30m’, ‘60m’, ‘120m’, ‘1d’, ‘1w’, ‘1M’. ‘1w’ 表示一周, ‘1M’ 表示一月
include_now:是否包含当前周期,默认为 True
fq_ref_date:复权基准日,默认为 None
返回:
返回结果类型:
字典(dict):键(key)为标的代码,值(value)为数据。
如:{‘000001.XSHE’: 9.2599999999999998, ‘603177.XSHG’: nan, ‘000002.XSHE’: 20.68, ‘601211.XSHG’: 18.704000000000001}
备注:
用法注释:
1.股价高于平均线,视为强势;股价低于平均线,视为弱势 2.平均线向上涨升,具有助涨力道;平均线向下跌降,具有助跌力道; 3.二条以上平均线向上交叉时,买进; 4.二条以上平均线向下交叉时,卖出; 5.移动平均线的信号经常落后股价,若以EXPMA 、VMA 辅助,可以改善。
VMA 变异平均线
VMA(security_list, check_date, timeperiod = 12, unit = '1d', include_now = True, fq_ref_date = None)
参数:
security_list:标的列表
check_date: 要查询数据的日期
timeperiod:统计的天数
unit:统计周期,默认为 ‘1d’, 支持如下周期: ‘1m’, ‘5m’, ‘15m’, ‘30m’, ‘60m’, ‘120m’, ‘1d’, ‘1w’, ‘1M’. ‘1w’ 表示一周, ‘1M’ 表示一月
include_now:是否包含当前周期,默认为 True
fq_ref_date:复权基准日,默认为 None
返回:
返回结果类型:
字典(dict):键(key)为标的代码,值(value)为数据。
如:{‘000001.XSHE’: 8.3202083333333334, ‘603177.XSHG’: nan, ‘000002.XSHE’: 18.979166666666668, ‘601211.XSHG’: 16.474166666666669}
备注:
用法注释:
股价高于平均线,视为强势;股价低于平均线,视为弱势;
平均线向上涨升,具有助涨力道;平均线向下跌降,具有助跌力道;
二条以上平均线向上交叉时,买进;
二条以上平均线向下交叉时,卖出;
VMA 比一般平均线的敏感度更高,消除了部份平均线落后的缺陷。
反趋向指标 RSI RSI :即相对强弱指标,是期货市场和股票市场中最为著名的动量指标。显示的是股价向上波动的幅度占总的波动幅度的百分比。如果其数值大,就表示市场处于强势状态,如果数值小,则表示市场处于弱势。
计算公式:NRSI = A / (A + B) × 100
A = N日内上涨的平均值之和;B = N日内下跌的平均值之和(取正值)
由于上面的公式对RSI的定义较为明确,即上涨的力量与下跌的力量进行比较 ,显然,上涨的力量越大,对应计算出的指数越上升;而下跌的力量越大,则对应指数出市场的弱势。
策略L:
RSI > 80 为超买,RSI < 20 为超卖
RSI 以50为中界线,大于50为多头行情,小于50为空头行情
RSI 在80以上形成M头或顶部形态时,为向下反转信号
RSI 在20以下形成W底或底部形态时,为向上反转信号
RSI(security_list, check_date, N1=6, unit = '1d', include_now = True, fq_ref_date = None)
参数:
security_list:标的列表
check_date:要查询数据的日期
N1:统计的天数N1
unit:统计周期,默认为 ‘1d’, 支持如下周期: ‘1m’, ‘5m’, ‘15m’, ‘30m’, ‘60m’, ‘120m’, ‘1d’, ‘1w’, ‘1M’. ‘1w’ 表示一周, ‘1M’ 表示一月
include_now:是否包含当前周期,默认为 True
fq_ref_date:复权基准日,默认为 None
返回:
返回结果类型:
字典(dict):键(key)为标的代码,值(value)为数据。
如: {‘000001.XSHE’: 86.697784941552129, ‘603177.XSHG’: nan, ‘000002.XSHE’: 45.669839353084029, ‘601211.XSHG’: 65.952531344607962}
1 2 3 4 5 6 7 8 from jqdata import *from jqlib.technical_analysis import *security_list = ['000001.XSHE' ,'000002.XSHE' ,'601211.XSHG' ] _RSI = RSI(security_list,check_date='2022-09-01' ,N1=6 ) for stock in security_list: print (stock,'2022-09-01RSI=' ,_RSI[stock])
KDJ 定义前面有,用的非常多
KDJ(security_list, check_date, N =9, M1=3, M2=3, unit = '1d', include_now = True, fq_ref_date = None)
参数:
security_list:标的列表
check_date:要查询数据的日期
N:统计的天数 N
M1:统计的天数 M1
M2:统计的天数 M2
unit:统计周期,默认为 ‘1d’, 支持如下周期: ‘1m’, ‘5m’, ‘15m’, ‘30m’, ‘60m’, ‘120m’, ‘1d’, ‘1w’, ‘1M’. ‘1w’ 表示一周, ‘1M’ 表示一月
include_now:是否包含当前周期,默认为 True
fq_ref_date:复权基准日,默认为 None
返回:
返回结果类型:
字典(dict):键(key)为标的代码,值(value)为数据。
如:({‘000001.XSHE’: 89.145187806127595, ‘603177.XSHG’: nan, ‘000002.XSHE’: 20.523907534762358, ‘601211.XSHG’: 82.545216532766361}, {‘000001.XSHE’: 82.915346288340473, ‘603177.XSHG’: nan, ‘000002.XSHE’: 21.246652224886216, ‘601211.XSHG’: 80.903864946907802}, {‘000001.XSHE’: 101.60487084170185, ‘603177.XSHG’: nan, ‘000002.XSHE’: 19.078418154514644, ‘601211.XSHG’: 85.827919704483492})
用法注释:
指标>80 时,回档机率大;指标<20时,反弹机率大;
K在20左右向上交叉D时,视为买进信号;
K在80左右向下交叉D时,视为卖出信号;
J>100 时,股价易反转下跌;J<0 时,股价易反转上涨;
KDJ 波动于50左右的任何信号,其作用不大。
压力支撑指标 BOLL Bollinger_Bands(security_list, check_date, timeperiod=20, nbdevup=2, nbdevdn=2, unit = '1d', include_now = True, fq_ref_date = None)
参数:
security_list:标的列表
check_date:要查询数据的日期
timeperiod:统计的天数timeperiod
nbdevup:统计的天数 nbdevup
nbdevdn:统计的天数 nbdevdn
unit:统计周期,默认为 ‘1d’, 支持如下周期: ‘1m’, ‘5m’, ‘15m’, ‘30m’, ‘60m’, ‘120m’, ‘1d’, ‘1w’, ‘1M’. ‘1w’ 表示一周, ‘1M’ 表示一月
include_now:是否包含当前周期,默认为 True
fq_ref_date:复权基准日,默认为 None
返回:
返回结果类型:
字典(dict):键(key)为标的代码,值(value)为数据。
如: ({‘000001.XSHE’: 9.2899945886169739, ‘603177.XSHG’: nan, ‘000002.XSHE’: 21.378028110909778, ‘601211.XSHG’: 18.846866409164456}, {‘000001.XSHE’: 9.1745000000000037, ‘603177.XSHG’: nan, ‘000002.XSHE’: 20.795500000000004, ‘601211.XSHG’: 18.423999999999999}, {‘000001.XSHE’: 9.0590054113830334, ‘603177.XSHG’: nan, ‘000002.XSHE’: 20.21297188909023, ‘601211.XSHG’: 18.001133590835543})
备注:
用法注释:
股价上升穿越布林线上限时,回档机率大;
股价下跌穿越布林线下限时,反弹机率大;
布林线震动波带变窄时,表示变盘在即;
BOLL须配合BB 、WIDTH 使用;
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 security_list1 = '000001.XSHE' security_list2 = ['000001.XSHE' ,'000002.XSHE' ,'601211.XSHG' ,'603177.XSHG' ] upperband, middleband, lowerband = Bollinger_Bands(security_list1, check_date='2017-01-04' , timeperiod=20 , nbdevup=2 , nbdevdn=2 ) print upperband[security_list1]print middleband[security_list1]print lowerband[security_list1]upperband, middleband, lowerband = Bollinger_Bands(security_list2, check_date='2017-01-04' , timeperiod=20 , nbdevup=2 , nbdevdn=2 ) for stock in security_list2: print upperband[stock] print middleband[stock] print lowerband[stock]
量价指标 OBV 参考连接
VOL 成交量指标:
用法注释:
成交量大,代表交投热络,可界定为热门股;
底部起涨点出现大成交量(成交手数),代表攻击量;
头部地区出现大成交量(成交手数),代表出货量;
观察成交金额的变化,比观察成交手数更具意义,因为成交手数并未反应股价的涨跌的后所应支出的实际金额。
参考链接
1 2 3 4 5 6 7 8 9 10 11 12 from jqdata import *from jqlib.technical_analysis import *security_list = ['000001.XSHE' ,'000002.XSHE' ] check_dates = ['2022-10-31' ,'2022-11-01' ] for check_date in check_dates: for security in security_list: _VOL,MAVOL1,MAVOL2 = VOL(security,check_date=check_date,M1=5 ,M2=10 ) print (check_date,f'{security} 的VOL:' ,_VOL[security]) print (check_date,f'{security} 的MOVAL1:' ,MAVOL1[security]) print (check_date,f'{security} 的MOVAL2:' ,MAVOL2[security])
量化策略回测 回测流程 1 2 3 4 5 6 7 flowchart LR A[选择股票池和实现回测函数] --> B[设定回测时间段,初始金额及调仓频率] B --> C[历史数据载入] C --> D[处理订单] D --> E[取消未完成订单] E --> F[输出日志] F --> G[生成回测报告]
选择股票池和实现回测函数 实现handle_data函数 编写量化交易策略
选定一个回测开始时间和结束日期 选择初始金额和调仓频率
取得股票数据 调用handle_data()函数
下单后,根据接下来时间的实际交易情况,处理订单
下单后,可以调用get_open_orders()取得所有未完成订单,调用cancel_order取消订单
可在任何时间打印日志
回测结束,生成回测报告,画出收益曲线和基准收益曲线,列出每日持仓和交易情况
MACD 金叉买入,死叉卖出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import jqdatafrom jqlib.technical_analysis import *import pandas as pddef initialize (context ): set_benchmark('000300.XSHG' ) set_option('use_real_price' , True ) g.security = '000001.XSHE' g.macd_yesterday = 0 def handle_data (context, data ): security = g.security DIF,DEA,_MACD = MACD(security_list = security,check_date=context.current_dt, SHORT=6 ,LONG=12 ,MID=9 ) cash = context.portfolio.cash if g.macd_yesterday < 0 and _MACD[security] > 0 and cash > 0 : order_value(security,cash) elif g.macd_yesterday > 0 and _MACD[security] < 0 and context.portfolio.positions[security].closeable_amount > 0 : order_target(security,0 ) g.macd_yesterday = _MACD[security]
量化回测的风险指标 定义:即股票投资收益率的不确定性 通常称之为风险 ,具体是指股票市场的一些未知的、不可预测的因素对股票价格造成的不确定的影响,可能是正面影响收益率,也可能是负面的背离。风险指标是对风险的量化评估 。
特点:风险指标有利于投资者对投资策略进行一个客观的评价。无论是回测还是模拟,所有风险指标都会根据每天收益后的收益计算 更新一次,并不考虑每盘中的收益情况 。
定义:Alpha是投资者获得与市场波动无关的回报。阿尔法系数,是基金/投资的绝对回报和按照beta系数计算的预期回报之间的差额。阿尔法收益与风险相关性很低。
算法:绝对收益或超额收益是基金/投资的实际收益减去无风险投资收益 。例如投资者获得了15%的回报,其基准获得了10%的回报,那么Alpha部分就是5%。
公式:Alpha = 投资年化收益率 - [无风险回报率+Beta*(基准年化收益率 - 无风险回报率)]
beta:表示投资的系统性风险,反映了策略对大盘变化的敏感性。例如一个策略的Beta为1.5,则大盘涨1%的时候,策略可能涨1.5%,反之亦然;如果一个策略的Beta为-1.5,说明大盘涨1%的时候,策略可能跌1.5%,反之亦然。
夏普比率:表示每承受一单位总风险,会产生多少的超额报酬,可以同时对策略的收益与风险进行综合考虑 。(越高越好)
各种风险指标详细参考
因子分析 因子分析概述 就是根据因子或特定的特征使我们能赚钱的方法。包括波动性、动量、股票规模等。
综述一下,就是根据财务指标和技术指标 作为因子(因子构造),通过选定的因子来选股(因子选股),构建股票池,策略回测(再优化)
自定义因子 自定义因子类继承了factor类,三个基本属性,分别为name、max_window和dependencies ;一个核心函数——calc()
构建自定义因子流程:构造因子属性—->实现因子计算—–>因子分析
name,因子名称。因子名称只能由字母、数字和下划线组成,并且第一个字符不能是数字,另外不能与Python中的关键字相同,也不能与基础因子冲突。
max_window,获取数据的最长时间窗口,返回日线数据。
dependencies,自定义因子依赖的基础因子名称,如high, low, close。
**因子计算:**实现Factor类内置calc()函数 calc(self,data)
data:字典对象
key属性是dependencies中的因子名称
value属性是因子对应的数据表(pandas.DataFrame格式)
示例:
1 2 def calc (self,data ): return data['close' ][-10 ].mean()
返回:Pandas.Series:index属性是股票代码,value属性是因子值
**单因子分析:**调用analyze_factor
analyze_factor(factor,start_date,end_date,industry,universe,quantiles,periods,weight_method,use_real_price,skip_paused,max_loss,factor_dep_definitions)
factor: 获取因子值,可输入三种类型的值
pandas.DataFrame: 因子值,columns为股票代码(如’000001.XSHE’),index为日期的DatetimeIndex或str
pandas.Series: 因子值,index为日期索引和股票代码的MultiIndex
Factor的子类,自定义因子
start_date: 开始日期;end_date: 结束日期
industry: 获取行业分类,默认值为’jq_l1’ ‘sw_l1’:申万一级行业;’sw_l2’:申万二级行业;’sw_l3’:申万三级行业;’jq_l1’:聚宽一级行业;’jq_l2’:聚宽二级行业;’zjw’: 证监会行业
universe: 对股票池 的定义,可输入两种类型的值。为str时认为输入的是一个股票池;当factor输入为因子值时(DataFrame、Series),该参数无效
quantiles: 分位数数量,默认5
periods: 调仓周期,int或int的列表,默认[1, 5, 10]
weight_method: 计算分位数收益时的加权方法;avg: 按平均加权;mktcap: 按市场加权
use_real_price: 是否使用复权,默认False(当factor为因子值时这个参数失效)
skip_paused: 是否跳过停牌,默认False(当factor为因子值时这个参数失效)
max_loss: 因重置值或nan值太多而无效的因子值的最大占比,默认0.25
factor_dep_definitions: 主因子的依赖因子的列表,默认为空列表(注:当factor为因子值时这个参数失效)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 from jqfactor import Factor,analyze_factorwarnings.filterwarnings('ignore' ) class MA10 (Factor ): name = 'ma10' max_window = 10 dependencies = ['close' ] def calc (self,data ): return data['close' ][-10 :].mean() far = analyze_factor(factor=MA10,start_date='2022-01-01' ,end_date='2022-06-30' ,weight_method='mktcap' , universe='000300.XSHG' ,industry='jq_l1' ,quantiles=8 ,periods=(1 ,5 ,10 )) far.ic_monthly
害,突然觉得量化基于这些指标的操作我并不喜欢,或者说我觉得量化的这些策略并没太大好处,就到这了