第二章:3 驗證趨勢交易策略是否有效


Posted by nightqwq on 2021-12-11

上一節,我們成功將策略進行打包並最佳化。

這一節,我們來驗證交易策略是否有效。


a. 策略驗證:Bootstrap Testing

現在我們的確找出了最優的趨勢交易策略,然而這樣的結果是否只是運氣好?我們要利用 Bootstrap Testing 這個方法來對此進行驗證。

這個方法是藉由跑出多種回測結果來測試該策略的信心水準,總共分三個步驟:

  1. 讓累積報酬率變成 0,去除策略的趨勢。

  2. 建構多種由不同雜訊構成的績效,讓這些績效的報酬率與我們策略的報酬率進行比對,如果比我們的策略高,代表該策略信心程度不足。

  3. 將這些雜訊策略做成一個績效分佈圖,並檢視我們策略會在分佈圖中的哪個位置。


b. 去除策略趨勢

現在我們就來執行第一步驟:

把策略儲存格的最後一行(叫出回測圖表的程式碼)存進 portfolio 這個變數裡面。

往下開新的儲存格,輸入以下程式碼獲取每日績效:

portfolio.daily_returns()

如圖可看到每日的績效。

在改良一下,把每日的績效加總起來並繪製成圖:

portfolio.daily_returns().iloc[:, 1].cumsum().plot()

由圖可以看到每日績效的加總有種隨著日子一天天過去逐漸上升的趨勢,這一步就是要去除這個趨勢,那麼如何去除?

其實很簡單,只要把每日績效的加總減去每日績效平均的加總,然後存進一個變數即可。

把上面的程式碼改成如下:

detrend = portfolio.daily_returns() - portfolio.daily_returns().mean()

到此第一步驟已完成。


c. 建立雜訊績效

接下來執行第二步驟:

把這個表格改成一整條時間序列:

detrend.unstack()

於上述程式碼後面接上「.values」,在用一個變數存起來,這就是我們的雜訊了:

samples = detrend.unstack().values

現在我們要利用這些雜訊建構出各種不同的績效。

開一個新的儲存格,導入 random 模組,利用 len 來查看每日績效有多少天,並從 sample 中隨機取出相同數目的雜訊,再將這些雜訊加總起來:

import random

ndays = len(portfolio.daily_returns())

sum(random.choices(samples, k = ndays))

因為這邊導入的是亂數模組,所以可以看到每次執行的數目都不相同。

再來於最後一行(有 sum 的那一行)上方建立一個空串列,在於空串列下方打造一個執行 1000 次的 for 迴圈,並把最後一行按 tab 鍵縮進:

import random

ndays = len(portfolio.daily_returns())

random_returns = []

for i in range(1000):

  sum(random.choices(samples, k = ndays))

再來把最後一行用上面的空串列包起來,並新增 append 變數,好讓程式每執行一次,跑出來的雜訊就會進入這個空串列中:

import random

ndays = len(portfolio.daily_returns())

random_returns = []

for i in range(1000):

  random_returns.append(sum(random.choices(samples, k = ndays)))

最後在最下方(別被迴圈包住)製作雜訊績效的分佈圖:

import random

ndays = len(portfolio.daily_returns())

random_returns = []

for i in range(1000):

  random_returns.append(sum(random.choices(samples, k = ndays)))

pd.Series(random_returns).hist()


d. 檢視策略位置

第二步已完成,開始執行第三步:

於下方開新的儲存格,輸入以下程式碼以排序所有 filters 的績效:

portfolio.final_value().sort_values()

因為排序過了,所以越往下報酬率越高。

於上述程式碼接上「.index[-1]」來找出最下面的 filters 並將其傳入變數中:

best_results = portfolio.final_value().sort_values().index[-1]

下一行程式碼有點難理解,簡而言之就是從上面的雜訊策略裡找出裡面所有的「最好策略績效」,也就是上述已經傳到變數裡面的 sma 和他的最佳參數配對,並將所有的最好績效加總起來:

portfolio.daily_returns()[best_result].sum()

其實現在就可以直接看出來,跑出來的最好績效總和是 4,而用雜訊做成的績效的數據不到 4,意味我們的策略其實並不是運氣,而是真正有效的策略。

但是為了嚴謹,還是將這份數據利用可視化的方式來與雜訊策略做比較,最後的程式碼看起來像這樣:

best_result = portfolio.final_value().sort_values().index[-1]

best_result_value = portfolio.daily_returns()[best_result].sum()

pd.Series(random_returns).hist()

import matplotlib.pyplot as plt

plt.vlines(best_result_value, 0, 50, color = 'red')

在上述程式碼中,我們把最好績效的總和傳進「best_result_value」這個變數裡面,然後在分佈圖下方導入 matplotlib,並利用 vlines 將最好績效的總和的位置放進雜訊策略裡,使其 y 軸為 0 ~ 50,長條圖為紅色。

下圖為最終結果:

可以看到,我們所製作的最佳策略跑出來的績效勝過用雜訊跑出來的績效,代表這個策略是實實在在有效的策略。


這一節,我們成功驗證交易策略是否有效。

下一節,我們來實作策略濾網。

完整版程式碼連結:https://colab.research.google.com/drive/10YT7z1lMX_oJ1X71G0fyRsKGEOJnrQYh?usp=sharing


#加密貨幣 #Python







Related Posts

hoisting(提升)

hoisting(提升)

30-Day LeetCoding Challenge 2020 April Week 3 || Leetcode 解題

30-Day LeetCoding Challenge 2020 April Week 3 || Leetcode 解題

[BE101]  PHP 與 MySQL  (前言)

[BE101] PHP 與 MySQL (前言)


Comments