編輯部翻譯:mchoi
【系列1】用于算法交易的神經網絡基于多變量時間序列(點選标題閱讀)
本次推文中我們會考慮回歸預測問題,為它設計和檢驗一個新的損失函數,将收益轉化為一些波動和為了這些問題檢驗不同的度量标準。代碼在文末檢視。
回到收益預測
首先,讓我們記住如何從原來的時間序列上切換到收益上(或者是百分比變動/增減率)。如果我們想要預知這些回報,我們可以将我們所有次元轉換為收益(open、high、low、close、volume)——他們将是已經歸一化的資料和更恰當的做法——如果我們打算更好地預測收益,要以收益的形式進行投資。
def data2change(data): change = pd.DataFrame(data).pct_change()
change = change.replace([np.inf, -np.inf], np.nan)
change = change.fillna(0.).values.tolist() return changeopenp = data_original.ix[:, 'Open'].tolist()
highp = data_original.ix[:, 'High'].tolist()
lowp = data_original.ix[:, 'Low'].tolist()
closep = data_original.ix[:, 'Adj Close'].tolist()
volumep = data_original.ix[:, 'Volume'].tolist()openp = data2change(openp)
highp = data2change(highp)
lowp = data2change(lowp)
closep = data2change(closep)
volumep = data2change(volumep)
複制
讓我們按照通常的做法來定義神經網絡,并要求它最小化的損失函數,我們将選擇這些函數作為新的平均絕對誤差(MAE)。特别是考慮到在這種情況下,如果我們預測一個百分比,我們會更容易進行地記錄,例如,5%的平均誤差。
model = Sequential()
model.add(Convolution1D(input_shape = (WINDOW, EMB_SIZE),nb_filter=16,filter_length=4,border_mode='same'))
model.add(MaxPooling1D(2))
model.add(LeakyReLU())3.model.add(Convolution1D(nb_filter=32,filter_length=4,border_mode='same'))model.add(MaxPooling1D(2))
model.add(LeakyReLU())
model.add(Flatten())model.add(Dense(16))
model.add(LeakyReLU())model.add(Dense(1))
model.add(Activation('linear'))opt = Nadam(lr=0.002)reduce_lr = ReduceLROnPlateau(monitor='val_loss',factor=0.9, patience=25, min_lr=0.000001, verbose=1)checkpointer = ModelCheckpoint(filepath="lolkekr.hdf5",verbose=1, save_best_only=True)model.compile(optimizer=opt,loss='mae')history = model.fit(X_train, Y_train,nb_epoch = 100,batch_size = 128,verbose=1,validation_data=(X_test, Y_test),callbacks=[reduce_lr, checkpointer],shuffle=True)
複制
我們得到了以下的結果:
基于平均絕對誤差的神經網絡預測
根據不同的度量标準,我們得到了MAE:0.00013,MAE:0.0082,MAPE:144.4%
讓我們來看看更接近MAE的錯誤:
讓我們記住我們之前打算預測的是什麼——多大和在什麼方向會改變。現在我想請你們讀一小段關于貝葉斯的方法的内容:
假設股票的未來回報率非常的小,是0.01(或者1%)。我們有一個預測未來股票價格的模型,我們的收益與虧損是直接與預測有關的。我們應如何衡量與模型預測相關的損失以及随後的預測?一個平方誤差損失在标記上是不可知的,對于0.1的預測同樣是不利于0.03的預測。如果你根據模型的預測進行了下注,那麼您将以0.03的預測賺取收益,并以-0.01的預測輸掉資金,但我們的損失并沒有捕捉到這一點。我們需要更好的虧損,考慮到預測和真實的價值的迹象。
我們現在可以看到,我們目前的損失函數MAE不會給我們有關變更方向的資訊! 我們将盡力修複它。
回到自定義損失函數
在Keras中實作它:
def stock_loss(y_true, y_pred): alpha = 100. loss = K.switch(K.less(y_true * y_pred, 0),alpha*y_pred**2-K.sign(y_true)*y_pred +K.abs(y_true), \ K.abs(y_true - y_pred)) return K.mean(loss, axis=-1)
複制
在實作Keras的“困難”損失函數的時候,要考慮到想“if-else-less-equal”和其它的操作必須通過适當的後端來實作,例如,if-else語句塊在我的K.switch 的例子中實作()。
我們可以看到,如果我們正确地預測方向(信号),那就是同樣的平均絕對誤差(K.abs(y_true-y_pred)),但如果不是,對錯誤的信号我們會懲罰我們的虧損(alpha * y_pred **2-K.sign(y_true)* y_pred +K.abs(y_true))參數a被需要用來控制懲罰量。為了将這個損失函數應用到我們的模型中,我們需要用它(參數a)去簡單地編譯模型。
讓我們來檢驗結果!
基于平均絕對誤差的神經網絡預測
在度量方面,它稍微好一點:MSE:0.00013,MAE:0.0081和MAPE:132%,但在我們眼中這個圖像仍然不能滿足,該模型不能更好地預測波動的力量。這是一個損失函數的問題,檢查以前的文章的結果,它并不是很好,但也要看看預測的“大小”。
作為一個練習,嘗試使用相同的手段——對錯誤的信号進行懲罰(原文是penalyzing,但沒有這個單詞的感覺,我覺得是之前的penalize的ing形式)損失函數——但運用均方誤差(MSE),因為對于回歸問題來說這個損失函數是更健全的。
回到波動率
首先,我們都同意,對于這個金融事物來說,預測市場什麼時候将要“跳躍”是非常重要的。有時候,跳的方向是什麼這并不重要——例如,在許多年輕的市場,像加密數字貨币跳躍幾乎總是意味着增長,或者,例如經過大規模但緩慢的增長期的這個跳躍的預測最有可能意味着一些下降,這些下降将給我們一個信号。在某種意義上,我們感興趣的是預測未來價格的“可變性”。
這個數量的“變可變性”被稱為波動率(維基百科):
在金融中,波動率(符号σ)是通過對數回報的标準差來衡量的交易價格序列随時間的變化程度。
我們将使用在過去N天的價格回報标的準偏差,并且将嘗試預測第二天的情況。
volatility = []for i in range(WINDOW, len(data)):
window = highp[i-WINDOW:i]
volatility.append(np.std(window))
複制
“月度波動率”對GOOGL股票如下所示:
讓我們檢驗一下,我們如何預測這個數量!
波動率預測
for i in range(0, len(data_original), STEP): try:
o = openp[i:i+WINDOW]
h = highp[i:i+WINDOW]
l = lowp[i:i+WINDOW]
c = closep[i:i+WINDOW]
v = volumep[i:i+WINDOW]
volat = volatility[i:i+WINDOW]
y_i = volatility[i+WINDOW+FORECAST]
x_i = np.column_stack((volat, o, h, l, c, v))
複制
我們将采用與上述相同的神經網絡架構,改變損失函數MSE并重複預測波動的過程。 結果如下所示:
總體上看起來并不糟糕! 當然,有些跳躍預計太晚了,不過,捕獲依賴關系的能力是很好的! 在名額方面,MSE為2.5426229985e-05,MAE為0.0037,MAPE為38%。
也想鼓勵大家嘗試不同的損失函數,例如從下面這個。 例如,讓我們嘗試使用MSE日志:
def mse_log(y_true, y_pred): y_pred = K.clip(y_pred, epsilon, 1.0 - epsilon)
loss = K.square(K.log(y_true) - K.log(y_pred)) return K.mean(loss, axis=-1)model.compile(optimizer=opt, loss=mse_log)
複制
名額是MSE 2.52380132336e-05,MAE 0.0037和MAPE 37%。不是很多,但已經更好了! 您可以在存儲庫中實作的一些其他損失功能。
代碼展示: