LumiBot / 下单与成交

LumiBot 的 AI Agent 提交了订单,凭什么算成交?

官方把「AI 能下单」写进了项目描述的第一句,但真正决定可信度的不是模型多聪明,而是订单有没有走完一条可核验的判定链:提交前的就绪检查、提交后的标识符核验、以及最关键的成交判定字段。

官方在工具文档里把这件事写成了硬规则:「Never claim a fill unless is_filled is true」。也就是说,提交成功不算成交、接口返回正常不算成交、轮询到期也不等于成交——只有订单状态里 is_filled 为真才算。这一条几乎可以单独用来筛选所有「AI 自动交易」演示。

这一页把这条链拆成六步,逐段说明你能观察到什么、容易在哪一步被误导,并给出一个自查清单:看到一个 AI 交易演示时,该问它哪几个问题。本站未在任何券商账户实盘下单,所有机制描述均来自官方仓库 docs/AI_AGENT_BUILTIN_TOOLS.mddocs/BROKER_ORDER_SEMANTICS.md,以官方实现为准。

成交判据 is_filled轮询上限 120 秒多腿整包 fail closed采集日期 2026-09-22
就绪检查账户 / 持仓 / 市价 三项须在同一次 run 内被读过,缺一项即拒绝下单
提交与核验提交后拿订单标识符,再用 orders_get_status 核验
成交判定只有 is_filled 为 true 才算成交;超时按未知处理
下单与成交判定流程示意(依据官方 docs/AI_AGENT_BUILTIN_TOOLS.md,2026-09-22 采集)。示意图只重述官方工具契约,不代表本站做过实盘验证。
判定链

一条订单要走完六步,才算「真的成交」

把「AI 下单」拆开看,它其实是一条有明确检查点的流水线。任何一步缺失或跳过,你拿到的就只是一句无法核验的说法。

步骤机制(工具 / 字段)你能观察到什么注意点
① 就绪检查account_portfolioaccount_positionsmarket_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_namemodel_call_id可以追溯「哪一个 agent、在哪一次模型调用里提交的」这是提交留痕,不是成交证据;记忆产物见记忆与回放
为什么顺序不能颠倒:把「提交成功」当成结论,是 AI 交易演示里最常见的偷换。官方把成交判定单独做成一个字段,就是为了让「说它买了」和「真的买了」之间有据可查。任何只展示净值曲线、不展示订单状态与 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 依据已核验的现金、组合价值与持仓显式给出
关键区别:这是「拒绝」,不是「自动补齐」。很多框架会在数据不全时补一个默认值继续执行;LumiBot 的选择是直接返回结构化错误并停手。对你的意义:如果一次运行日志里出现了 ORDER_READINESS_REQUIRED,说明那一次根本没有发出委托——不要把它读成「下单失败但可能已经成交」。权限侧的分界(哪些工具在只读 agent 上根本不存在)见agent 权限分界
多腿期权

为什么它宁愿整单失败,也不拆成几条腿

多腿结构(价差、铁鹰、蝶式、跨式等)最怕的不是「没成交」,而是只成交了一部分——那会留下你没打算持有的裸敞口。LumiBot 在这里选的是 fail closed。

规则注意点
提交方式orders_submit_multileg 把若干条腿作为一个原子请求提交「原子」在这里的含义是:要么整包被券商接受,要么整包不发出
券商能力不足时若当前券商未实现整包(package)提交,LumiBot 在提交任何一条腿之前就拒绝该请求这不是重试逻辑,而是一道前置闸门
绝不回退不会把多腿请求拆成若干条单腿子订单去「凑」拆单正是产生裸敞口的典型原因,所以官方明确不做
每条腿的必填字段symbolexpirationstrikerightquantityside字段缺失属于无效请求,不会进入执行阶段
开仓 / 平仓动作开仓用 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 个 symbolmarket_last_prices超过上限要拆批;返回值里有可用与缺失两个清单,缺失的不要臆造价格
历史数据加载每次 1 个 symbolmarket_load_history_table要横向扫描多个标的时,先用批量取价筛,再把入选者加载进 DuckDB 分析
成交的唯一判据is_filled 为真orders_get_status提交成功、HTTP 200、轮询到期都不构成成交证据
标识符核验提交后必须用 orders_get_status 核验官方工具文档跳过这一步,后续所有状态判断都可能对错单
挂单能否被处理轮询期间靠 strategy.sleep 让挂单有机会推进orders_wait_for_terminal自己写死循环等待会绕过这条机制
跨券商行为差异行为表按 8 类券商品种分节,官方自述仍需 smoke testdocs/BROKER_ORDER_SEMANTICS.md「同一份策略代码」不等于「所有券商行为一致」,见本页自查清单与回测与实盘一致性
自查清单

看到一个「AI 自动交易」演示时,该问什么

下面六条不需要你懂期权或券商接口,只需要看对方有没有给出可核验的东西。这一页的价值也在这里:把「能不能下单」变成一个可以逐条问的问题。

看到的迹象说明什么该问什么
只给收益曲线或净值截图曲线可能来自回测,也可能来自平台数字,与真实委托无关要看订单记录与每笔订单的 is_filled 状态
说「AI 已经下单」,但没有状态字段「提交」与「成交」被合并成一句话订单标识符是什么?最终状态是不是 is_filled
日志里没有账户与持仓检查可能跳过了就绪门,或根本没有走 LumiBot 的订单工具运行日志里有没有 account_portfolioaccount_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
FAQ

关于「LumiBot 下单与成交」的高频问题

以下回答基于 2026-09-22 对官方仓库 docs/AI_AGENT_BUILTIN_TOOLS.mddocs/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_namemodel_call_id。它证明的是提交发生过,不是成交发生过。要证明成交,仍然只能回到订单状态里的 is_filled记忆与回放的完整产物清单见记忆与回放

我怎么自己核对这一页的说法?

三个入口:①官方工具文档 docs/AI_AGENT_BUILTIN_TOOLS.md(就绪门、成交判定原文、期权工具、批量上限都在这里);②官方订单语义文档 docs/BROKER_ORDER_SEMANTICS.md(按券商品种分节的行为表,并自述仍需 smoke test);③仓库里面向 AI 编码工具的 llms.txt版本会变,请以你打开时的默认分支 dev 内容为准;本站记录的采集日期是 2026-09-22。

下一步:订单与指标都说「没问题」时,回测里最容易自欺的是哪一处?

判定链解决的是「有没有真的下单」。下一个更容易被跳过的问题是:这套回测本身有没有偷看未来——官方自己的文档里就写着一个数值从 25 变成 1510 的回归案例。