機器學習量化應用:用迴歸策略預測價格

我們已經知道,監督學習主要就是分類和迴歸兩種方法。本文以支持向量機(support vector machine,SVM)來說明,如何採取機器學習中迴歸方法來預測股票價格。這在傳統量化中是根本不可能實現的,在機器學習領域卻能達到50%以上的勝率。

1、支持向量機

支持向量機
支持向量機是一種監督學習算法,可用於分類和迴歸問題,如支持分類的 SVC和支持迴歸的SVR。這是20世紀90年代被開發出來的,直到現在,都是高性能算法的首選,在機器學習領域有極爲廣泛的應用。

核心思想
算法的核心思想是尋找最能將特徵分離到不同域的超平面。它的理論根據就是,任何一個P維物體(空間)都可以被一個P-1 維的超平面分成兩部分,就像我們可以用刀(二維平面)將西瓜(三維物體)分成兩半。

術語概念
直接看圖吧,我們要圖中將紅藍點分開,應該怎麼辦吧呢。
在這裏插入圖片描述

決策邊界
如圖所示,紅點和藍點分別代表兩類樣本,二維空間中的超平面就是圖中的黑色直線。如果一條直線可以讓兩類樣本中的點到這條直線的最短距離取最大值,一般認爲這條直線就是最穩定的分界線,在機器學習中我們稱之爲“決策邊界”;
支持向量:而決定這條直線的點往往是由少數幾個支撐點決定的,這些點稱爲支持向量。就是如下圖中紅線和藍線穿過的點。而支持向量與決策邊界之間的距離就叫做邊距。

sklearn中如何使用
這裏我們使用的是SVR,直接從sklearn中引用SVR模塊就可以了

from sklearn import svm
sk_model =svm.SVR(kernel='linear')

這裏只有一個關鍵參數,就是核(kernel)

  • 線性核
  • 多項式核
  • 高斯核

算法預測的原理
1)如果用機器學習的語言表述,我們根據已知的“特徵”x1 和“標籤”y ,通過“訓練”得到一個反映兩者線性關係的模型。
2)如果這種關係在未來一段時間內能夠延續,那麼任意給出一個股票當前時刻的特徵因子x1,我們就可以“預測”該股票未來時刻的價格 𝑦̂ = 𝑤0 +𝑤1𝑥1。
3)根據已有的特徵和標籤訓練模型,使用新的特徵進行預測,兩者構成了監督學習最核心的兩個環節。

2、策略描述

標的選擇:滬深300指數
訓練數據:2011~2016年共7年的日線數據
預測數據:基於訓練出的模型,預測2017,2018,2019年每天的漲跌

數據描述
在這裏插入圖片描述
這個日線數據有以下的字段:
【ts_code】 股票或基金的代碼,上證股票SH結尾,深證股票以SZ結尾
【trade_date】 交易日期
【open】 開盤價
【high】 最高價
【low】 最低價
【close】 收盤價
【change】 漲跌幅,復權之後的真實漲跌幅,保證準確

策略實現描述

  1. 計算當日~前20日的滾動收盤價,作爲我們這裏的特徵,共21個特徵
  2. 採用SVM中的SVR線性迴歸模型來進行訓練
  3. 訓練好模型後就可以用來預測第二天的收盤價
  4. 通過將預測到的明日收盤價來和明日開盤價比較,就可以得到漲跌預測
  5. 然後我們根據預測結果計算策略收益,用圖形展示出來

3、代碼實現

代碼的基本實現步驟:

1.準備數據

index_data,features_train,labels_train= getStockData(“000300.SH”,20,‘20110101’,‘20161231’)

2.訓練模型

sk_model = trainModel(features_train,labels_train)

3.驗證測試集

index_test, features_test, labels_test = getStockData(“000300.SH”,20, ‘20170101’, ‘20171231’) predictData(sk_model,features_test,
labels_test,index_test)

