1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > 基于夏普比率对因子的筛选 以及基于股票期货交易策略对多因子策略的机器学习算法探讨

基于夏普比率对因子的筛选 以及基于股票期货交易策略对多因子策略的机器学习算法探讨

时间:2024-05-11 15:33:46

相关推荐

基于夏普比率对因子的筛选 以及基于股票期货交易策略对多因子策略的机器学习算法探讨

试论因子的筛选,股票期货策略,以及基于多因子策略的机器学习算法

前言正文股票因子的筛选股票期货策略基于多因子策略的机器学习

前言

之前参加泰迪杯的,但又没什么时间,自己又是python新手,量化投资新手,还有不熟悉量化投资软件的使用。做的一塌糊涂。。往后却没有时间参加。

写这个文章,虽然也很糟糕,但也算是提供一种思路吧,便于新手入门的参考吧,也算是自己的一种收获吧。

正文

本文以python3.7上点宽网采用-01-01至-09-30时期的平台数据,以及回测框架。

股票因子的筛选

因子:能引起股票产生变化的因素,常见的有价值类因子PB,PE等等。。。见链接

因子获取

这里以获取价值类的因子数据为例(那里共有12大类):

# -*- coding: utf-8 -*- ##支持中文输入from atrader import * # 导入atrader工具包,点宽回测必须的包import pandas as pd # 导入pandas工具包import os ###处理文件和目录因子类名='价值类'因子类=['NegMktValue','PE','PB','PS','MktValue','PCF','LFLO','LCAP','NLSIZE','ForwardPE','StaticPE','ETOP','CETOP','PEG3Y','PEG5Y','CTOP','TA2EV','ETP5','CTP5']股票 = pd.DataFrame(get_code_list('hs300', date='-09-30')) ##获取 年 9 月 30 日沪深 300 指数的成分股及权重:for 序号, 数据 in 股票.iterrows(): ##进入循环多个因子 = pd.ExcelWriter("C:\\因子\\%s\\%s_%d_%s.xlsx" % (因子类名,因子类名,序号, 数据['name']))isExists=os.path.exists("C:\\因子\\%s\\"%因子类名)if not isExists:os.makedirs(r"C:\\因子\\%s\\"%因子类名)因子数值 = get_factor_by_code(factor_list=因子类,target=数据['code'],begin_date='-01-1', end_date='-09-30') #这里是获取某个日期范围内的数据文件 = pd.DataFrame(data=因子数值) ##文件.to_excel(多个因子, sheet_name=数据['name'], index=False)print("已完成第%d个,本企业代码为%s"%(序号,数据['code'])) 多个因子.save() ###文件保存print("已完成!!")

其中,利用点宽的函数get_code_list(‘hs300’, date=‘-09-30’),数据前几行长这样:

完成后有300家股票对应的因子数据,第一家平安银行的因子数据前几行长这样:

因子处理

