国内期货事件驱动回测框架(L1/L5 Tick + Bar,多合约,可配置撮合策略)
Project description
KestrelFBT — 国内期货回测框架
基于 Python 的事件驱动期货回测系统,支持 L1(普通行情)和 L5(五档深度)数据, 覆盖国内全交易所(SHFE / DCE / CZCE / CFFEX / INE / GFEX)。
快速开始
安装依赖
pip install -r requirements.txt
运行示例
# Bar 策略(双均线)
python examples/demo_strategy.py
# Tick 策略(L1 ask1 动量)
python examples/demo_tick_strategy.py
# 完整仓位管理(止盈/止损/移动止损)
python examples/example_position_mgmt.py
# 多合约价差策略(rb + hc)
python examples/example_multi_contract.py
# L5 walk_book 冲击成本对比
python examples/example_l5_walkbook.py
数据源
目录结构
{data_root}/
├── FUTURES_L1_TICK_ALL/ # L1 行情,覆盖全交易所
│ └── {YYYYMMDD}/
│ ├── DAY/{instrument}_day.csv
│ └── NIGHT/{instrument}_night.csv
├── FUTURES_L5_TICK_SHFE/ # L5 深度行情,按交易所分目录
├── FUTURES_L5_TICK_DCE/
├── FUTURES_L5_TICK_CZCE/
├── FUTURES_L5_TICK_CFFEX/
├── FUTURES_L5_TICK_INE/
└── FUTURES_L5_TICK_GFEX/
CSV 格式(30 列,无表头)
| 列 | 字段 | 说明 |
|---|---|---|
| 0 | instrument | 合约代码 |
| 1 | date | 自然日 YYYYMMDD |
| 2 | time | HHMMSSMMM(如 090000000) |
| 3 | turnover | 当日累计成交额 |
| 4 | volume | 当日累计成交量(session 内重置) |
| 5 | last_price | 最新价 |
| 6 | open_interest | 持仓量 |
| 7 | high_price | 当日最高 |
| 8 | low_price | 当日最低 |
| 9 | timestamp | Unix 微秒时间戳 |
| 10-14 | bid1-5 | 买一到买五价格 |
| 15-19 | ask1-5 | 卖一到卖五价格 |
| 20-24 | bid1-5_vol | 买一到买五挂量 |
| 25-29 | ask1-5_vol | 卖一到卖五挂量 |
L1 文件中 bid2-5 / ask2-5 列恒为 0
日期约定
文件夹日期 = 自然日(数据物理发生的日期)
交易日 T 的数据 =
夜盘:{T 的上一个自然日}/NIGHT/ ← 物理发生在上一自然日晚
日盘:{T}/DAY/
示例:交易日 20250103 = 20250102/NIGHT/ + 20250103/DAY/
基本用法
1. 编写策略
继承 BaseStrategy,重写需要的回调:
from kestrel.strategy.base import BaseStrategy
from kestrel.data.schema import TickData, BarData
class MyStrategy(BaseStrategy):
name = "MyStrategy"
def on_start(self): ... # 回测开始,初始化
def on_day_start(self, date): ... # 每日开始
def on_tick(self, tick: TickData): ... # 每条 tick
def on_bar(self, bar: BarData): ... # 每根 K 线(需配置 bar_periods)
def on_fill(self, fill_data): ... # 成交回报
def on_reject(self, reject_data): ...# 拒单通知
def on_day_end(self, date): ... # 每日结束
def on_stop(self): ... # 回测结束
2. 下单接口
# 开仓(均返回 order_id)
order_id = self.buy_open(instrument, price, volume, order_type="LIMIT")
order_id = self.sell_open(instrument, price, volume, order_type="MARKET")
# 平仓
order_id = self.sell_close(instrument, price, volume, order_type="LIMIT")
order_id = self.buy_close(instrument, price, volume, close_today=False)
# 撤单
self.cancel(order_id)
# order_type: "LIMIT"(限价)或 "MARKET"(市价/对手价)
3. 查询接口
tick = self.get_last_tick("rb2501") # 最新 tick
pos = self.get_position("rb2501") # 持仓(含多空手数、均价)
eq = self.get_equity() # 总权益
cash = self.get_cash() # 可用资金
4. 配置回测
from kestrel.engine.backtest import BacktestEngine, BacktestConfig
from kestrel.engine.matching import ContractInfo, FillPolicy
config = BacktestConfig(
instruments = ["rb2501"], # 订阅合约列表
start_date = 20250102, # 回测起始交易日
end_date = 20250228, # 回测结束交易日
initial_capital = 500_000.0, # 初始资金(元)
contracts = [ContractInfo(...)], # 合约规格(见下方)
use_l5 = False, # True=L5数据,False=L1数据
fill_policy = FillPolicy(...), # 撮合策略(见下方)
bar_periods = [1, 5], # K线周期(分钟),None=不合成K线
data_root = "/mnt/nvme1n1", # 数据根目录
output_path = "./results/out.json", # 结果输出路径(None=不输出)
)
engine = BacktestEngine(config, MyStrategy())
report = engine.run()
5. 合约规格
ContractInfo(
instrument = "rb2501", # 合约代码
exchange = "SHFE", # 交易所
multiplier = 10, # 合约乘数(元/点)
price_tick = 1.0, # 最小变动价位
margin_rate = 0.08, # 保证金率(按合约价值比例)
commission_per_lot = 10.0, # 手续费(元/手),与 commission_rate 二选一
commission_rate = 0.0, # 手续费率(按成交额比例)
)
常见合约规格参考 config/contract_specs.json(含乘数和最小变动价,不含保证金/手续费)。
6. 撮合策略
FillPolicy(
# 限价单成交模式
limit_fill_mode = "next_tick", # 默认:下一tick才成交(最保守)
# "price_cross":价格穿越即成交
# "volume_participation":按成交量参与比例
volume_participation_rate = 0.3, # 仅 volume_participation 模式有效
# 市价单 / 对手价成交模式
market_fill_mode = "next_tick", # 默认:下一tick对手盘价格成交
# "current_tick":当前快照价格(有预见性偏差)
market_slippage_ticks = 1, # 额外滑点跳数(>=0)
# L5 模式:按五档深度逐档消耗,量化市场冲击成本
# L1 模式下此参数自动忽略
walk_book = True,
)
数据模型
TickData
tick.instrument # 合约代码
tick.trading_date # 交易日 YYYYMMDD
tick.time # HHMMSSMMM
tick.timestamp # Unix 微秒
tick.last_price # 最新价
tick.delta_volume # 本 tick 新增成交量(差分后)
tick.bid1 # 买一价(L1/L5 均有)
tick.ask1 # 卖一价
tick.bid1_vol # 买一量
tick.ask1_vol # 卖一量
tick.bid2-5 # 买二到买五(仅 L5 有效)
tick.ask2-5 # 卖二到卖五(仅 L5 有效)
tick.is_l5() # 是否包含五档深度
tick.ask_prices() # [ask1, ask2, ..., ask5]
tick.ask_vols() # [ask1_vol, ..., ask5_vol]
BarData
bar.instrument # 合约代码
bar.trading_date # 交易日
bar.bar_time # Bar 开始时间 HHMMSSMMM
bar.period_min # K 线周期(分钟)
bar.open / high / low / close
bar.volume # 该 Bar 内成交量
InstrumentPosition
pos = self.get_position("rb2501")
pos.long_volume # 多头持仓手数
pos.short_volume # 空头持仓手数
pos.long_avg_price() # 多头均价
pos.short_avg_price()# 空头均价
pos.floating_pnl() # 浮动盈亏
回测报告
engine.run() 返回 dict,同时(若配置了 output_path)写入 JSON 文件:
{
"config": { "instruments": [...], "start_date": ..., ... },
"metrics": {
"total_return": 0.0512,
"annual_return": 0.1823,
"sharpe_ratio": 1.42,
"calmar_ratio": 2.31,
"max_drawdown": 12500.0,
"max_drawdown_pct": 0.025,
"win_rate": 0.54,
"profit_factor": 1.8,
"total_commission": 1200.0,
"total_trades": 120,
"total_turnover": 8500000.0
},
"equity_curve": [
{ "date": 20250102, "equity": 502000, "daily_pnl": 2000, ... },
...
]
}
控制台打印摘要:
from kestrel.analytics.report import print_summary
print_summary(report)
架构概览
BacktestConfig
└─ BacktestEngine
├─ DataFeed ← 多合约 tick 归并回放 + Bar 合成
├─ EventEngine ← 同步事件总线
├─ MatchingEngine ← 撮合引擎(FillPolicy 可配置)
│ └─ ContractInfo ← 合约规格
├─ Portfolio ← 持仓 + 逐日盯市结算
└─ BaseStrategy ← 用户策略(可插拔)
↑ on_tick / on_bar / on_fill
事件流(每个 tick):
DataFeed → TickData
→ MatchingEngine.on_tick() 先撮合上一 tick 的挂单
→ Portfolio.on_tick() 更新浮动盈亏
→ Strategy.on_tick() 触发策略逻辑
→ Strategy.on_bar() 触发已完成的 Bar
→ EventEngine.process_all() 处理 ORDER / FILL / REJECT
注意事项
-
L1 vs L5 互斥:两者代表不同的实盘账户类型,不可混用。 用 L5 数据回测但实盘只有 L1 会高估信息优势。
-
撮合近似性:所有基于快照数据的成交模拟都是近似。
FillPolicy的默认参数(next_tick+ 1 跳滑点)偏保守。 建议用实盘成交数据校准滑点参数。 -
成交量累计:CSV 中的
volume是 session 内累计值。 框架内部已自动做差分,tick.delta_volume即为本 tick 新增成交量。 DAY/NIGHT session 切换时差分基准自动重置。 -
交易日归属:夜盘数据文件夹日期为自然日,但在框架内已映射为下一交易日。 策略代码中的
tick.trading_date和on_day_start(date)始终是交易日。 -
多合约时间对齐:多合约 tick 按
timestamp(微秒)全局排序后串行回放, 保证跨合约策略(套利)的时间一致性和结果确定性。 -
参数优化:如需跑多组参数,使用
multiprocessing.Pool在多进程中 各自创建独立的BacktestEngine,不要在引擎内部使用多线程。
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kestrel_fbt-0.1.0.tar.gz.
File metadata
- Download URL: kestrel_fbt-0.1.0.tar.gz
- Upload date:
- Size: 34.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3076ceeb98d1959c8c495fbc9029a279e305b227512574ab04732e46e8c9ce96
|
|
| MD5 |
3061c5010c4cbc1f6181fa95413327fb
|
|
| BLAKE2b-256 |
b2c06880b65242021b28321e6d33875d8dc8ef965196ff0309d272f2d58c0d5a
|
File details
Details for the file kestrel_fbt-0.1.0-py3-none-any.whl.
File metadata
- Download URL: kestrel_fbt-0.1.0-py3-none-any.whl
- Upload date:
- Size: 37.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
51bb1dc2e51ce750093e4ea274c4b428cbecca3b7965a91df29e950dd5673ce9
|
|
| MD5 |
9ea422d188e9bb1ccd2ca27f1a84d25b
|
|
| BLAKE2b-256 |
c3974ec69338c7fdcf1d83585bab6046ce67b1c8de345cecce75163cbad3ae77
|