分享

使用SVM预测大盘涨跌的简单策略

 ddguo2001 2017-04-26

 本策略是为了验证SVM对于大盘涨跌的预测是否有效,相比于纯随机策略,是否有明显的提高。

SVM模型用06~14年的数据训练,16年1月~12月的数据用来回测,这样是为了避免因为在模型中投入了现阶段的数据导致的过拟合。

  • 第一次运算准确率为.66,不过个人认为这个准确率不一定能复现,所以做了Accuracy with sets这张图来看数据量和准确率的变化趋势。

  • Accuracy with sets这张图描述了准确率随着数据量提高的变化,可以看出准确率的变化趋势,以及准确率的变化范围。可以重复生成这张图,以便了解最低测试准确率为多少。

  • 克隆notebook后,通过更改最后一段数据中第48行的 代码
    if predict_up and not cost:
    将predict_up去掉,改为:
    if not cost:
    就可以生成出不使用我们的SVM模型,纯粹的随机策略的图了。用以比较该模型和纯随机策略的相比,是否有显著的提高。

从结果来看,在16年的小范围下跌中,该模型表现还凑合吧……

[python] view plain copy
在CODE上查看代码片派生到我的代码片
  1. import numpy as np  
  2. import pandas as pd  
  3. from CAL.PyCAL import Date  
  4. from CAL.PyCAL import Calendar  
  5. from CAL.PyCAL import BizDayConvention  
  6. from sklearn import svm  
  7. start = '2014-01-01'                       # 回测起始时间  
  8. end = '2016-12-01'                         # 回测结束时间  
  9. benchmark = 'HS300'                        # 策略参考标准  
  10. universe = set_universe('HS300')  # 证券池,支持股票和基金  
  11. capital_base = 100000                      # 起始资金  
  12. freq = 'd'                                 # 策略类型,'d'表示日间策略使用日dw线回测,'m'表示日内策略使用分钟线回测  
  13. re  

处理数据

[python] view plain copy
在CODE上查看代码片派生到我的代码片
  1. fields = ['tradeDate','closeIndex', 'highestIndex','lowestIndex', 'turnoverVol','CHG','CHGPct']  
  2. 2  
  3. stock = '000300'  
  4. 3  
  5. #tradeDate是交易日、closeIndex是收盘指数、highestIndex是当日最大指数,lowestIndex是当日最小指数,CHG是涨跌  
  6. 4  
  7. index_raw = DataAPI.MktIdxdGet(ticker=stock,beginDate=u"2006-03-01",endDate=u"2015-03-01",field=fields,pandas="1")  
  8. 5  
  9. #获取2006年3月1日到2015年3月1日,上一行代码设定的所有索引的相关信息。  
  10. 6  
  11.   
  12. 7  
  13. index_date = index_raw.set_index('tradeDate')  
  14. 8  
  15. index_date = index_date.dropna()  
  16. 9  
  17. index_date['max_difference'] = index_date['highestIndex'] - index_date['lowestIndex']  
  18. 10  
  19.   
  20. 11  
  21. index_date['max_of_30day'] = None  
  22. 12  
  23. index_date['min_of_30day'] = None  
  24. 13  
  25. index_date['max_difference_of_30day'] = None  
  26. 14  
  27. index_date['closeIndex_after30days'] = None  
  28. 15  
  29. #预设需要处理的值为None,方便之后直接用dropna函数去掉无效数据  
  30. 16  
  31.   
  32. 17  
  33. for i in xrange(len(index_date)-30):  
  34. 18  
  35.     #对数据进行处理  
  36. 19  
  37.     index_date['max_of_30day'][i+30] = max(index_date['highestIndex'][i:i+30])  
  38. 20  
  39.     #找出前30天最大值。  
  40. 21  
  41.     index_date['min_of_30day'][i+30] = min(index_date['lowestIndex'][i:i+30])  
  42. 22  
  43.     #找出前30天最小值  
  44. 23  
  45.     index_date['max_difference_of_30day'][i+30] = max(index_date['max_difference'][i:i+30])  
  46. 24  
  47.     #找出前30天最大日波动  
  48. 25  
  49.     index_date['closeIndex_after30days'][i]=index_date['closeIndex'][i+30]  
  50. 26  
  51.     #找出30天后的收盘价。  
  52. 27  
  53.   
  54. 28  
  55. index_date = index_date.dropna()   #去掉前30个和后30个无效的数据。  
  56. 29  
  57. lables_raw = index_date['closeIndex_after30days'] #提取出需要预测的数据  
  58. 30  
  59. lables = index_date['closeIndex_after30days'] > index_date['closeIndex'] #为分类处理数据,判断30天后的收盘价是否大于今日收盘价  
  60. 31  
  61. lables_ud = lables.replace({True:'up',False:'down'}) #方便他人阅读,将True和False改为up和down,意味着30天后收盘价涨了还是跌了  
  62. 32  
  63. features = index_date.drop(['closeIndex_after30days'],axis = 1) #在特征值中去掉我们要预测的数据。  

