如果沒有完整歷史資料,那就只能實單回測,對於小資族而言,相當於是在賭身家,所以擁有完整的歷史 Tick 資料進行回測,對於確認策略的可能性及基礎有效性,是相當關鍵的一件事情。本系列將不會提及如何取得完整的歷史 Tick 資料,原因待有興趣的朋友進了圈子後自會理解。
請詳細閱讀前面各日所提及的各種技術與指標,回測系統需要整合已提過的相關技術。
大型台指期 2019/01/02 ~ 2019/09/20 Tick 資料
共 11341351 筆資料
TXF1-Ticks-2019-01-02~2019-09-20.csv
Date | Time | Price | Volume |
---|---|---|---|
2019/01/02 | 08:45:00.000 | 9760.000000 | 910 |
2019/01/02 | 08:45:00.000 | 9759.000000 | 1 |
2019/01/02 | 08:45:00.000 | 9759.000000 | 1 |
2019/01/02 | 08:45:00.000 | 9759.000000 | 1 |
2019/01/02 | 08:45:00.000 | 9759.000000 | 1 |
2019/01/02 | 08:45:00.000 | 9758.000000 | 1 |
2019/01/02 | 08:45:00.000 | 9758.000000 | 1 |
2019/01/02 | 08:45:00.000 | 9758.000000 | 1 |
2019/01/02 | 08:45:00.000 | 9758.000000 | 1 |
2019/01/02 | 08:45:00.000 | 9760.000000 | 2 |
2019/01/02 | 08:45:00.000 | 9760.000000 | 1 |
... | ... | ... | ... |
2019/09/20 | 13:44:57.992 | 10900.000000 | 5 |
2019/09/20 | 13:44:58.665 | 10899.000000 | 1 |
2019/09/20 | 13:44:58.761 | 10900.000000 | 2 |
2019/09/20 | 13:44:58.955 | 10900.000000 | 1 |
2019/09/20 | 13:44:59.020 | 10901.000000 | 2 |
2019/09/20 | 13:44:59.206 | 10901.000000 | 6 |
2019/09/20 | 13:44:59.659 | 10901.000000 | 6 |
2019/09/20 | 13:44:59.667 | 10901.000000 | 1 |
2019/09/20 | 13:44:59.731 | 10900.000000 | 1 |
2019/09/20 | 13:44:59.742 | 10900.000000 | 4 |
2019/09/20 | 13:44:59.947 | 10901.000000 | 6 |
在以下規格電腦中共花費約 13 分鐘匯入
import csv
import datetime
import loguru
import munch
import pymongo
def main():
client = pymongo.MongoClient('mongodb://%s:%s@%s:%s/' % (
'root',
'root',
'localhost',
'27017'
))
db = client.backtest
with open('TXF1-Ticks-2019-01-02~2019-09-20.csv') as f:
reader = csv.DictReader(f)
ticks = []
for row in reader:
# 透過 munchify 轉換為 stdObject 以方便在 formatted string 中取用屬性
row = munch.munchify(row)
t = datetime.datetime.strptime(f'{row.Date} {row.Time}+0800', '%Y/%m/%d %H:%M:%S.%f%z')
# 不做夜盤,僅保留日盤資料
if t.hour < 8 or t.hour > 13:
continue
ticks.append({
'time': t,
'price': float(row.Price),
'volume': int(row.Volume),
'created': datetime.datetime.now()
})
# 每 10000 筆資料再批次匯入,以提升匯入速度
if len(ticks) > 10000:
db.ticks.insert(ticks)
ticks = []
client.close()
if __name__ == '__main__':
loguru.logger.add(
f'{datetime.date.today():%Y%m%d}.log',
rotation='1 day',
retention='7 days',
level='DEBUG'
)
main()
在以下規格電腦中共花費約 50 分鐘計算並匯入
import datetime
import loguru
import pandas
import pymongo
def main():
client = pymongo.MongoClient('mongodb://%s:%s@%s:%s/' % (
'root',
'root',
'localhost',
'27017'
))
db = client.backtest
# 針對 2019 年每天執行計算
day = datetime.date(2019, 1, 1)
end = datetime.date(2020, 1, 1)
while day != end:
t = day
day = day + datetime.timedelta(days=1)
# 從 MongoDB 的 ticks 集合取出指定日期的全部 Tick
s = datetime.datetime(t.year, t.month, t.day, 0, 0, 0)
t = t + datetime.timedelta(days=1)
e = datetime.datetime(t.year, t.month, t.day, 0, 0, 0)
cursor = db.ticks.find({
'time': {
'$gte': s,
'$lt': e
}
}).sort([('created', 1)])
if cursor.count() == 0:
continue
# 將取出的 Tick 放入 DataFrame
docs = list(cursor)
TXF_TICKS = pandas.DataFrame(docs)
TXF_TICKS = TXF_TICKS.set_index('time')
# 計算 1 分 K,並將資料寫入 k1min 集合
TXF_1MINK = TXF_TICKS['price'].resample('1MIN').ohlc()
kbars = []
for index, row in TXF_1MINK.iterrows():
kbars.append({
'time': index,
'open': row['open'],
'high': row['high'],
'low': row['low'],
'close': row['close'],
'created': datetime.datetime.now()
})
db.k1min.insert(kbars)
# 計算 5 分 K,並將資料寫入 k5min 集合
TXF_5MINK = TXF_TICKS['price'].resample('5MIN').ohlc()
kbars = []
for index, row in TXF_5MINK.iterrows():
kbars.append({
'time': index,
'open': row['open'],
'high': row['high'],
'low': row['low'],
'close': row['close'],
'created': datetime.datetime.now()
})
db.k5min.insert(kbars)
if __name__ == '__main__':
loguru.logger.add(
f'{datetime.date.today():%Y%m%d}.log',
rotation='1 day',
retention='7 days',
level='DEBUG'
)
main()
透過修改以上方式,一樣能對均線等其他指標進行計算,並保存於 MongoDB 的集合中。
團隊系列文:
CSScoke - 金魚都能懂的這個網頁畫面怎麼切 - 金魚都能懂了你還怕學不會嗎
Clarence - LINE bot 好好玩 30 天玩轉 LINE API
Hina Hina - 陣列大亂鬥
King Tzeng - IoT沒那麼難!新手用JavaScript入門做自己的玩具
Vita Ora - 好 Js 不學嗎 !? JavaScript 入門中的入門。
TaTaMo - 用Python開發的網頁不能放到Github上?Lektor說可以!!