回測
線上連結¶
如下程式說明如何使用 FinMind 進行策略回測,主要透過 strategies 來進行回測,DataLoader 讀取 FinMind 提供的資料。
在進行回測的過程中,主要要先決定回測標的、回測區間、資金部位、交易稅以及策略的設計。
回測邏輯主要是去決定進場、維持和出場的訊號 (signal),例如:
- 今天計算出來的訊號為 -1,代表明天會以開盤價**賣掉** 1 張股票
- 今天計算出來的訊號為 0,代表明天什麼事都不做
- 今天計算出來的訊號為 1,代表明天會以開盤價**買進** 1 張股票
回測結果提供資訊如下:
- trade_detail: 回測詳細資料
- compare_market_detail: 大盤累積報酬和回測累積報酬走勢
- final_stats: 回測結果
- compare_market_stats: 大盤年化報酬率和策略年化報酬率
在範例程式中,主要分成使用 FinMind 提供的策略和客製化策略。
初始化,設定回測股票代碼、時間區間
import numpy as np
import pandas as pd
from FinMind import strategies
from FinMind.data import DataLoader
from FinMind.strategies.base import Strategy
from ta.momentum import StochasticOscillator
data_loader = DataLoader()
# data_loader.login(user_id, password) # 可選
obj = strategies.BackTest(
stock_id="0056",
start_date="2018-01-01",
end_date="2019-01-01",
trader_fund=500000.0,
fee=0.001425,
data_loader=data_loader,
)
obj.stock_price
將會用以下 data 計算回測
date stock_id Trading_Volume Trading_money open max min close spread Trading_turnover CashEarningsDistribution StockEarningsDistribution
0 2018-01-02 0056 1868451 46856990 25.00 25.14 25.00 25.13 0.13 733.0 0.0 0.0
1 2018-01-03 0056 3846820 97179269 25.15 25.31 25.15 25.31 0.18 1202.0 0.0 0.0
2 2018-01-04 0056 2736229 69496928 25.31 25.45 25.31 25.41 0.10 957.0 0.0 0.0
3 2018-01-05 0056 2383585 60620826 25.41 25.48 25.39 25.44 0.03 782.0 0.0 0.0
4 2018-01-08 0056 3048596 77817525 25.45 25.57 25.45 25.57 0.13 1236.0 0.0 0.0
.. ... ... ... ... ... ... ... ... ... ... ... ...
242 2018-12-24 0056 1501284 36271556 24.20 24.21 24.09 24.18 0.01 773.0 0.0 0.0
243 2018-12-25 0056 13908880 332473777 24.01 24.06 23.84 23.97 -0.21 6359.0 0.0 0.0
244 2018-12-26 0056 12600245 300239138 24.09 24.09 23.67 23.72 -0.25 6413.0 0.0 0.0
245 2018-12-27 0056 2986526 71566004 24.00 24.02 23.90 23.91 0.19 1651.0 0.0 0.0
246 2018-12-28 0056 2657586 63571334 23.93 23.96 23.89 23.94 0.03 1075.0 0.0 0.0
設計策略
class Kd(Strategy):
"""
summary:
日KD 80 20
日K線 <= 20 進場
日K線 >= 80 出場
"""
kdays = 9
kd_upper = 80
kd_lower = 20
def create_trade_sign(self, stock_price: pd.DataFrame) -> pd.DataFrame:
stock_price = stock_price.sort_values("date")
kd = StochasticOscillator(
high=stock_price["max"],
low=stock_price["min"],
close=stock_price["close"],
n=self.kdays,
)
rsv_ = kd.stoch().fillna(50)
_k = np.zeros(stock_price.shape[0])
_d = np.zeros(stock_price.shape[0])
for i, r in enumerate(rsv_):
if i == 0:
_k[i] = 50
_d[i] = 50
else:
_k[i] = _k[i - 1] * 2 / 3 + r / 3
_d[i] = _d[i - 1] * 2 / 3 + _k[i] / 3
stock_price["K"] = _k
stock_price["D"] = _d
stock_price.index = range(len(stock_price))
stock_price["signal"] = 0
stock_price.loc[stock_price["K"] <= self.kd_lower, "signal"] = 1
stock_price.loc[stock_price["K"] >= self.kd_upper, "signal"] = -1
return stock_price
回測模擬交易
obj.add_strategy(Kd)
obj.simulate()
obj.final_stats
output
MeanProfit 2366.450976
MaxLoss -1425.510000
FinalProfit 6196.970000
MeanProfitPer 0.470000
FinalProfitPer 1.240000
MaxLossPer -0.290000
AnnualReturnPer 1.250000
AnnualSharpRatio 0.860000
dtype: float64
交易明細
obj.trade_detail
output
stock_id date EverytimeProfit RealizedProfit UnrealizedProfit board_lot hold_cost hold_volume signal tax fee trade_price trader_fund
0 0056 2018-01-03 0.00 0.00 0.00 1000 0.000000 0 0 0.001 0.001425 25.15 500000.00000
1 0056 2018-01-04 0.00 0.00 0.00 1000 0.000000 0 0 0.001 0.001425 25.31 500000.00000
2 0056 2018-01-05 0.00 0.00 0.00 1000 0.000000 0 0 0.001 0.001425 25.41 500000.00000
3 0056 2018-01-08 0.00 0.00 0.00 1000 0.000000 0 0 0.001 0.001425 25.45 500000.00000
4 0056 2018-01-09 0.00 0.00 0.00 1000 0.000000 0 0 0.001 0.001425 25.55 500000.00000
.. ... ... ... ... ... ... ... ... ... ... ... ... ...
241 0056 2018-12-24 7274.35 5677.56 1596.79 1000 23.742118 4000 0 0.001 0.001425 24.20 410709.09425
242 0056 2018-12-25 6516.19 5677.56 838.63 1000 23.742118 4000 0 0.001 0.001425 24.01 410709.09425
243 0056 2018-12-26 6835.42 5677.56 1157.86 1000 23.742118 4000 0 0.001 0.001425 24.09 410709.09425
244 0056 2018-12-27 6476.29 5677.56 798.73 1000 23.742118 4000 0 0.001 0.001425 24.00 410709.09425
245 0056 2018-12-28 6196.97 5677.56 519.41 1000 23.742118 4000 0 0.001 0.001425 23.93 410709.09425
視覺化
obj.plot()