天天看點

利用機器學習模型,建構量化擇時政策(附全流程代碼)

作者:散文随風想

零. 機器學習,淺嘗一下

人類發現規律一般采用的是歸納演繹法,對觀察到的大量現象進行歸納,在心中形成規律,然後再遇到類似的情況,就可以迅速做出預測和判斷,比如說“朝霞不出門,晚霞行千裡”、“瑞雪兆豐年”、“狗打噴嚏天要晴”,這都是老祖先歸納演繹法的結晶,可能不是每回都靈驗。

利用機器學習模型,建構量化擇時政策(附全流程代碼)

機器學習和人類的思考過程非常相似,把曆史資料輸入到模型當中,訓練出一個能完成特定任務的數學模型,等到有新的資料出現時,就把新資料輸入到訓練好的模型當中,這就會輸出一個預測的結果,特别地,機器學習在識别非線性規律方面,相較于人腦更有優勢。

具體結合咱這次的目标進行說明,咱這次的任務就是利用機器學習模型,預測滬深300指數第二天的漲跌情況,輸入的資料就是滬深300指數的開高低收行情資料,将這些資料輸入到支援向量機(Support Vector Machine,SVM)當中進行模型訓練,待SVM訓練好之後,輸入今天的行情資料,就能輸出對第二天行情的預判。

為什麼選擇SVM呢?因為咱這次使用的資料集是滬深300指數的日線行情資料,它自2005年上市以來,攏共才四千多個交易日,換句話說,也才四千多個樣本點,相對于幾百萬上千萬的“大資料”來說,這充其量才算一個“小樣本”,這無疑是一個非常适合SVM的應用場景。

因為在深度學習(一般需要大資料“投喂”)尚未全面興起時,SVM由于其較高的小樣本預測準确率,并且能夠解決非線性分類問題,屬于當時機器學習方法潮流圈中的扛把子。

SVM很能打,但本身并不是非常複雜,今兒個不摳數學細節,大白話講講SVM是什麼有什麼用,以免沒開始就把大夥兒勸退了。

利用機器學習模型,建構量化擇時政策(附全流程代碼)

SVM最初的設計是用來解決二分類問題,後來擴充到多分類問題,“預測滬深300指數漲跌”就屬于典型的二分類問題,“漲”是一個類别,“跌”就是另一個類别。

它通過尋找一個最大間隔超平面(上圖黑斜線)将兩類樣本線性區分開來,并且保證兩側樣本的最近邊緣點到這個平面的距離是最大的,由于最大間隔超平面僅取決于兩個類别的邊緣點,例如上圖中被紅線和藍線穿過的紅點和藍點,這些點就被稱為支援向量,這就是“支援向量機”名稱的由來。

但現實世界很奇妙,有線性可分的資料集,就有非線性可分的資料集,那遇到非線性可分的情況怎麼辦?

利用機器學習模型,建構量化擇時政策(附全流程代碼)

那也有辦法,SVM引入了核函數,可以将低維不可分的資料映射到高維線性可分,如上圖,二維不可分就映射到三維,常用的核函數有線性核、多項式核、高斯核(RBF核)和Sigmoid核。

利用機器學習模型,建構量化擇時政策(附全流程代碼)

但在現實當中,由于噪聲和極端樣本點的存在,資料集無論在低緯和高維都可能出現線性不可分的情況,于是乎,SVM當中引入了松弛變量的概念,允許了最大間隔超平面不用完美區分兩個類别,允許錯誤分類的存在,SVM通過懲罰系數C控制這些錯誤分類的容忍程度,C值越高分類準确率越高,但數值過高容易導緻過拟合,C值過低則會導緻準确率受損。

SVM唠完了,咱來說說一般機器學習模組化的流程,一般分為6步走,按照先後順序分别是收集資料、準備資料、選擇/建立模型、訓練模型、測試模型和調節參數。量化,沒有白走的路,每一步都算數,下文咱一步一步地走一遍~

利用機器學習模型,建構量化擇時政策(附全流程代碼)

一. 收集資料

巧婦難為無米之炊,第一步咱要擷取到最原始的模組化資料,對于指數的日線資料而言,有非常多的免費擷取管道,隻要能擷取到指數的日期(date)、開盤價(open)、最高價(high)、最低價(low)和收盤價(close)就可以了。

在此處以tushare為例,擷取滬深300指數自2005年4月8日上市以來的全部行情資料,它是一個免費、開源的python财經資料接口包,網址是:http://tushare.org/。

