SamSuka
阿程量化交易
阿程量化交易

patreon


【關於日內數據(Intraday Data)你不知道的二三事】

之前的分析和策略都是基於日間數據(Daily data),今次筆者會分享回測基於日內數據(Intraday data)的策略的中伏位

(程式交易編程系列 2)

(因為放假原因遲左少少出3月的最後一帖)

甚麼是日內數據?

日間數據(Daily data)和日內數據(Intraday data)是根據時間範圍的不同而有所區別。

- 日間數據是以一個交易日為單位的數據,包括開盤價、最高價、最低價、收盤價以及交易量等,通常用於分析長期市場趨勢。

- 日內數據是在一個交易日內所記錄的數據,通常以固定時間間隔(如每分鐘、每五分鐘、每十分鐘等)記錄市場數據,通常用於分析短期價格變動和交易活動,用於日內交易、技術分析和高頻交易等。

很多時,同一個策略可以適用於日間數據和日內數據,例如超簡單的移動平均線交叉策略,策略思路是使用移動平均線的交叉點來判斷買入和賣出信號。

例如用S&P500 期貨日間數據去回測時的步驟是:

1. 計算移動平均線:例如使用過去5天的收盤價計算5天平均線(SMA5),並使用過去20天的收盤價計算20天平均線(SMA20)

2. 當 SMA5 大於 SMA20 時,在收市買入S&P500 期貨

3. 當 SMA5 小於 SMA20 時,在收市賣出S&P500 期貨

4. 之後,你就可以回測不同短期和長期移動平均線的組合(例如短期5+長期20,短期10+長期90),找出這些組合的回報(例如複合年回報,夏普率,最大回撤),從而找出最佳回報的組合。

當你用S&P500 期貨日內數據(時間間隔為如每分鐘)去回測的步驟是:

1. 計算移動平均線:例如使用過去10分鐘的收盤價計算10分鐘平均線(SMA10),並使用過去40分鐘的收盤價計算40分鐘平均線(SMA40)

2. 當 SMA10 大於 SMA40 時,在收市買入S&P500 期貨

3. 當 SMA10 小於 SMA40 時,在收市賣出S&P500 期貨

4. 同樣地,你可以回測不同短期和長期移動平均線的組合(例如短期10分鐘+長期40分鐘,短期20分鐘+長期120分鐘),找出這些組合的回報(例如複合年回報,夏普率,最大回撤),從而找出最佳回報的組合。

你可能會覺得:「日內數據和日間數據只是時間間隔不同,分析和做回測的技巧也是一樣,沒有甚麼特別。」 但當你做回測的時候,就有機會中了陷阱也不知道!


用日內數據做回測的中伏位:日內數據有缺失資料的問題(Missing Data)

日間數據是以一個交易日為單位,交易日內一定有交易(除非是一些非常非常不流動的交易工具),所以每一個交易日一定會有一行交易數據在日間數據中。

但日內數據卻不同,舉例我們想用時間間隔是如每分鐘的日內數據做回測,但在交易日內不是每分鐘都一定有交易,那麼這一分鐘內的交易量(Volume)就是0,有些交易數據提供者所提供的日內數據可能會直接skip了那一分鐘的數據,例如以下的日內數據會直接skip了 2009-12-14 23:53:00 那一分鐘的數據


如果日內數據skip了零交易量的數據,依賴時間去計算的指標就會計算錯誤

以下是 S&P500 期貨的日內數據,時間間隔是每分鐘,假設策略需要用到收盤價的5分鐘移動平均線,那麼用Excel或Python回測時, 2009-12-14 00:01:00 的 5分鐘移動平均線的數值

= (958.25 + 958.50 + 958.25 + 958.25 + 958.00) / 5

= 4791.25 / 5

= 958.25

我們看看數日前同一時段的日內數據,用Excel或Python回測時,2009-12-11 00:01:00 的 5分鐘移動平均線的數值

= (949.25 + 949.25 + 949.00 + 949.25 + 949.25) / 5

= 4746.00 / 5

= 949.20

大家應該發現到問題所在:

