事件驱动式回测
事件驱动式策略回测
备注
backtest 为 SYS 和 PF 回测的补充,但 SYS 和 PF 回测与事件回测原理不同,不要在事件回测中进行对 SYS 和 PF 的测试。
重要注意事项
备注
on_bar(stg) 函数中,为了回测和实盘一体,不能直接使用以下函数, 否则回测中使用的将是未来数据:
Datetime.now() 和 Datetime.today(),而需要使用 stg.now() 和 today()。
stock.get_kdata, 使用 stg.get_kdata, stg.get_last_kdata
- backtest([context, ]on_bar, tm, start_date, end_date, ktype, ref_market, mode, support_short, sp)
事件驱动式回测, 通常直接测试 Strategy 中的主体函数
如果 hikyuu 已经加载数据,可以忽略 context 参数。否则通 Strategy 类似,需要主动传入 context 参数, context 中包含需要加载的股票代码、K线类型、K线数量、K线起始日期等信息。
- 参数:
context (StrategyContext) -- 策略上下文 (在已经使用 load_hikyuu 的环境下,context可省略)
on_bar (func) -- 策略主体执行函数, 如: on_bar(stg: Strategy)
tm (TradeManager) -- 策略测试账户
start_date (Datetime) -- 起始日期
end_date (Datetime) -- 结束日期(不包含其本身)
ktype (Query.KType) -- K线类型(按该类型逐 Bar 执行测试)
ref_market (str) -- 所属市场
mode (int) -- 0 - 当前bar收盘价执行买卖操作; 1 - 下一bar开盘价执行买卖操作
support_short -- 是否支持卖空
sp (Slippage) -- 滑点算法
示例1 (在已使用 load_hikyuu 加载数据的环境下,可省略 context 参数)
from matplotlib import pyplot as plt
from hikyuu import *
options = {
"stock_list": ['sz000001'],
"ktype_list": ['min'],
"preload_num": {"min_max": 100000},
"load_history_finance": False,
"load_weight": False,
"start_spot": False
}
load_hikyuu(**options)
ma1 = MA(CLOSE(), 10)
ma2 = MA(CLOSE(), 30)
stk = sm['sz000001']
def on_bar(stg: Strategy):
k = stg.get_last_kdata(stk, 30, Query.MIN)
if len(k) < 30 or k[-1].datetime != stg.today():
# print("1")
return
ind = CROSS(ma1, ma2)(k)
if ind[-1] >= 1 and not stg.tm.have(stk):
stg.buy(stk, k[-1].close, 100)
elif ind[-1] < 1 and stg.tm.have(stk):
stg.sell(stk, k[-1].close, 100)
start_date = Datetime(2024, 1, 1)
end_date = Datetime(2025, 1, 1)
stk = sm['sz000001']
k = stk.get_kdata(Query(start_date, end_date, ktype=Query.MIN))
tm = crtTM()
backtest(on_bar, tm, start_date, end_date, Query.MIN)
tm.performance(Query(start_date, end_date, Query.MIN))
plt.show()
示例2 (使用 StrategyContext)
备注
该方式下, 无法在 stg 外获取像 sm['sz000001'] 这样获取股票对象,仅能在 stg 内部获取。如需在 stg 外部获取,参考示例3。
from hikyuu import *
class Config:
ktype = Query.DAY
stock = 'sz000001' # 注意此时不能使用 sm['sz000001']
ma1 = MA(CLOSE(), 10)
ma2 = MA(CLOSE(), 30)
def on_bar(stg: Strategy):
stk = sm[Config.stock]
k = stg.get_last_kdata(stk, 30, Config.ktype)
if len(k) < 30 or k[-1].datetime != stg.today():
return
ind = CROSS(Config.ma1, Config.ma2)(k)
if ind[-1] >= 1 and not stg.tm.have(stk):
stg.buy(stk, k[-1].close, 100)
elif ind[-1] < 1 and stg.tm.have(stk):
stg.sell(stk, k[-1].close, 100)
if __name__ == '__main__':
s = Strategy(['sz000001'], [Query.DAY])
# 实盘
# s.run_daily(my_func2, Minutes(1)) # , ignore_market=True)
# s.start()
# 回测
start_date = Datetime(2024, 1, 1)
end_date = Datetime(2025, 1, 1)
# 该方式下,此处获取不大实际的 stk !!!
# stk = sm['sz000001']
# k = stk.get_kdata(Query(start_date, end_date, ktype=Config.ktype))
tm = crtTM()
backtest(s.context, on_bar, tm, start_date, end_date, Config.ktype)
tm.performance(Query(start_date, end_date, Config.ktype))
from matplotlib import pyplot as plt
plt.show()
示例3 (使用 load_hikyuu 加载函数)
该方式一般用于回测或调试
from hikyuu import *
class Config:
ktype = Query.DAY
stock = 'sz000001' # 注意此时不能使用 sm['sz000001']
ma1 = MA(CLOSE(), 10)
ma2 = MA(CLOSE(), 30)
def on_bar(stg: Strategy):
stk = sm[Config.stock]
k = stg.get_last_kdata(stk, 100, Config.ktype)
# hku_info("{}, 当前价: {:<.2f}", stg.today(), k[-1].close)
if len(k) < 30 or k[-1].datetime != stg.today():
return
ind = CROSS(Config.ma1, Config.ma2)(k)
if ind[-1] >= 1 and not stg.tm.have(stk):
hku_info("{} 触发买入", stg.today())
stg.buy(stk, k[-1].close, 100)
hku_info("{}", stg.tm.get_position(stg.today(), stk))
elif ind[-1] < 1 and stg.tm.have(stk):
stg.sell(stk, k[-1].close, 100)
if __name__ == '__main__':
import os
import sys
if sys.platform == 'win32':
os.system('chcp 65001')
options = {
"stock_list": [Config.stock],
"ktype_list": [Config.ktype],
"load_history_finance": False,
"load_weight": False,
"start_spot": False
}
load_hikyuu(**options)
s = Strategy()
# 实盘
# s.run_daily(my_func2, Minutes(1)) # , ignore_market=True)
# s.start()
# 回测
start_date = Datetime(2023, 1, 1)
end_date = Datetime(2025, 1, 1)
print(sm['sz000001'])
tm = crtTM()
backtest(on_bar, tm, start_date, end_date, Config.ktype)
tm.performance(Query(start_date, end_date, Config.ktype))
from matplotlib import pyplot as plt
plt.show()