跳转到正文

期货日频回测 ​

先完成安装,阅读期货机制。本页使用日频收盘模型:普通委托按真实合约收盘价尝试成交,系列移仓按结算价完成。该模型不承诺可按实盘收盘时点复制成交。

运行 ​

保存为 future_daily.py,执行 python future_daily.py。示例首个可用 bar 开多 RB 系列 1 手,盘后核对实际数量,随后持有;未达目标直接报错。示例固定手续费不是历史交易所费率。

python
from datetime import datetime
from pathlib import Path
from zoneinfo import ZoneInfo

from localquant import run_func
from localquant.apis import buy_open, get_position, subscribe
from localquant.mod.localquant_mod_seeddata_source import load_framework_data, register_bundle, discard_bundle
from localquant.mod.localquant_mod_sys_analyser.report import export_full_html

CODE = "RB.SHF"
START, END = "2026-09-01", "2026-09-03"
FREQUENCY = "1d"
MATCHING = "current_bar"
BASE_URL = "http://127.0.0.1:28637"
name = datetime.now(ZoneInfo("Asia/Shanghai")).strftime("%Y-%m-%d-%H-%M-%S")
output = Path("output/backtest") / name
output.mkdir(parents=True, exist_ok=False)

def init(context):
    subscribe(CODE)
    context.sent = False

def handle_bar(context, bars):
    if not context.sent and not bars[CODE].isnan:
        buy_open(CODE, 1)
        context.sent = True

def after_trading(context):
    if get_position(CODE).quantity != 1:
        raise RuntimeError("示例未达到 1 手多仓,请检查订单状态与行情")

bundle = load_framework_data(
    [CODE], START, END, base_url=BASE_URL, asset_type="cn_future",
    frequency=FREQUENCY, index_codes=["NHCI.NH"], include_yield_curve=False,
)
key = register_bundle(bundle)
try:
    result = run_func(init=init, handle_bar=handle_bar, after_trading=after_trading, config={
        "base": {"start_date": START, "end_date": END, "frequency": FREQUENCY,
                 "accounts": {"future": 1_000_000}, "margin_multiplier": 1,
                 "capital_gain_tax_rate": 0, "use_risk_free_rate": False},
        "mod": {
            "seeddata_source": {"enabled": True, "lib": "localquant.mod.localquant_mod_seeddata_source",
                                "priority": 0, "bundle_key": key},
            "sys_accounts": {"futures_settlement_price_type": "settlement"},
            "sys_simulation": {"matching_type": MATCHING},
            "sys_transaction_cost": {"futures_commission": {
                "default": {"type": "by_money", "open": 0.0001, "close": 0.0001, "close_today": 0.0001},
            }},
            "sys_analyser": {"enabled": True, "record": True,
                             "benchmark": {"type": "instrument", "order_book_id": "NHCI.NH"}, "output_file": str(output / "result.pkl")},
        },
    })["sys_analyser"]
finally:
    discard_bundle(key)

export_full_html(result, name, output / "full_report.html")
print(result["trades"])
print(output.resolve())

结果位于 output/backtest/<运行时间>/result.pkl 与 full_report.html。本例显式选择 NHCI.NH 为基准;期末保留持仓,收益按末日结算后权益评价。更换代码、区间或数据地址时,应确认相应数据已就绪。

信号与路由 ​

阶段行情与策略行为
before_trading日线历史截至前一交易日,可生成滞后信号;不能查询当日系列下单路由
handle_bar,15:15当日日线已完整;系列开仓使用当日 mapping,实际月合约收盘价撮合
after_trading检查普通成交和策略状态;日终移仓及结算尚未完成
日终结算按系统移仓模型换月、到期处理、结算,再生成结果快照

连续系列仅允许 handle_bar 下单,get_future_series_contract(series) 也仅在此日频回调返回当日路由。日频当前映射与收盘数据按收盘后可得处理,不能拿它们倒推盘前已可执行的订单。

推荐日频策略在 T 日盘前读取截至 T-1 的日线,T 日收盘回调执行。框架也允许使用 T 日完整日线生成信号后按 T 日收盘价成交;这属于同收盘研究假设,必须在策略执行口径中明确。日频 handle_bar 的 include_now=False 仍包含当天,不能用它排除当日数据。

日频没有 next_bar 成交模式;设置它会告警并按 current_bar 运行。连续系列若要求观察完成后在后续可交易时点执行,应使用分钟回测,并按其固定路由规则处理。

策略验收 ​

检查信号截止日、实际合约、方向、手数、费用与账户权益。反转先完成原方向平仓,再按实际资金开仓;拒单或部分成交后的继续处理由策略声明。order_to(series, 0) 只表达净目标,多空相等的对冲仓不能据此认为已清空。

换月当天的策略成交与系统成交分别看 trade_source。普通成交受撮合限制,系统移仓不受同一限制。成本、移仓资金与结算算例见期货机制。

localquant documentation