在未调参之前,我们先获取一次准确率:

[python] view plain copy
在CODE上查看代码片派生到我的代码片
  1. from sklearn import cross_validation  
  2. from sklearn import preprocessing  
  3. scaler = preprocessing.StandardScaler().fit(features)  
  4. features_scaler = scaler.transform(features)  
  5. #上面两行代码用来标准化数据  
  6.   
  7. X_train,X_test, y_train, y_test = cross_validation.train_test_split(features_scaler, lables, test_size = 0.2, random_state = 0)  
  8.   
  9. clf_svm = svm.SVC()   #使用SVM分类器来判断涨跌  
  10. clf_svm.fit(X_train, y_train)  
  11. print "预测准确率为:%0.2f" % (clf_svm.score(X_test, y_test))  

然后调C值,这里我是先让C在1~100的range跑,然后100~200……到300~400的时候发现不会进一步提高了。其实可以直接从1~1000跑一次,很快就能绘画出整个变动的图,然而我电脑渣带不动。

[python] view plain copy
在CODE上查看代码片派生到我的代码片
  1. i_list = []  
  2. score_list = []  
  3. for i in range(300,400,1):  
  4.     i=i/1.  
  5.     clf_svm = svm.SVC(C = i)   #使用SVM分类器来判断涨跌  
  6.     clf_svm.fit(X_train, y_train)  
  7.     i_list.append(i)  
  8.     score_list.append(clf_svm.score(X_test, y_test))  
  9.   
  10. score_list_df =  pd.DataFrame({'i_list':i_list,'score_list':score_list})  
  11. score_list_df.plot(x='i_list' ,y='score_list',title='score change with c')  

然后是gamma值,和C值调参上也是同理。

[python] view plain copy
在CODE上查看代码片派生到我的代码片
  1. i_list = []  
  2. score_list = []  
  3. for i in range(100,200,1):  
  4.     i=i/100.  
  5.     clf_svm = svm.SVC(C=350 ,  gamma = i)   #使用SVM分类器来判断涨跌  
  6.     clf_svm.fit(X_train, y_train)  
  7.     i_list.append(i)  
  8.     score_list.append(clf_svm.score(X_test, y_test))  
  9.   
  10. score_list_df =  pd.DataFrame({'gamma_list':i_list,'score_list':score_list})  
  11. score_list_df.plot(x='gamma_list' ,y='score_list',title='score change with gamma')  


虽说没什么卵用……还是假吧意思的比对一下不同核函数下的准确率吧。理所当然的是默认的高斯核表现最好。

[python] view plain copy
在CODE上查看代码片派生到我的代码片
  1. i_list = []  
  2. score_list = []  
  3.   
  4. kernels  =  ['linear', 'rbf','sigmoid']  
  5. for i in kernels :  
  6.     clf_svm = svm.SVC(C=350 , gamma = 1.8 , kernel = i )     
  7.     clf_svm.fit(X_train, y_train)  
  8.     i_list.append(i)  
  9.     score_list.append(clf_svm.score(X_test, y_test))  
  10.   
  11. score_list_df =  pd.DataFrame({'kernels':i_list,'score_list':score_list})  
  12. score_list_df.plot(x='kernels' ,y='score_list',title='score change with kernels',kind='bar')  


知道了大致参数最优范围以后,我们使用grisearchCV在这个范围内找到最优解。

[python] view plain copy
在CODE上查看代码片派生到我的代码片
  1. from sklearn.grid_search import GridSearchCV  
  2. from sklearn.cross_validation import ShuffleSplit  
  3. i = range(100,200,1)  
  4. params = {'C':range(300,400,1),'gamma':[x /100. for x in range(100,200,1)]}  
  5.   
  6. # X_train,X_test, y_train, y_test = cross_validation.train_test_split(features_scaler, lables, test_size = 0.2, random_state = 0)  
  7.   
  8. clf_svm = svm.SVC()  
  9. # cv_sets = ShuffleSplit(X_train.shape[0], n_iter = 10, test_size = 0.20, random_state = 0)  
  10.   
  11. grid = GridSearchCV(clf_svm, params )  
  12. grid = grid.fit(X_train, y_train)  
  13. print grid.best_estimator_  