# -*- coding: utf-8 -*-from atrader import *import numpy as npimport pandas as pdimport ffn各类因子 = ["基础科目与衍生类","质量类","收益风险类","情绪类","成长类","常用技术指标类","动量类","价值类","每股指标类","模式识别类","行业、分析师类","特色技术指标类"]hs300 = pd.read_excel('G:\\泰迪杯\\\\A\\因子\\hs300.xlsx')table=pd.DataFrame()for i, j in hs300.iterrows():##获取时期内单个股票的bar,循环,连续300个股票的barkdata = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\bar\\bar_%d_%s.xlsx' % (i, j['name'])))dataclose = kdata.closedatavolume = kdata.volumedataopen = kdata.opendatahigh = kdata.highdatalow = kdata.lowdataamount = kdata.amount##数据读入并处理删除整列空值的以及删除日期列-----d0 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[0], 各类因子[0], i, j['name']))).dropna(axis=1, how="all")d1 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[1], 各类因子[1], i, j['name']))).dropna(axis=1, how="all").drop(['date'], axis=1, inplace=False)d2 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[2], 各类因子[2], i, j['name']))).dropna(axis=1, how="all").drop(['date'], axis=1, inplace=False)d3 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[3], 各类因子[3], i, j['name']))).dropna(axis=1, how="all").drop(['date'], axis=1, inplace=False)d4 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[4], 各类因子[4], i, j['name']))).dropna(axis=1, how="all").drop(['date'], axis=1, inplace=False)d5 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[5], 各类因子[5], i, j['name']))).dropna(axis=1, how="all").drop(['date'], axis=1, inplace=False)d6 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[6], 各类因子[6], i, j['name']))).dropna(axis=1, how="all").drop(['date'], axis=1, inplace=False)d7 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[7], 各类因子[7], i, j['name']))).dropna(axis=1, how="all").drop(['date'], axis=1, inplace=False)d8 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[8], 各类因子[8], i, j['name']))).dropna(axis=1, how="all").drop(['date'], axis=1, inplace=False)d9 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[9], 各类因子[9], i, j['name']))).dropna(axis=1, how="all").drop(['date'], axis=1, inplace=False)d10 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[10], 各类因子[10], i, j['name']))).dropna(axis=1,how="all").drop(['date'], axis=1, inplace=False)d11 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[11], 各类因子[11], i, j['name']))).dropna(axis=1,how="all").drop(['date'], axis=1, inplace=False)合并 = pd.concat([d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11], axis=1)if len(合并['date']) != len(kdata['time']):print("长度不一致")continuefactors=合并.drop(['date'], axis=1, inplace=False)factorname = []sharpe_factor=[]for ii ,jj in factors.iteritems():###按列循环##判断某个时期某个因子的值是否一直不变,如果不变,则主观认为该因子在本股票内的这个时期内并没有影响,所以被忽略计算if jj.var() == jj.mean():# print("该因子名称为",ii,"的值始终相同,已舍去。")continuefactorname.append(ii) ##记录因子的名字ret=ffn.to_returns(dataclose) ##计算每期收益率,####参考书籍‘量化投资以python为工具----蔡立耑 著’252页jjj = jj.astype(np.float) ###转为float类型jjj = jjj.fillna(np.nanmean(jj)) ##因子缺失值处理jjj[jjj < jjj.mean() - 3 * jjj.std()] = jjj.mean() - 3 * jjj.std() ##极小值处理jjj[jjj > jjj.mean() + 3 * jjj.std()] = jjj.mean() + 3 * jjj.std() ##极大值处理jjj = (jjj - jjj.min()) / (jjj.max() - jjj.min()) ##数据标准化(归一化)f=pd.DataFrame(ret[1:].values)/pd.DataFrame(jjj[:-1].values) ##截面回归分析,其中f为因子收益率###这里,我参考点宽网的相关资料,采用截面回归分析,大家也可以采用其他方法。。f[np.isinf(f)]=np.nan ##正负无穷值处理为缺失值f = f.dropna(axis=0, how="all") ###缺失值的剔除sharpe=ffn.calc_risk_return_ratio(f) ###计算整个时期的夏普比率sharpe_factor.append(sharpe)##每个因子的夏普比率记录###转为dataframetable1 = pd.concat([pd.DataFrame(factorname),pd.DataFrame(sharpe_factor)], axis=1)table1.columns = ['%s_因子'% (j['name']) , '夏普比率%d' % (i)]###利用其中函数进行排序,在转为dataframetable2=pd.DataFrame(table1.sort_values(by='夏普比率%d' % (i),ascending=False).values)table2.columns = ['%s_因子'% (j['name']) , '夏普比率%d' % (i)]table = pd.concat([table, table2], axis=1)print(table)#print("当前已完成到第",i,j['name'])# table.to_excel('G:\\合并因子.xlsx', 'rb')

其中,300个股票的平安银行bar的前几行数据长这样:

其中,计算收益率,年化收益率,夏普比率等可以参考python ffn包,详情看链接1或者链接2

其中截面数据回归分析,单个因子的具体算法可以参考点宽,看下图

其中,第一个股票因子合并后的某几个因子的数据长这样:(大概有5-6百个因子数据)

第一个股票的单期收益率和整个时期的夏普比率长这样:

程序运行完后,部分相对应因子的夏普比率如图,这里是以截面回归分析而来的,也可以采取其他的方法计算收益率,夏普比率。

通过上面的代码,我们就可以按照夏普比率来挑选出因子了。

股票期货策略

就本人稍微看过的,股票期货策略有动量交易策略,RSI相对强弱指标策略,均线系统策略,通道突破策略,随机交易指标策略,OBV指标交易策略等等,均可上度娘搜一下,

详情可以参考书籍‘量化投资以python为工具----蔡立耑 著’,或者其他相关量化书籍。

基于多因子策略的机器学习

机器学习需要训练集,测试集;

这里我把

本地至当前已注册前的时期的因子数据作为训练集x,

本地至当前已注册前的时期的行情数据作为训练集y;

把当前注册的因子数据作为测试集xtest,

得出的测试结果作为买卖信号signal。