導入tushare包之後,使用它的get_k_data函數,就可以獲得滬深300指數的曆史K線資料,傳回的資料格式是dataframe,咱隻選取開高低收資料,并将日期(字元串格式)設定為索引。

import numpy as np
import pandas as pd
import talib
import warnings
warnings.filterwarnings('ignore')
import tushare as ts


data = ts.get_k_data(code='hs300', start='2005-04-08', end='2022-11-08', ktype='D')
data = data.set_index('date')
data = data[['open', 'high', 'low', 'close']]
print('樣本數目:%d' %data.shape[0])
print(data.head(10))
print(45*'-')
print(data.tail(10))           
利用機器學習模型,建構量化擇時政策(附全流程代碼)

二. 資料準備

有了原始資料之後,咱還要進一步進行加工和處理,主要工作是變量選擇、确認标簽和資料清洗。

變量選擇在量化投資當中叫“因子選擇”,就是用哪些因子(factor)進行選股擇時那些,在機器學習領域一般叫“特征選擇”,指定用哪些特征(feature)來作為算法模型的輸入。

在這裡咱用到因子分别是EMA值(ema)、價格波動率(stddev)、價格斜率(slope)、RSI值(rsi)和威廉名額值(wr),此處咱利用talib包絲滑地完成計算,它是一款量化圈馳名、彪悍強大的第三方技術分析名額計算包。

data['ema'] = talib.EMA(data['close'].values, timeperiod=20)
data['stddev']= talib.STDDEV(data['close'].values, timeperiod=20, nbdev=1)
data['slope'] = talib.LINEARREG_SLOPE(data['close'].values, timeperiod=5)
data['rsi'] = talib.RSI(data['close'].values, timeperiod = 14)
data['wr'] = talib.WILLR(data['high'].values, data['low'].values, data['close'].values, timeperiod=7)
data.tail(10)           
利用機器學習模型,建構量化擇時政策(附全流程代碼)

确認标簽呢,就是給這個樣本點打上類别标簽,由于咱是預測指數第二天的漲跌情況,于是,咱先計算出每個樣本第二天的漲幅(pct),如果第二天上漲,則設定标簽(rise)為1,反之為0。

由于指數資料一般異常情況不是很多,如果有空值,咱把空值删除就好了。

data['pct'] = data['close'].shift(-1) / data['close'] - 1.0
data['rise'] = data['pct'].apply(lambda x: 1 if x>0 else 0)
#删除缺失值
data = data.dropna()
data.tail(10)           
利用機器學習模型,建構量化擇時政策(附全流程代碼)

三. 選擇/建立模型

選擇/建立模型就是需要确定自己這次使用哪種機器學習模型,是支援向量機SVM呢,還是神經網絡NN呢,亦或是随機森林RF呢,或者其他的模型。

在之前已經說過了,咱是用SVM模型,原因和原理不再贅述,為了方(tou)便(lan)實作和建立模型,咱可以直接從Scikit-learn(簡稱sklearn)中導入,它是非常流行的Python免費機器學習庫 ,具有各種分類、回歸和聚類算法,一般配合numpy資料格式使用。

四. 訓練模型

在這裡,咱需要把整個資料集分拆為訓練集和測試集,因為除了訓練模型之外,咱還要留出一部分資料來驗證訓練出來模型的優劣。

一般來說,将完整資料集80%的樣本作為訓練集,剩餘20%的樣本作為測試集,要注意的是,這裡要将dataframe中的因子資料轉換成numpy的ndarray數組格式,因為這種資料類型更适配sklearn。

# 劃分訓練集和測試集
num_train = round(len(data)*0.8)
data_train = data.iloc[:num_train, :]
data_test = data.iloc[num_train:, :]
# 訓練集資料和标簽
X_train = data_train[['ema', 'stddev', 'slope', 'rsi', 'wr']].values
y_train = data_train['rise']
# 測試集資料和标簽
X_test = data_test[['ema', 'stddev', 'slope', 'rsi', 'wr']].values
y_test = data_test['rise']
print(X_train[:10])
print(45*'-')
print(X_test[:10])           
利用機器學習模型,建構量化擇時政策(附全流程代碼)

在劃分資料集之後,還有非常重要的一步,那就是對資料進行标準化處理,這是因為每個因子的數值量綱差别太大,例如指數EMA的均值是2919.6,而RSI的均值是52.7,這樣會造成SVM對某些因子的“偏心”。

在此處,采用“(原始值 - 均值) / 标準差”的方法對資料進行标準化處理,處理過後,每個因子的均值都會變為0,标準差變為1.0。

from sklearn.preprocessing import StandardScaler