計算 2009-12-11 00:01:00 的 5分鐘平均收盤價應該用 2009-12-10 23:57:002009-12-11 00:01:00 這 5 分鐘收盤價的平均數值,由於 23:58 和 23:59 沒有交易,所以這兩分鐘的收盤價等於 23:57 的收盤價(即是949.00)

所以,2009-12-11 00:01:00 的 真正 5 分鐘移動平均線的數值

= (949.25 + 949.25 +  949.00 + 949.00 + 949.00) / 5

= 4745.50 / 5

= 949.10

當你有不少的技術指標計算有問題時,會影響很多買入賣出的指標,你就會得到一個錯誤的回測結果。試想像如果在做pairs trading / stat arb 的回測中,兩個或多個以上產品要做spread 的計算而忘記了修復以上問題,那就可能導致了look ahead 的問題,影響可大可小。


用 Python 去填補缺失的資料(Fill missing data)

第一步:讀取E-mini S&P 500期貨合約的日內數據,時間間隔為每分鐘

第二步:用Python DataFrame 的 .describe() function去找關於DataFrame中每個數值列的統計摘要

透過.describe()我們可以觀察到:

1. 日內數據的日期是由 2008-01-02 到 2023-05-05,而且有5.3百萬行(row)交易數據

2. 每行交易數據最低交易量是1,即是沒有交易量是0的交易數據

3. 時間間隔呢?.describe() 看不到時間間隔,在第一步的圖片可以看到首5行和尾5行交易數據的時間間隔是一分鐘,但我們不知道這5.3百萬行交易數據時間間隔是否都是一分鐘,這需要交給第三步去做

第三步:為每一行交易數據去尋找和上一行數據的時間差,以及和下一行數據的時間差。

1. 製造一個叫"last_datetime" 的新column:將datetime 的 column 用 .shift(1) 去把整個column shift去下一行。當datetime 是2008-01-02 06:02:00, last_datetime 就會是00-01-02 06:01:00

2. 製造一個叫"datetime_diff_from_lst" 的新column:將datetime 的 column 減去 last_datetime 的 column,這就是今行交易數據和上一行交易數據的時間差

3. 用同樣的方法,去找下一行交易數據的時間(next_datetime column)以及下一行交易數據今行交易數據的時間差(datetime_diff_to_next column)

第四步:用Python DataFrame 的 .value_counts() 去找最頻繁出現的時間差

透過.value_counts()我們可以觀察到:

1. 日內數據最頻繁出現的時間差是一分鐘(接近99%)

2. 總共有有74個時間差(雖然有些時間差出現極少)

3. 第二名和第三名分別是 2 分鐘和 3 分鐘,都是有些時候交易量=0所造成

4. 第四名是16分鐘?!為何不是 4 分鐘?我們繼續再看多一步!

5. 我們將 .value_counts() 的結果再把時間差去排列次序,時間差由1分鐘到14分鐘出現次數是愈來愈少的。但 15分鐘和 16分鐘出現的次數不尋常地高!

第五步:Sample Check 時間差是 2分鐘、3分鐘、15分鐘、16分鐘的交易數據

1. 時間差是 2分鐘

我們可以觀察到:

- 出現時間差是 2分鐘附近的數據都是交易量比較少


2. 時間差是 3分鐘

我們可以觀察到:

- 出現時間差是 3分鐘附近的數據都是交易量比較少


3. 時間差是 15分鐘

我們可以觀察到:

- 出現時間差是 15分鐘附近的數據都是交易量比較多

- 在所有sample 都是 16:16 至 16:30 沒有交易數據,很大機會是常規的停止交易時間

- 在16:15的交易量比較少

4. 時間差是 16分鐘

我們可以觀察到:

- 出現時間差是 16分鐘附近的數據都是交易量比較多

- 在所有sample 都是 16:15 至 16:30 沒有交易數據,很大機會是常規的停止交易時間

- 在16:14的交易量比較多

小結:時間差是 2分鐘、3分鐘的交易數據極大機會因為沒有交易量;而時間差是15分鐘、16分鐘的交易數據很大機會是因為16:15 至 16:30 是常規的停止交易時間。