然后在最优解的基础上再次计算一次准确率

[python] view plain copy
在CODE上查看代码片派生到我的代码片
  1. from sklearn import cross_validation  
  2. from sklearn import preprocessing  
  3. scaler = preprocessing.StandardScaler().fit(features)  
  4. features_scaler = scaler.transform(features)  
  5. #上面两行代码用来标准化数据  
  6.   
  7. X_train,X_test, y_train, y_test = cross_validation.train_test_split(features_scaler, lables, test_size = 0.2, random_state = 0)  
  8.   
  9. clf_svm = svm.SVC(C = 300,gamma = 1.03)   #使用SVM分类器来判断涨跌  
  10. clf_svm.fit(X_train, y_train)  
  11. print "预测准确率为:%0.2f" % (clf_svm.score(X_test, y_test))  

为了判断模型是否稳健,我们让训练集合处于变化中,然后观察随着训练集合的变化,准确率的波动范围图。这里采取的是1000~2500数据每10个变化一次。

发现最低没有低于过0.72的准确率,波动较大在0.14左右,模型稳健度一般。

[python] view plain copy
在CODE上查看代码片派生到我的代码片
  1. num_list = []  
  2. score_list = []  
  3. for i in xrange((len(features_scaler)-1000)/10):  
  4.     num_now = len(features_scaler)%10 + 10*i +1000  
  5.     X_train,X_test, y_train, y_test = cross_validation.train_test_split(features_scaler[:num_now], lables[:num_now], test_size = 0.2, random_state = 0)  
  6.     clf_svm = svm.SVC(C=350,gamma = 1.8)   #使用SVM分类器来判断涨跌  
  7.     clf_svm.fit(X_train, y_train)  
  8.     num_list.append(num_now)  
  9.     score_list.append(clf_svm.score(X_test, y_test))  
  10.       
  11. score_list_df =  pd.DataFrame({'sets_num':num_list,'accuracy':score_list})  
  12. score_list_df.plot(x='sets_num' ,y='accuracy',title='Accuracy with sets')  


接下来是比对用的空白组,纯随机策略(不控制风险,只是随机买,1.20倍卖出)

[python] view plain copy
在CODE上查看代码片派生到我的代码片
  1. import random  
  2. start = '2016-01-01'                       # 回测起始时间  
  3. end = '2016-12-01'                         # 回测结束时间  
  4. benchmark = 'HS300'                        # 策略参考标准  
  5. universe = set_universe('HS300')  # 证券池,支持股票和基金  
  6. capital_base = 100000                      # 起始资金  
  7. freq = 'd'                                 # 策略类型,'d'表示日间策略使用日线回测,'m'表示日内策略使用分钟线回测  
  8. refresh_rate = 1                           # 调仓频率,表示执行handle_data的时间间隔,若freq = 'd'时间间隔的单位为交易日,若freq = 'm'时间间隔为分钟  
  9.   
  10. def initialize(account):                   # 初始化虚拟账户状态  
  11.     pass  
  12.   
  13. features_list = []  
  14. def handle_data(account):  
  15.     random.shuffle(account.universe)       # 随机化股票池一遍随机策略  
  16.     for stock in account.universe:         # 股票是股票池中的股票,并且优矿帮你自动剔除了当天停牌退市的股票  
  17.         p = account.reference_price[stock]        # 股票前一天的收盘价  
  18.         cost = account.security_cost.get(stock)  # 股票的平均持仓成本  
  19.         if not cost:                           # 判断当前没有买入该股票  
  20.             order_pct_to(stock, 0.10)          # 将满足条件的股票买入,总价值占虚拟帐户的10%  
  21.         elif cost and p >= cost * 1.20:        # 卖出条件,当p这个价格涨幅到买入价的1.20倍;  
  22.             order_to(stock, 0)        # 将满足条件的股票卖到剩余0股,即全部卖出  


然后是纯随机策略基础上,只增加一个预测盘指的涨跌,如果预测涨,则随机买入,否则不买。和纯随机策略比,的确好了一丢丢。

