一、代码整体功能概览
本周的设定时间交易代码使用的是一套期货分钟级都策略模板,运行在 Panda ai的回测/实盘框架里,核心功能是:
交易标的:固定为白银主力某个合约 AG2604.SHF
频率:框架每分钟调用 handle_data,策略每分钟决策一次
信号逻辑:
用上一分钟 K线的阴阳来决定是否开仓:
阳线(收盘价 > 开盘价) → 无持仓时开多
阴线(收盘价 < 开盘价) → 无持仓时开空
十字线(收盘价 == 开盘价) → 不开仓
持有后满5分钟就无条件平仓(不再看后面的行情)
可以把它理解为一个“超简化的 1 分钟反应策略模板”:用最近一分钟的方向开仓,用时间管理平仓。
二、代码结构与框架回调
代码遵循 Panda 量化框架的典型结构,包含以下回调函数:
initialize(context):回测/实盘开始时只执行一次,用于初始化与打印信息
before_trading(context):每天开盘前执行一次
handle_data(context, data):每个 bar(这里是每一分钟)执行一次,是策略核心
after_trading(context):每天收盘后执行一次
2.1 全局常量:交易合约列表
当前只交易一个合约:AG2604.SHF(白银 2604 合约)
如果未来要扩展多合约,这里建议可以往列表加;后面有用到 len(SYMBOLS) 和 SYMBOLS[idx] 做轮换逻辑。(只作为技术分享不作为投资建议!!!)
#三、初始化函数
作用:在策略开始时打印日志,方便确认策略启动成功和当前时间。context.now 是框架提供的当前回测/实盘时间;datetime.now() 是本机时间,两者在回测里一般不同,实盘中可以接近。这里只是调试输出,没有做任何交易相关初始化(如参数、状态等)。可以理解为“程序启动说明书”,让你知道策略什么时候被加载起来。
四、开盘前回调 before_trading
每个交易日开盘前执行一次,目前只是简单打印日志。
实战中通常会在这里做:
当日数据预加载
计算日级信号
复位当日状态等
在当前版本中,它只是一个“占位函数”。
五、核心逻辑:handle_data(每分钟执行)
每分钟框架会把最新行情推进来,自动调用 handle_data。
第一行记录日志,第二行从 context.run_info 里取当前使用的期货账户 ID,用来后面下单。
5.1 按当前分钟选择合约
now = datetime.now():取当前本机时间
idx = now.minute % len(SYMBOLS):
用当前的“分钟数”对合约数量取模,得到一个索引
若有多个合约,会 按分钟轮换 合约进行下单
当前只有一个合约,所以 idx 永远是 0,实际就是一直用 AG2604.SHF
用轮换写法是为未来扩展多合约留接口,但目前实际等同于:
## 5.2 获取 1 分钟历史行情
panda_quant.get_previous_trading_date(…):
输入今天日期(如 20250111),返回 上一交易日(例如 20250110)。
future_api_quotation(…):
拉取期货 1 分钟级行情,字段通常包含 date, time, open, high, low, close, volume 等。
参数:
symbol_list=[symbol]:只请求当前合约
start_date:上一交易日
end_date:今天
period=‘1m’:1 分钟线
这样做的目的:一次性取自 上一交易日到当前日 的全部1分钟线,再从中拿最新几根 K 线用来决策
日志记录了完整的 DataFrame,方便调试和回溯。
5.3 数据有效性检查与排序
当数据为空或不足两条(少于两根 1 分钟 K 线)时,直接退出,不做任何交易。
为什么需要 >= 2 根 K 线?因为策略需要“倒数第二根 K 线”作为信号 bar。
排序逻辑:如果有 time 列,就按 [date, time] 排序 → 分时精确排序,否则只按 date 排序。这样可以保证 quotation_df_1m.iloc[-1] 真的是最新的那根 K 线,iloc[-2] 是倒数第二根。
5.4取前一根 1 分钟 K 线作为信号
prev_bar = 倒数第二根 1 分钟 K 线:策略选择用“前一根 bar”作为信号,而不是当前正在形成的 bar。
提取:
open_price:该分钟的开盘价
close_price:该分钟的收盘价
策略信号依据:
若 close_price > open_price → 该分钟为阳线 → 看涨信号
若 close_price < open_price → 阴线 → 看跌信号
若两者相等 → 十字线 → 不做方向判断
5.5 获取当前持仓
context.future_account_dict[account].positions[symbol]:
从框架提供的账户信息里读取 该合约当前持仓情况。
buy_quantity:多头持仓数量
sell_quantity:空头持仓数量
策略后面的逻辑会根据这个持仓状态决定:
是否允许开新仓
平多 or 平空 的数量
六、开仓逻辑
条件:
只有当 既没有多头也没有空头 (long_quantity == 0 and short_quantity == 0) 时,才会发开仓指令。
具体开仓规则:
阳线 → 开多
close_price > open_price:
调用 buy_open(account, symbol, 1):多头开仓 1 手
记录状态到 context.trade_state 中:
side: “long”(方向为多)
open_minute: now(开仓时间)
阴线 → 开空
close_price < open_price:
sell_open(account, symbol, 1):开空 1 手
side 记录为 “short”
十字线 → 不操作
close_price == open_price:
写日志说明“十字线,不开仓”,直接返回。这里的 context.trade_state 是一个 自定义的状态记录字典,挂在 context 上,用来在不同分钟之间记住:这个合约是何时开的仓,是多单还是空单
七、平仓逻辑
分支 else: 对应:当前已经有持仓(多或空之一)。
平仓规则:不看当前 K 线形态,只看 持仓时间是否超过 5 分钟。
流程拆解:读取先前记录的开仓信息
state = context.trade_state.get(symbol)
如果 state 不存在(比如策略重新启动,状态丢失):不进行时间相关控制,直接 return
检查 open_minute 类型,正常情况下是 datetime,如果数据异常,则打日志并退出
计算持仓时长(分钟)
held_minutes = (now - open_minute).total_seconds() / 60.0
满 5 分钟则平仓
若是多仓:
side == “long” and long_quantity > 0 → 调用 sell_close(…) 全部平多
若是空仓:
side == “short” and short_quantity > 0 → 调用 buy_close(…) 全部平空
平仓后清理状态
context.trade_state.pop(symbol, None):删除该合约在 trade_state 中的记录,下一次又可以作为“无持仓状态”重新开仓
划重点:
这里的平仓是 “时间驱动” 的,不管是浮盈还是浮亏,只要持有时间达到 5 分钟,就直接平。逻辑上只允许 单方向持仓,不会同时持多持空;开仓前限制了 long_quantity0 and short_quantity0。
八、收盘后回调 after_trading
每个交易日收盘后调用,目前只是打印日志。
实战中可以用来:输出当日收益 汇总日志、发送通知 清理或持久化 context.trade_state 等
九、整体策略逻辑总结
可以把整个策略概括为:数据获取层 每分钟获取上一交易日至今的1分钟线 取倒数第二根 K 线作为信号 bar信号层 若没有任何持仓:
上一分钟为阳线 → 开多 1 手
上一分钟为阴线 → 开空 1 手
十字线 → 不开仓
仓位与风控层
每个合约最多只持一个方向(多或空)
以“开仓时间 + 5 分钟”作为平仓触发条件
平仓后清空记录,下一轮信号可以重新开仓
它是一个很适合用来:熟悉 Panda 回测/实盘接口 理解 handle_data 每分钟的执行流程
演示如何:调用行情接口 从 context 读取持仓
调用 buy_open / sell_open / buy_close / sell_close
利用 context 存储自定义状态