練習版程式碼連結:https://colab.research.google.com/drive/1u_uLl79ZHgIxn_IlYTsLNMNorRm3KsXa?usp=sharing
(請參考第一章第一節來啟動該筆記本)
在這一節,我們將利用各種不同的 filters 來研發八種趨勢交易策略。
a. 什麼是趨勢交易
趨勢交易就是買進上漲趨勢的股票。買了以後就一直抱著,直到趨勢結束。
跟上一章的雙均線不同,趨勢交易並不會藉由均線走勢來判斷進出場,而是根據不同的指標來判斷一個趨勢的結束與開始,趨勢開始時買進,趨勢結束時賣出。
b. 單 filters 撰寫
請開啟本節開頭的筆記本來一起練習。
為了測試我們的 filters 對於價格變化有何反應,我們需建立一條簡單的時間序列:
import pandas as pd
s = pd.Series([0] * 200 + [1] * 300 + [0] * 200)
s.plot()
然後開始引入 filters:
from finlab_crypto import indicators
當你輸入「indicators??」時,會跳出這行程式碼的說明:
圖上顯示了八種不同的 filters,有空可以在裡面探索看看,我們先拿出一種 filters 來做策略撰寫:
trend = indicators.trends['sma'](s, 50)
s.plot()
trend.plot()
在上述程式碼中,我們從 indicators 裡叫出了 sma 這個 filters,然後把價格丟進去(時間序列 s),並設定 filters 為每 50 日一個平均,之後傳到 trend 這個變數裡面,最後把價格和預測趨勢都畫出來。
由上圖可以看到,價格趨勢的預測線段(黃色線)由於在一邊確認價格是否從 0 變成 1,一邊進行運算的緣故,並不會百分百貼著價格跑。
那我們來研究其他 filters,是否能夠讓預測價格更加貼近實際價格。
c. 多 filters 撰寫
我們利用 for 迴圈的方式,把 indicators 裡面所有 filters 的名稱和其對應的函式一併列印出來:(因為 indicators 是字典,取出裡面的元素需要加上 items):
for name, func in indicators.trends.items():
print(name, func)
接下來就要拿實際價格跟上面所有的 filters 做比較,看哪一條最接近實際價格。
其實做法與原本叫出 sma 的方法相似,先把 print 那行去掉,之後會像這樣:
s.plot()
for name, func in indicators.trends.items():
trend = func(s, 50)
trend.plot()
雖然很容易看出來,成九十度的藍色線段就是原本的價格,但是卻很難分辨到底哪條 filters 最貼近藍色線段,所以必須要改良這段程式碼。
首先在迴圈上方先建立一個 DataFrame,並把價格存進 DataFrame 裡面,然後再迴圈裡把預測價格存進 DataFrame 裡,並標註為 filters 的名稱。
直接畫出來,先顯示這個 DataFrame,程式碼看起來會像這樣:
filter_results = pd.DataFrame()
filter_results['original_price'] = s
for name, func in indicators.trends.items():
trend = func(s, 50)
filter_results[name] = trend
filter_results.plot()
我們可以看到,雖然「detrend」這條 filters 離原本價格最近,但同時突起比較大,導致有時候價格會失真。
所以究竟如何找到最適合的 filters 呢?我們來實際撰寫交易策略試試看。
d. 撰寫交易策略
先下載比特幣的歷史價格:
ohlcv = finlab_crypto.crawler.get_all_binance('BTCUSDT', '4h')
再來直接將第一章的策略複製過來:
close = ohlcv.close
sma20 = close.rolling(20).mean()
sma60 = close.rolling(60).mean()
entries = (sma20 > sma60) & (sma20.shift() < sma60.shift())
exits = (sma20 < sma60) & (sma20.shift() > sma60.shift())
close.plot()
sma20.plot()
sma60.plot()
entries.astype(int).plot(secondary_y=True)
(-exits.astype(int)).plot(secondary_y=True)
最後把雙均線改成趨勢交易,用言語說明有點難懂,請看下面的最終程式碼,會發現我們先是新增了一條filter ,再把兩條均線做修改,總共更動三個地方:
filter_name = 'wma'
close = ohlcv.close
sma20 = indicators.trends[filter_name](close, 20)
sma60 = indicators.trends[filter_name](close, 60)
entries = (sma20 > sma60) & (sma20.shift() < sma60.shift())
exits = (sma20 < sma60) & (sma20.shift() > sma60.shift())
close.plot()
sma20.plot()
sma60.plot()
entries.astype(int).plot(secondary_y=True)
(-exits.astype(int)).plot(secondary_y=True)
上述程式碼採用了 wma 這條 filters,我們可以對每條 filters 都這樣做,並一一打包成 strategy 且進行最佳化,然後各自比較,來看看哪一條的報酬率最高。
至此,我們學到了第二種交易策略。
下一節,我們來實際操作趨勢交易的策略打包及最佳化。