[python] view plain copy
在CODE上查看代码片派生到我的代码片
  1. import random  
  2. 2  
  3. start = '2016-01-01'                       # 回测起始时间  
  4. 3  
  5. end = '2016-12-15'                         # 回测结束时间  
  6. 4  
  7. benchmark = 'HS300'                        # 策略参考标准  
  8. 5  
  9. universe = set_universe('HS300')  # 证券池,支持股票和基金  
  10. 6  
  11. capital_base = 100000                      # 起始资金  
  12. 7  
  13. freq = 'd'                                 # 策略类型,'d'表示日间策略使用日线回测,'m'表示日内策略使用分钟线回测  
  14. 8  
  15. refresh_rate = 1                           # 调仓频率,表示执行handle_data的时间间隔,若freq = 'd'时间间隔的单位为交易日,若freq = 'm'时间间隔为分钟  
  16. 9  
  17. stock = '000300' #预测的指数,沪深300指数。和策略参考池一致。  
  18. 10  
  19. fields = ['tradeDate','closeIndex', 'highestIndex','lowestIndex', 'turnoverVol','CHG','CHGPct']   
  20. 11  
  21. #tradeDate是交易日、closeIndex是收盘指数、highestIndex是当日最大指数,lowestIndex是当日最小指数,CHG是涨跌  
  22. 12  
  23.   
  24. 13  
  25. def initialize(account):                   # 初始化虚拟账户状态  
  26. 14  
  27.     pass  
  28. 15  
  29.   
  30. 16  
  31. features_list = []  
  32. 17  
  33. def handle_data(account):  
  34. 18  
  35.     # 生成买入列表  
  36. 19  
  37.     last_date = account.previous_date.strftime("%Y-%m-%d") #获取上一个交易日日期并格式化  
  38. 20  
  39.     begin_date = pd.date_range(end=last_date,periods=60)[0] #获取60日之前的交易日日期  
  40. 21  
  41.     begin_date = begin_date.strftime("%Y-%m-%d") #格式化这个日期  
  42. 22  
  43.     to_class = DataAPI.MktIdxdGet(ticker='000300',beginDate=begin_date,endDate=last_date,field=fields,pandas="1")  
  44. 23  
  45.     to_class = to_class.dropna()  
  46. 24  
  47.     to_class = to_class[-30:] #获取我们要的30天的指数信息  
  48. 25  
  49.     to_class_date = to_class.set_index('tradeDate')  
  50. 26  
  51.     to_class_date['max_difference'] = to_class_date['highestIndex'] - to_class_date['lowestIndex']  
  52. 27  
  53.       
  54. 28  
  55.     to_class_date_max_of_30day = max(to_class_date['highestIndex'])  
  56. 29  
  57.     #找出前30天最大值。  
  58. 30  
  59.     to_class_date_min_of_30day = min(to_class_date['lowestIndex'])  
  60. 31  
  61.     #找出前30天最小值  
  62. 32  
  63.     to_class_date_max_difference_of_30day = max(to_class_date['max_difference'])  
  64. 33  
  65.     #找出前30天最大日波动  
  66. 34  
  67.       
  68. 35  
  69.     features_for_predict = to_class_date[-1:]  
  70. 36  
  71.     features_for_predict['max_of_30day'] = to_class_date_max_of_30day  
  72. 37  
  73.     features_for_predict['min_of_30day'] = to_class_date_min_of_30day  
  74. 38  
  75.     features_for_predict['max_difference_of_30day'] = to_class_date_max_difference_of_30day  
  76. 39  
  77.       
  78. 40  
  79.     features_fp_scaler = scaler.transform(features_for_predict)  
  80. 41  
  81.     predict_up = clf_svm.predict(features_fp_scaler)  
  82. 42  
  83.   
  84. 43  
  85.     #预测30天后的收盘是涨还是跌。  
  86. 44  
  87.     random.shuffle(account.universe)  
  88. 45  
  89.     for stock in account.universe:         # 股票是股票池中的股票,并且优矿帮你自动剔除了当天停牌退市的股票  
  90. 46  
  91.         p = account.reference_price[stock]        # 股票前一天的收盘价  
  92. 47  
  93.         cost = account.security_cost.get(stock)  # 股票的平均持仓成本  
  94. 48  
  95.         if predict_up and not cost:                        # 判断当前没有买入该股票  
  96. 49  
  97.             order_pct_to(stock, 0.10)          # 将满足条件的股票买入,总价值占虚拟帐户的10%  
  98. 50  
  99.         elif cost and p >= cost * 1.20:        # 卖出条件,当p这个价格涨幅到买入价的1.20倍;  
  100. 51  
  101.             order_to(stock, 0)        # 将满足条件的股票卖到剩余0股,即全部卖出  


更多实盘源码请点击链接

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多