第六步:填補缺失的資料(Fill missing data)

接住下來,我們會用Python去填補交易量是0的資料,但我們不會填補停止交易時間的資料,由於接近所有missing data都是時間差介乎 2分鐘至14分鐘之間,所以我們只會填補這些資料。

步驟如下:

(不會詳細解釋code,如果有很多朋友反映想要,我再另外寫一篇去詳解)

1. 在日內數據時間範圍內,製造一個DataFrame包含所有每分鐘的時間點

2. 把原本的日內數據的 DataFrame OUTER JOIN 包含所有每分鐘的時間點的 DataFrame

3. 用.ffill() 把 datetime_diff_to_next Forward Fill 以及把收盤價Forward Fill

4. 排除時間差大於14分鐘的新data(因我們不會填補停止交易時間的資料)

5. 把填補數據的交易量 set 做0

6. 把填補數據的Open, High, Low 都 set 做等於Close 的價格(因為這一分鐘內沒有交易量)

7. 填補完數據,就把時間差再計算一次

8. 最後再用 .value_counts() 去找最頻繁出現的時間差,就看到已經處理好絕大部分0交易量的Missing data


總結

1. 日內數據是在一個交易日內所記錄的數據,通常以固定時間間隔(如每分鐘、每五分鐘、每十分鐘等)記錄市場數據

2. 用日內數據做回測的中伏位是:日內數據有機會沒有記錄零交易量的數據

3. 如果日內數據skip了零交易量的數據,依賴時間去計算的指標就會計算錯誤(例如simple moving average)

4. 之後,我們用 Python 去分析日內數據中的時間差,我們發現接近所有交易量是零的 missing data 都是時間差介乎2分鐘至14分鐘之間,所以我們只會填補這些資料。另外一些時間差(例如15,16分鐘)很大機會是常規的停止交易時間

5. 最後用 Python 去填補缺失的資料(Fill missing data),之後我們就可以用這些data去回測日內交易的策略


(連結連埋 code + part of the data)

----------------------------------------------------------------------------------------------------------------

阿程量化交易 -> 1個月至少4篇精華文章

----------------------------------------------------------------------------------------------------------------

【公開量化策略系列】

策略 1 (Sharpe Ratio 1.4):

https://www.patreon.com/posts/gong-kai-liang-1-98710085

策略 2 (Sharpe Ratio 1.84):

https://www.patreon.com/posts/zhen-wen-fa-1-ce-100421185

策略 3 (Sharpe Ratio 1.34) - Long+Short 美期:

https://www.patreon.com/posts/gong-kai-liang-3-101097951

----------------------------------------------------------------------------------------------------------------

【程式交易編程系列】

1. 真正深入回測恆指每月第一個交易日/最後交易日規律:

https://www.patreon.com/posts/zhen-zheng-shen-99709770

----------------------------------------------------------------------------------------------------------------

【行內秘聞】

1. 量化基金如何保護他們的交易策略:

https://www.patreon.com/posts/liang-hua-ji-jin-95730512

2. 行內交易員對Alpha的看法:

https://www.patreon.com/posts/xing-nei-jiao-yi-97170473

3. 上司如何得知一個初級量化交易員的悟性?:

https://www.patreon.com/posts/shang-si-ru-he-99299074





【關於日內數據(Intraday Data)你不知道的二三事】

Comments

期貨轉月一般用 backward adjustment 處理,可用 differencing 或 ratio方法。但最好方法是,如果只做日內交易,逐個逐個individual contract去回測再將成績串連起來最穩陣。

SY

順帶一問,期貨轉月應如何處理?是否要好像股票那樣調整以前的數據?

Bendix Yiu

正解,要睇情況

SY

我覺得做唔做intraday data filling係兩睇,唔一定要做。好似SMA咁,你係想做"一段時間"嘅平均價格,定係"一段有成交嘅時段"平均價格。missing data多數係個時段冇成交先冇data(至少我data source係咁),所以我個人取向係唔做filling

Yat Fung Chan


More Creators