下面是各個函數的具體實現
#數據獲取和處理

  def getStockData(ts_code,bar_num,start_date,end_date):
            #1.讀取數據
            index_data =  pd.read_csv(ts_code+'.csv',parse_dates=['trade_date'])   #parse_dates
            #選取字段
            index_data = index_data[['trade_date','close','open']]
            #按日期排序
            index_data.sort_values(by='trade_date', inplace=True)
            #設置日期索引
            index_data.set_index('trade_date', inplace=True)
            
            #2.特徵處理
            #這裏以當日收盤價和之前n天的收盤價作爲特徵
            for i in range(1,bar_num+1):
                index_data['close_'+str(i)] = index_data['close'].shift(i)            
            #去掉前面的空值
            index_data = index_data[bar_num:]
        
            #3.按日期截取
            index_data = index_data[(index_data.index>pd.to_datetime(start_date))&(index_data.index<pd.to_datetime(end_date))]
        
            #特徵數據
            features_data = index_data[[x for x in index_data.columns if 'close' in x]]
            #標籤數據
            # 迴歸問題的標籤就是預測的股價,所以下一天的收盤價就是前一天的標籤;
            labels_data = index_data['close'].shift(-1)  
             # 進行訓練的數據裏不能有nan值,因爲這一個值對整體影響可以忽略,可以刪除也可以填充,這裏採用的填充
            labels_data.fillna(method='ffill', inplace=True) 
        
            return  index_data,features_data,labels_data

模型訓練

def trainModel(features_train,label_train):
    #選擇模型
    sk_model =svm.SVR(kernel='linear')
    #訓練模型(執行大概需要幾分鐘時間)
    print("開始訓練=========>")
    sk_model.fit(features_train,label_train)
    print("<========= 訓練結束")
    return sk_model      

預測價格和計算收益

def predictData(sk_model,features_data,labels_data,base_data):
    #準備用列表方式構造新dataframe
    date_line = list(labels_data.index.strftime("%Y-%m-%d"))  # 日期序列 將timestamp轉換成string
    next_close = list(labels_data)                 #明日的收盤價
    current_close = list(features_data['close'])   #取今日的收盤價
    next_open = list(base_data['open'].shift(-1))  #取明天的開盤價
    
    #預測價格
    predict = sk_model.predict(features_data)

    #訓練結果評分
    # score = sk_model.score(predict, labels_data)
    # print('預測得分:%.4f'%score)

    # 預測的明日收盤價,轉換成list
    predict = list(predict)

    #構造新的dataframe
    index_data = pd.DataFrame({'date': date_line, 'next_close': next_close,'next_predict':predict,'close':current_close,'next_open':next_open})
    print(index_data.head())
    print(index_data.columns)

    #計算持倉
    index_data['position'] = np.where(index_data['next_predict']>index_data['next_open']*(1+0.002),1,0)   #這裏設置2/1000的滑點

    #模型收益計算和可視化
    index_data['PL'] = np.where(index_data['position']==1,(index_data['next_close']-index_data['next_open'])/index_data['next_open'],0)
    print(index_data.head())
    index_data['strategy'] = (index_data['PL'].shift(1) + 1).cumprod()
    index_data['baseline'] = (index_data['next_close'].pct_change() + 1).cumprod()
    index_data.dropna(inplace=True)
    print(index_data.head())

    # 繪製圖形
    plt.plot(index_data['strategy'])
    plt.plot(index_data['baseline'])
    plt.legend(loc='best')
    # plt.savefig('1.jpg')
    plt.show()

4、策略效果

我們用的2011~2016年數據訓練好的模型進行預測,下面看先一下對各個時期的預測結果。
1)對訓練數據(2011~2016年)的測試
在這裏插入圖片描述
說明:這結果好到爆有沒有,當然,這是訓練數據,再好都沒有意義的

2)對2017年數據測試
在這裏插入圖片描述
說明:這個效果也很不錯,雖然收益率跟直接持有差不多,但是夠平滑

3)對2018年數據測試
在這裏插入圖片描述
說明:這個效果就很明顯了,在大盤大幅下跌的情況下保持了正收益。

5、總結

總的來看,這個策略效果還是不錯的,但是要注意,只是這樣的策略是完全無法用於實戰的,本文只是展示了程序實現的邏輯和流程。
1)一方面,完全沒有考慮交易費用、滑點等損耗。
2)另一方面,單純用價格預測價格,特徵太單一了,可靠性不高。

擴展練習

  • 選取長度的特徵或不同的特徵組合
  • 不用線性核,採用多項式核或高斯核
  • 不用支持向量迴歸,改用其他的迴歸算法
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章