print('---标準化之前---')
print('訓練集的均值:')
print(X_train.mean(axis=0))
print('訓練集的标準差:')
print(X_train.std(axis=0))


# 對資料進行标準化
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)


print('---标準化之後---')
print('訓練集的均值:')
print(X_train.mean(axis=0))
print('訓練集的标準差:')
print(X_train.std(axis=0))           
利用機器學習模型,建構量化擇時政策(附全流程代碼)

資料标準化處理之後,就可以将訓練集資料輸入SVM當中,代碼實作很簡單,從sklearn的svm子產品當中導入SVM分類器SVC,建立執行個體對象後,将訓練集因子資料和對應标簽塞進fit函數就行了,SVM模型的懲罰系數使用預設值1.0,核函數也用預設的RBF核函數,訓練過程非常快,不用一個東的時間,就把SVM分類器訓練好了。

from sklearn.svm import SVC


classifier = SVC(C=1.0, kernel='rbf')
classifier.fit(X_train, y_train)
print(classifier)           
利用機器學習模型,建構量化擇時政策(附全流程代碼)

五. 測試模型

至此,SVM分類器已經訓練好了,把因子資料塞進predict函數,就能輸出每個樣本的預測值,咱分别把訓練集和測試集的預測标簽插回到原來的資料集當中,用來計算預測的準确率。

y_train_pred = classifier.predict(X_train)
y_test_pred = classifier.predict(X_test)
data_train['pred'] = y_train_pred
data_test['pred'] = y_test_pred
accuracy_train = 100 * data_train[data_train.rise==data_train.pred].shape[0] / data_train.shape[0]
accuracy_test = 100 * data_test[data_test.rise==data_test.pred].shape[0] / data_test.shape[0]
print('訓練集預測準确率:%.2f%%' %accuracy_train)
print('測試集預測準确率:%.2f%%' %accuracy_test)           

輸出結果:

訓練集預測準确率:57.52%
測試集預測準确率:52.35%           

從結果當中看出,訓練集的預測準确率明顯比測試集的高,這是因為整個模型都是在訓練集資料上訓練出來的,對測試集資料則還很“陌生”,這就相當于聯考數學考卷都是你們學校的數學老師出的,整體來看,你們的平均分就非常可能比其他同級别的學校高。

光看準确率還不夠直覺,咱還要看一下如果純粹按照這個擇時模型的預測結果進行投資,能獲得多少收益,此處隻使用測試集進行模拟。

假設指數可以多空交易,如果模型預測為1(上漲),第二天政策的收益率就是指數的漲幅,如果模型預測為0(下跌),第二天政策的收益率就是指數的漲幅的相反數,有了每天的日收益率之後,通過dataframe自帶的累乘函數cumprod,就可以得到擇時政策和滬深300指數的淨值曲線,為了方(tou)便(lan)起見,不考慮交易費率,以及按照收盤價成交。

import matplotlib.pyplot as plt


#政策日收益率
data_test['strategy_pct'] = data_test.apply(lambda x: x.pct if x.pred>0 else -x.pct, axis=1)
#政策和滬深300的淨值
data_test['strategy'] = (1.0 + data_test['strategy_pct']).cumprod()
data_test['hs300'] = (1.0 + data_test['pct']).cumprod()
# 粗略計算年化收益率
annual_return = 100 * (pow(data_test['strategy'].iloc[-1], 250/data_test.shape[0]) - 1.0)
print('SVM 滬深300指數擇時政策的年化收益率:%.2f%%' %annual_return)


#将索引從字元串轉換為日期格式,友善展示
data_test.index = pd.to_datetime(data_test.index)
ax = data_test[['strategy','hs300']].plot(figsize=(16,9), color=['SteelBlue','Red'],
                                          title='SVM 滬深300指數擇時政策淨值  by 量化君')
plt.show()           
利用機器學習模型,建構量化擇時政策(附全流程代碼)

六. 調節參數

從上一步的測試當中看出,訓練集和測試集的預測準确率隻有57%和52%,不算理想,說明還有很大的提升空間,還可以對模型進行優化改進。

比如說,現在使用的5個因子,還沒有反應到價格波動的本質,還可以增改更多的因子。

還比如說,SVM模型當中的懲罰系數C過小,對錯誤樣本的容忍度過高,RBF核函數不适合作為這個資料集的映射轉換函數。

再比如說,甚至連SVM模型本身也是一個參數,也可以更改,比如說可以換成其他的機器學習分類模型。

也就是說到這調節參數這一步,如果訓練好的模型結果不能讓自己滿意,就可以重新将前5步走一遍。

繼續閱讀