分别对300家股票的任意个因子数据和行情数据依照某个交易策略在不同时期都进行机器学习。

# -*- coding: utf-8 -*-from atrader import *import numpy as npimport pandas as pdfrom sklearn import svm#支持向量机from sklearn.linear_model import LogisticRegression ##逻辑回归from sklearn.ensemble import RandomForestClassifier ##随机森林from sklearn import preprocessingfactor=['PB','VOL5','VOL20']各类因子 = ["基础科目与衍生类","质量类","收益风险类","情绪类","成长类","常用技术指标类","动量类","价值类","每股指标类","模式识别类","行业、分析师类","特色技术指标类"]hs300 = pd.read_excel('G:\\泰迪杯\\\\A\\因子\\hs300.xlsx')def init(context: 'ContextBackReal'):set_backtest(initial_cash=100000000.0, stock_cost_fee=60)for i in factor:reg_factor([i]) ##因子注册reg_kdata('month', 1) ##频率passdef on_data(context: 'ContextBackReal'):data = get_reg_kdata(reg_idx=context.reg_kdata[0], length=1, fill_up=True, df=True)##获取已注册的行情数据factors=pd.DataFrame(data['target_idx'])##记录行情数据的标for i in range(len(factor)):factorrr=get_reg_factor(reg_idx=context.reg_factor[i], target_indices=[], length=1, df=True)['value']##获取注册因子中数据值列,最后作为测试集factors = pd.concat([factors,factorrr], axis=1)##每个因子因子按列合并factor_name = ['target_idx']##factor_name.extend(factor)factors.columns = factor_name ##因子列名命名factors = factors.dropna(axis=0, how='any', inplace=False) ##对因子缺失值进行删除factor_select_name = ['date']factor_select_name.extend(factor) ##这步是为对本地已获取因子挑选做准备signal=[]for i, j in hs300.iterrows():##对300家股票循环,一个一个股票的进行循环kdata = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\bar\\bar_%d_%s.xlsx' % (i, j['name'])))##获取本地单个股票整个时期的交易数据d0 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[0], 各类因子[0], i, j['name'])))d1 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[1], 各类因子[1], i, j['name']))).dropna(axis=1, how="all").drop(['date'], axis=1, inplace=False)d2 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[2], 各类因子[2], i, j['name']))).dropna(axis=1, how="all").drop(['date'], axis=1, inplace=False)d3 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[3], 各类因子[3], i, j['name']))).dropna(axis=1, how="all").drop(['date'], axis=1, inplace=False)d4 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[4], 各类因子[4], i, j['name']))).dropna(axis=1, how="all").drop(['date'], axis=1, inplace=False)d5 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[5], 各类因子[5], i, j['name']))).dropna(axis=1, how="all").drop(['date'], axis=1, inplace=False)d6 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[6], 各类因子[6], i, j['name']))).dropna(axis=1, how="all").drop(['date'], axis=1, inplace=False)d7 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[7], 各类因子[7], i, j['name']))).dropna(axis=1, how="all").drop(['date'], axis=1, inplace=False)d8 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[8], 各类因子[8], i, j['name']))).dropna(axis=1, how="all").drop(['date'], axis=1, inplace=False)d9 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[9], 各类因子[9], i, j['name']))).dropna(axis=1, how="all").drop(['date'], axis=1, inplace=False)d10 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[10], 各类因子[10], i, j['name']))).dropna(axis=1, how="all").drop(['date'], axis=1, inplace=False)d11 = pd.DataFrame(pd.read_excel('G:\\泰迪杯\\\\A\\因子\\%s\\%s_%d_%s.xlsx' % (各类因子[11], 各类因子[11], i, j['name']))).dropna(axis=1, how="all").drop(['date'], axis=1, inplace=False)合并 = pd.concat([d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11], axis=1)##本地各大类因子合并day_factor = str(data['time'][0])[0:str(data['time'][0]).find(" ")]###因子日期对应的格式转换day_kdata = str(data['time'][0]) ##行情数据日期对应的格式转换try:##这一步try的原因是,我们挑选出的因子有可能在本股票中数据为空factor_select=合并[factor_select_name] ###从本地因子数据中选取对应注册因子数据。最后作为训练集xexcept:print("某因子的数据不存在,某列因子整列丢失!")continueif factor_select.isnull().any().sum() > 0:print("因子存在缺失!")factor_select.fillna(factor_select.median()) ###这里缺失值,我用中位数代替# continue#print("\n当前回测时间为:",day_factor)try:##这一步try的原因是,当前股票已注册行情数据的日期在本地已获取的行情数据中可能并存在day_kdata0 = kdata[kdata['time'] == day_kdata].index.values[0] ##获取与注册行情数据日期相应的下标day_factor1 = factor_select[factor_select['date'] == day_factor].index.values[0] ##获取与注册行情数据日期相应的下标factor_last = factor_select.loc[0:day_factor1 - 2, :] ##连续获取至当前交易数据前2个交易日数据kdata_last = kdata.loc[1:day_kdata0 - 1, :] ##连续获取至当前行情交易数据前1个交易日数据except:print(j['name'], "所对应的因子和kdata日期不匹配!!!\n","因子所在日期为",day_factor)continueif len(factor_last['date']) != len(kdata_last['time']):print("因子与kdata的数据长度不一致")continue# 准备训练数据xx1 = factor_last.drop('date', 1)[1:].valuesx1 = x1.astype(np.float) ##数据类型转换min_max_scaler = preprocessing.MinMaxScaler() ##数据归一的一个函数x1 = min_max_scaler.fit_transform(x1) ##将数据归一到 [ 0,1 ] ##标准化# 准备测试数据xtestxtest = factors.drop('target_idx', 1).loc[i, :].values # 准备测试数据xtest,i 取本时期的单个股票的因子值xtest = xtest.reshape(1, -1).astype(np.float)xtest = min_max_scaler.fit_transform(xtest)###本来这里是多因子多策略的,现这里仅写一个简单的策略kdata_last0 = kdata.loc[1:day_kdata0 - 1, :]##这个取新的命名,方便加入其他策略dataclose = kdata_last0.closedataopen = kdata_last0.opendatahigh = kdata_last0.highdatalow = kdata_last0.lowdatavolume = kdata_last0.volumedataamount = kdata_last0.amountAjOBV=((dataclose - datalow) - (datahigh - dataclose)) /\(datahigh - datalow) * datavolume ##修正型OBV策略# 准备训练数据ysignalOBV = (2 * (AjOBV.diff() > 0) - 1)[1:]y1=signalOBV.tolist()##使用python机器学习的模块 ##这里可以使用自动调参的函数,遗传算法等等来调核函数,惩罚参数等等。。clf1 = svm.SVC(C=1.0, kernel='linear', decision_function_shape='ovr', probability=True) ##支持向量机clf2 = LogisticRegression(multi_class='multinomial', solver='saga') ##logistic。。clf3 = RandomForestClassifier(n_estimators=200) ##决策树。。clf1.fit(x1, y1)clf2.fit(x1, y1)clf3.fit(x1, y1)signal1 = clf1.predict(xtest)signal2 = clf2.predict(xtest)signal3 = clf3.predict(xtest)print('\n- 对当前股票为:---\t',j['name'],"\n-01-01至当前回测时期", day_factor) ###本地数据日期为-01-01---09-30的print('\t- 基于修正型 OBV 的判断信号 : \t')print('\t\t- 支持向量机 ','\t- 判断信号:', signal1)print('\t\t- 逻辑回归 ','\t- 判断信号:', signal2)print('\t\t- 随机森林 ','\t- 判断信号:', signal3,"\n")if signal1==1: ##1买入signal.append(i)else: ##0卖出order_target_volume(account_idx=0, target_idx=i, target_volume=0, side=1,order_type=2, price=0)for i in signal:order_target_value(account_idx=0, target_idx=i, side=1, price=0, order_type=2,target_value=10000000.0/len(signal))if __name__ == '__main__':data = get_code_list('hs300', date='-09-30')run_backtest(strategy_name='+'.join(factor),##策略名字file_path='.', # 策略文件路径,‘.’为本文件target_list=data['code'],frequency='month', # 策略刷新频率,仅支持以下频率:’min’,’day’,默认为’min’,必须小于k值注册频率fre_num=1, # 策略刷新频数,仅支持如下规则:’day’仅支持1,默认为1begin_date='-01-01', # 准备数据的开始日期end_date='-09-30',fq=0 # 复权常量,)

##data 获取已注册的行情数据前几行长这样:

##factors 注册因子合并后数据前几行长这样:

OBV策略,这里我参考书本‘量化投资以python为工具----蔡立耑 著’524页。

对当前股票基于OBV策略学习后的买卖信号判断:

到这里,策略就已经完成了,策略对不同股票在不同时期对不同因子都进行机器学习,效率很低,虽然基于这个修正型OBV策略也不是很乐观,但也算是一种摸索吧。。。。

如有不恰当之处,请指教!!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。