策略¶
策略是一个继承 Strategy 基类的 Python 类,核心是实现 on_bar 方法。
基本结构¶
from qka import Strategy
class MyStrategy(Strategy):
def __init__(self, cash=100_000):
super().__init__(cash=cash)
def on_bar(self, date):
close = self.get('close')
if close is None or close.empty:
return
# 交易逻辑写在这里
生命周期¶
回测按时间顺序逐日推进。每个交易日调用一次 on_bar(date),策略根据当日数据决定是否交易。
数据获取¶
self.get(factor) — 当日所有股票的横截面数据:
close = self.get('close')
# 返回 pd.Series:
# 000001.SZ 10.50
# 600000.SH 8.32
price = float(close['000001.SZ'])
for sym in close.index:
price = float(close[sym])
self.history(factor, window) — 过去 N 个交易日的历史数据:
hist = self.history('close', 20)
# 返回 pd.DataFrame:
# 000001.SZ 600000.SH
# 2024-01-02 10.2 8.12
# 2024-01-03 10.5 8.32
avg = hist['000001.SZ'].mean()
可访问的字段由 Data 配置决定。基础字段(open/high/low/close/volume)自动可用,指标字段需在 indicators 中声明。
交易¶
size 为股数。使用 self.sizing 计算合理仓位。
仓位计算¶
size = self.sizing.percent(0.1, price) # 可用资金的 10%
size = self.sizing.fixed_amount(10000, price) # 固定金额 1 万元
size = self.sizing.atr_risk(0.02, price, atr) # ATR 风控仓位
详见仓位。
状态管理¶
在 __init__ 中定义的自定义属性在整个回测过程中持续有效:
class MyStrategy(Strategy):
def __init__(self, cash=100_000):
super().__init__(cash=cash)
self.bought = False # 自定义状态
self.entry_prices = {} # 入场价格记录
多股票处理¶
self.get('close') 返回所有股票的横截面,遍历处理即可:
def on_bar(self, date):
close = self.get('close')
if close is None or close.empty:
return
for sym in close.index:
price = float(close[sym])
if price <= 0 or sym in self.broker.positions:
continue
size = self.sizing.percent(0.1, price)
if size > 0:
self.broker.buy(sym, price, size)
注意事项¶
| 行为 | 原因 |
|---|---|
不要在 on_bar 中下载数据 |
每根 bar 都下载会导致性能严重下降 |
不要在 on_bar 中使用 print |
数千根 bar 的输出量过大,应使用 logger.debug |
| 不要访问回测引擎内部 | 策略只需与 broker 和 sizing 交互 |