LumiBot / 下单与成交
LumiBot 的 AI Agent 提交了订单,凭什么算成交?
官方把「AI 能下单」写进了项目描述的第一句,但真正决定可信度的不是模型多聪明,而是订单有没有走完一条可核验的判定链:提交前的就绪检查、提交后的标识符核验、以及最关键的成交判定字段。
官方在工具文档里把这件事写成了硬规则:「Never claim a fill unless is_filled is true」。也就是说,提交成功不算成交、接口返回正常不算成交、轮询到期也不等于成交——只有订单状态里 is_filled 为真才算。这一条几乎可以单独用来筛选所有「AI 自动交易」演示。
这一页把这条链拆成六步,逐段说明你能观察到什么、容易在哪一步被误导,并给出一个自查清单:看到一个 AI 交易演示时,该问它哪几个问题。本站未在任何券商账户实盘下单,所有机制描述均来自官方仓库 docs/AI_AGENT_BUILTIN_TOOLS.md 与 docs/BROKER_ORDER_SEMANTICS.md,以官方实现为准。
docs/AI_AGENT_BUILTIN_TOOLS.md,2026-09-22 采集)。示意图只重述官方工具契约,不代表本站做过实盘验证。一条订单要走完六步,才算「真的成交」
把「AI 下单」拆开看,它其实是一条有明确检查点的流水线。任何一步缺失或跳过,你拿到的就只是一句无法核验的说法。
| 步骤 | 机制(工具 / 字段) | 你能观察到什么 | 注意点 |
|---|---|---|---|
| ① 就绪检查 | account_portfolio、account_positions、market_last_price(或批量 market_last_prices 里包含该 symbol) | 这三个只读工具在同一次 agent run 内都被调用过 | 缺任何一项,订单工具返回结构化错误 ORDER_READINESS_REQUIRED,不会下单 |
| ② 提交 | orders_submit_order;多腿期权用 orders_submit_multileg | 调用返回,agent 获得待核验的订单信息 | 「提交返回」不等于成交;官方要求随后核验标识符 |
| ③ 标识符核验 | orders_get_status | 券商侧订单标识与本地订单对象对应得上 | 先核验身份再谈状态;券商侧订单对象可能发生刷新与变化 |
| ④ 状态轮询 | orders_wait_for_terminal,有界轮询上限 120 秒,内部用 strategy.sleep 让挂单有机会被处理 | 轮询结束时的订单状态 | 到 120 秒仍未进入终态,只能记为未知,不能记为「已成交」 |
| ⑤ 成交判定 | 订单状态里的 is_filled 字段 | 为真才可称为成交 | 官方原文:Never claim a fill unless is_filled is true |
| ⑥ 审计留痕 | 提交后自动写入 order.submitted 记忆事件,事件带 agent_name 与 model_call_id | 可以追溯「哪一个 agent、在哪一次模型调用里提交的」 | 这是提交留痕,不是成交证据;记忆产物见记忆与回放 |
is_filled 的演示,都还停留在提示词层面。ORDER_READINESS_REQUIRED 长什么样
这是 LumiBot 相对一般「让模型直接调用下单接口」的做法最不一样的一处设计:它要求 agent 在提交前自己先把账看清楚。
| 检查项 | 为什么需要 | 缺了会怎样 | 注意点 |
|---|---|---|---|
account_portfolio | 给出可用现金与组合总价值,是任何下单量的依据 | 返回 ORDER_READINESS_REQUIRED,订单不提交 | 框架不会替你按现金比例自动缩单 |
account_positions | 给出当前持仓,避免在已有仓位上重复加码或误平 | 同上,拒绝下单 | 期权持仓会带上合约字段、有符号数量、均价与市值等 |
market_last_price | 给出所下 symbol 的当前价格 | 同上,拒绝下单 | 一次调用只处理一个交易符号 |
或 market_last_prices 批量 | 扫描一批标的时用批量接口取价 | 批量里必须包含要下单的那个 symbol | 批量接口的 symbols 上限为 150,并会返回可用与缺失清单 |
| 「同一次 run」的约束 | 保证价格与账户状态是同一时刻的、不是上一轮残留的 | 跨轮次取用旧数据同样会被判为未就绪 | 这是防「用过期价格下单」的机制 |
| 下单量的责任归属 | 官方明确:不静默调整下单量、也不跨资产类别套用统一保证金规则 | 不会出现「框架替你决定买多少」 | 下单量由 agent 依据已核验的现金、组合价值与持仓显式给出 |
ORDER_READINESS_REQUIRED,说明那一次根本没有发出委托——不要把它读成「下单失败但可能已经成交」。权限侧的分界(哪些工具在只读 agent 上根本不存在)见agent 权限分界。为什么它宁愿整单失败,也不拆成几条腿
多腿结构(价差、铁鹰、蝶式、跨式等)最怕的不是「没成交」,而是只成交了一部分——那会留下你没打算持有的裸敞口。LumiBot 在这里选的是 fail closed。
| 项 | 规则 | 注意点 |
|---|---|---|
| 提交方式 | orders_submit_multileg 把若干条腿作为一个原子请求提交 | 「原子」在这里的含义是:要么整包被券商接受,要么整包不发出 |
| 券商能力不足时 | 若当前券商未实现整包(package)提交,LumiBot 在提交任何一条腿之前就拒绝该请求 | 这不是重试逻辑,而是一道前置闸门 |
| 绝不回退 | 不会把多腿请求拆成若干条单腿子订单去「凑」 | 拆单正是产生裸敞口的典型原因,所以官方明确不做 |
| 每条腿的必填字段 | symbol、expiration、strike、right、quantity、side | 字段缺失属于无效请求,不会进入执行阶段 |
| 开仓 / 平仓动作 | 开仓用 buy_to_open / sell_to_open;平仓用 buy_to_close / sell_to_close | 不要用「买入 / 卖出」这种现货语序去理解期权腿 |
| 净价符号 | 净价正数为付出(debit)、负数为收入(credit) | 方向搞反会让整包价格与实际意图相反 |
| 工具不做的事 | 官方 8 个期权工具只负责取链、取行权价、取希腊值、找行权价、找到期日、评估市场、算多腿价格、检查价差收益 | 工具不替你选策略、不替你选腿;选腿是 agent 或你的责任 |
docs/BROKER_ORDER_SEMANTICS.md 里按 Alpaca、Schwab、Tradier、IBKR(股票期权)、IBKR(期货)、Tradovate、ProjectX、Crypto(Coinbase)分别记录,并自己注明这份行为表仍需 smoke test 才能从「文档」变成「事实」。时间与数量边界:哪些数字是硬上限
这些数字决定了你的策略在实盘里能跑多快、一次能扫多大范围。它们全部来自官方工具文档与仓库实现,不是本站的推荐值。
| 边界项 | 数值 / 规则 | 出处 | 注意点 |
|---|---|---|---|
| 订单状态轮询上限 | 120 秒 | orders_wait_for_terminal | 这是「等多久」,不是「多久该成交」;超时后状态依然要靠 orders_get_status 复核 |
| 批量取价规模 | 150 个 symbol | market_last_prices | 超过上限要拆批;返回值里有可用与缺失两个清单,缺失的不要臆造价格 |
| 历史数据加载 | 每次 1 个 symbol | market_load_history_table | 要横向扫描多个标的时,先用批量取价筛,再把入选者加载进 DuckDB 分析 |
| 成交的唯一判据 | is_filled 为真 | orders_get_status | 提交成功、HTTP 200、轮询到期都不构成成交证据 |
| 标识符核验 | 提交后必须用 orders_get_status 核验 | 官方工具文档 | 跳过这一步,后续所有状态判断都可能对错单 |
| 挂单能否被处理 | 轮询期间靠 strategy.sleep 让挂单有机会推进 | orders_wait_for_terminal | 自己写死循环等待会绕过这条机制 |
| 跨券商行为差异 | 行为表按 8 类券商品种分节,官方自述仍需 smoke test | docs/BROKER_ORDER_SEMANTICS.md | 「同一份策略代码」不等于「所有券商行为一致」,见本页自查清单与回测与实盘一致性 |
看到一个「AI 自动交易」演示时,该问什么
下面六条不需要你懂期权或券商接口,只需要看对方有没有给出可核验的东西。这一页的价值也在这里:把「能不能下单」变成一个可以逐条问的问题。
| 看到的迹象 | 说明什么 | 该问什么 |
|---|---|---|
| 只给收益曲线或净值截图 | 曲线可能来自回测,也可能来自平台数字,与真实委托无关 | 要看订单记录与每笔订单的 is_filled 状态 |
| 说「AI 已经下单」,但没有状态字段 | 「提交」与「成交」被合并成一句话 | 订单标识符是什么?最终状态是不是 is_filled? |
| 日志里没有账户与持仓检查 | 可能跳过了就绪门,或根本没有走 LumiBot 的订单工具 | 运行日志里有没有 account_portfolio 与 account_positions? |
| 多腿策略出现多笔单腿成交 | 与 LumiBot 的 fail closed 设计相反,说明不是走整包提交 | 券商是否支持整包提交?失败时是否拆单? |
| 把回测年化收益当成实盘结果 | 官方自己说明过:短区间的年化是外推,不是已实现的年度收益 | 回测区间多长?策略版本是哪一版?有没有样本外? |
| 券商对账单与展示的成交对不上 | 订单事件与现金事件在 LumiBot 里本就是两套记录 | 以谁的记录为准?差额出现在手续费、滑点还是未成交? |
is_filled、失败时按未知处理而不是按成功处理。这条链缺任何一环,你看到的就只是提示词加上一张截图。最小流程骨架,以及六类真实卡点
下面这段是流程示意:工具名取自官方 docs/AI_AGENT_BUILTIN_TOOLS.md,用来表达调用顺序;实际的方法签名、参数与返回值请以官方文档与仓库实现为准。
# 流程示意:只有被显式授权、且先看过账的 agent 才能提交订单
from lumibot.strategies import Strategy
class FillCheckDemo(Strategy):
def initialize(self):
self.sleeptime = "1D"
# 只有这个 agent 允许提交订单;其余 agent 用 allow_trading=False
self.agents.create(name="trader", allow_trading=True)
def on_trading_iteration(self):
# 1) 就绪检查:同一次 run 内先看账、看仓、看价,缺一项就会被拒
# account_portfolio / account_positions / market_last_price
# 2) 提交:orders_submit_order(多腿用 orders_submit_multileg)
# 3) 核验:orders_get_status 拿到券商侧标识符
# 4) 等待:orders_wait_for_terminal(有界轮询,上限 120 秒)
# 5) 判定:只有 is_filled 为 true 才算成交;超时按「未知」处理
pass
| 卡点 | 通常原因 | 处置 | 注意点 |
|---|---|---|---|
拿到 ORDER_READINESS_REQUIRED | 本次 run 内没有读账户、持仓或市价 | 在同一轮里补齐三项检查后再提交 | 这是拒绝,不是失败重试;不要试图绕过 |
| 提交后长时间不进入终态 | 超过 120 秒的轮询上限,或券商标的流动性不足 | 用 orders_get_status 复核,按「未知」记录 | 不要因为它最终成交过,就反推「当时已经成交」 |
| 多腿请求被直接拒绝 | 当前券商未实现整包提交 | 换支持整包的券商,或把策略改成单腿 | LumiBot 不会拆单兜底,这是设计而不是缺陷 |
| 取不到价格 | 该 symbol 在当前运行时点没有可用价格 | 跳过该标的,不要用自有估值替代 | 批量接口会返回缺失清单,按缺失清单处理 |
| agent 完全没有下单工具 | 创建时 allow_trading=False,变更类工具已被移除 | 重建该 agent 并显式开启交易权限 | 权限分界见agent 权限分界 |
| 批量取价部分 symbol 报缺失 | 超过 150 上限,或部分标的不可交易 | 拆批重试,并核对可用与缺失两个清单 | 不要把缺失当成价格为 0 |
关于「LumiBot 下单与成交」的高频问题
以下回答基于 2026-09-22 对官方仓库 docs/AI_AGENT_BUILTIN_TOOLS.md、docs/BROKER_ORDER_SEMANTICS.md 与工具清单的核对;涉及具体行为的部分以官方文档与仓库实现为准。本站未在任何券商账户实盘下单,也不做收益声明。
agent 提交订单之后,多久才算成交?
没有固定的「多久」。官方给出的 120 秒 是工具 orders_wait_for_terminal 的轮询上限,含义是「我等这么久」,不是「这么久应该成交」。等完仍未进入终态,正确的处理是按未知记录,再用 orders_get_status 复核。把 120 秒当成成交时限,会让偶发的延迟成交被误判成失败,也会让真正超时的单子被误判成成功。
is_filled 为真就说明这笔交易没问题了吗?
不是。它只回答一个问题:这笔订单成交了没有。成交价与预期价的差距(滑点)、手续费、以及部分成交的可能性,都不在这个字段里体现。官方之所以把它定为唯一判据,是为了让「说它买了」有最低限度的证据,而不是为了给交易质量背书。要评估交易质量,需要把订单记录与券商对账单、现金事件一起看;LumiBot 对现金事件另有一份专门文档,因为它与订单事件是两套记录。
为什么下单前必须先读账户和持仓?这不是多此一举吗?
这是官方故意设的门槛:它保证 agent 的下单量是基于同一时刻的真实现金、组合价值与持仓算出来的,而不是基于记忆里上一轮的旧数据。缺任一项就返回 ORDER_READINESS_REQUIRED 并不下单;框架也明确不静默调整下单量、不跨资产类别套用统一保证金规则。换句话说,仓位管理的责任明确留给 strategy 或 agent,框架不做隐式兜底。
多腿期权为什么整单失败,而不是尽量成交?
因为多腿结构的风险来自「腿不齐」。如果只成交了买入腿而没有成交卖出腿,你就持有了一个自己没打算开的裸敞口。LumiBot 的选择是原子提交、fail closed:券商不支持整包提交时,在提交任何一条腿之前就拒绝,也绝不回退成分腿子订单。代价是遇到不支持的券商时完全无法成交——所以多腿策略要把「券商是否支持整包」当成选券商的硬条件。
记忆里的 order.submitted 能当成交证据吗?
不能。它是订单提交后自动写入的一条记忆事件,用来追溯「哪一个 agent、在哪一次模型调用里提交的」,并带有 agent_name 与 model_call_id。它证明的是提交发生过,不是成交发生过。要证明成交,仍然只能回到订单状态里的 is_filled。记忆与回放的完整产物清单见记忆与回放。
我怎么自己核对这一页的说法?
三个入口:①官方工具文档 docs/AI_AGENT_BUILTIN_TOOLS.md(就绪门、成交判定原文、期权工具、批量上限都在这里);②官方订单语义文档 docs/BROKER_ORDER_SEMANTICS.md(按券商品种分节的行为表,并自述仍需 smoke test);③仓库里面向 AI 编码工具的 llms.txt。版本会变,请以你打开时的默认分支 dev 内容为准;本站记录的采集日期是 2026-09-22。