第 8 章 · 01 订单类型与提交


文档摘要

第 8 章 · 01 订单类型与提交 本节摘要:本节钻取 Lean 的第 8 层入口——订单类型与订单提交链路。 目录是 Lean 最大的领域模型集中地之一(约 1.5 万行、80+ 个 .cs 文件),覆盖订单类型(Market 市价/Limit 限价/StopMarket 止损市价/StopLimit 止损限价/Combo 组合/OptionExercise 期权行权/MarketOnOpen 开盘市价/MarketOnClose 收盘市价)、订单属性(IOrderProperties,内含 TimeInForce/Exchange)、订单票据(OrderTicket,跟踪 Status/FilledQuantity/AverageFillPrice

第 8 章 · 01 订单类型与提交

本节摘要:本节钻取 Lean 的第 8 层入口——订单类型与订单提交链路。Common/Orders 目录是 Lean 最大的领域模型集中地之一(约 1.5 万行、80+ 个 .cs 文件),覆盖订单类型(Market 市价/Limit 限价/StopMarket 止损市价/StopLimit 止损限价/Combo 组合/OptionExercise 期权行权/MarketOnOpen 开盘市价/MarketOnClose 收盘市价)、订单属性(IOrderProperties,内含 TimeInForce/Exchange)、订单票据(OrderTicket,跟踪 Status/FilledQuantity/AverageFillPrice 并支持查询/修改/取消)、订单序列化(OrderJsonConverter + Serialization/)。订单从用户代码到 TransactionHandler 的链路为:QCAlgorithm.Trading 的便捷方法(MarketOrder/LimitOrder/SetHoldings)→ 构造 SubmitOrderRequestPreOrderChecks 预检(资金/市场/数量/手数)→ Transactions.AddOrder 进入事务管理器 → 由 TransactionHandler 落地。读完本节,你掌握了 Lean 订单体系的骨架与下单链路。

内容来源:原项目源码 Common/Orders/Order.csMarketOrder.csLimitOrder.csStopMarketOrder.csStopLimitOrder.csComboOrder.csOptionExerciseOrder.csMarketOnOpenOrder.csMarketOnCloseOrder.csOrderProperties.csOrderTicket.csAlgorithm/QCAlgorithm.Trading.cs,精读并套用体系化模板。

⚠️ 注意:本节聚焦"订单是什么 + 怎么提交",成交怎么算(ImmediateFillModel/PartialFillModel)在下一节,手续费/滑点/TimeInForce 在第 03 节。三者共同构成"订单生命周期"。

学习目标

阅读完本节,你应当能够:

  1. 列出 Lean 的 8+ 种订单类型与各自的核心字段。
  2. 读懂 Order 抽象基类的统一字段与 CreateOrder 工厂。
  3. 复述下单链路:便捷方法 → SubmitOrderRequestPreOrderChecksAddOrder
  4. 解释 IOrderPropertiesOrderTicket 的作用。
  5. 区分 SetHoldings(按百分比)与 MarketOrder(按绝对数量)。
  6. 说出订单从用户代码到 TransactionHandler 的完整传递过程。

一、Common/Orders:1.5 万行订单模型的家

Common/Orders/ 下 80+ 个 .cs 文件,按职责分四组:

分组 代表文件
订单类型 Order.cs(基类)、MarketOrder.csLimitOrder.csStopMarketOrder.csStopLimitOrder.csTrailingStopOrder.csLimitIfTouchedOrder.csMarketOnOpenOrder.csMarketOnCloseOrder.csOptionExerciseOrder.csComboOrder.cs/ComboMarketOrder.cs/ComboLimitOrder.cs/ComboLegLimitOrder.cs
订单请求/响应 SubmitOrderRequest.csUpdateOrderRequest.csCancelOrderRequest.csOrderResponse.csOrderError.cs
订单票据/事件 OrderTicket.csOrderEvent.csOrderUpdateEvent.cs
属性/序列化 OrderProperties.csAlpacaOrderProperties.cs 等 20+ 券商专属属性、OrderJsonConverter.csSerialization/

另有三个子目录:Fills/(成交模型,下节讲)、Fees/(手续费,第 03 节)、Slippage/(滑点,第 03 节)、TimeInForces/(有效期,第 03 节)、OptionExercise/(行权模型,第 03 节)。命名规律清晰——文件名即类型名。

二、Order 抽象基类:统一字段

Common/Orders/Order.cs:31(所有订单类型的基类):

31 public abstract class Order 33 private volatile int _incrementalId; 41 public int Id { get; internal set; } // 订单ID 62 public int ContingentId { get; internal set; } // 依赖订单(先处理后处理本单) 68 public List<string> BrokerId { get; internal set; } // 券商侧ID(可能多个) 74 public Symbol Symbol { get; internal set; } // 标的 80 public decimal Price { get; internal set; } // 订单价格(成交后回填均价) 96 public DateTime Time { get; internal set; } // 创建时间(UTC) 108 public DateTime? LastFillTime { get; internal set; } // 最近成交时间 114 public DateTime? LastUpdateTime { get; internal set; } 120 public DateTime? CanceledTime { get; internal set; } 126 public virtual decimal Quantity { get; internal set; }// 数量(正买负卖) 136 public abstract OrderType Type { get; } // 订单类型(子类实现) 142 public OrderStatus Status { get; set; } // 状态 148 public TimeInForce TimeInForce => Properties.TimeInForce; 160 public IOrderProperties Properties { get; private set; } // 订单属性 172 public OrderDirection Direction // 方向(由Quantity符号决定) 176 if (Quantity > 0) return OrderDirection.Buy; 180 if (Quantity < 0) return OrderDirection.Sell; 184 return OrderDirection.Hold;

两个抽象成员决定了"子类必须实现什么":Type(返回 OrderType 枚举)和 Clone()(深拷贝,用于回测快照)。GetValueImpl(security) 也是抽象的——每种订单算"订单价值"的方式不同(市价单按当前价,限价单按限价)。

Order.cs:413 的静态工厂 CreateOrder(SubmitOrderRequest) 是订单构造的总入口,内部 switch 按 OrderType 实例化对应子类:

413 public static Order CreateOrder(SubmitOrderRequest request) 420 private static Order CreateOrder(int orderId, OrderType type, ...) 425 switch (type) 427 case OrderType.Market: order = new MarketOrder(...); break; 431 case OrderType.Limit: order = new LimitOrder(...); break; 435 case OrderType.StopMarket:order = new StopMarketOrder(...);break; 439 case OrderType.StopLimit: order = new StopLimitOrder(...);break; 443 case OrderType.TrailingStop: order = new TrailingStopOrder(...);break; 451 case OrderType.MarketOnOpen: order = new MarketOnOpenOrder(...);break; 455 case OrderType.MarketOnClose: order = new MarketOnCloseOrder(...);break; 459 case OrderType.OptionExercise:order = new OptionExerciseOrder(...);break; 463 case OrderType.ComboLimit: order = new ComboLimitOrder(...);break; 471 case OrderType.ComboMarket: order = new ComboMarketOrder(...);break; 478 order.Status = OrderStatus.New; 479 order.Id = orderId;

三、八种订单类型对照

每种订单类型都是 Order 的子类,只多出"自己专属的字段":

类型 类名 专属字段 成交逻辑(下节详述)
市价 MarketOrder 立即按当前价全部成交
限价 LimitOrder LimitPrice 价格触及限价或更好时成交
止损市价 StopMarketOrder StopPrice 价格触及止损价后按市价成交
止损限价 StopLimitOrder StopPrice+LimitPrice+StopTriggered 触发后转成限价单
追踪止损 TrailingStopOrder TrailingAmount+TrailingAsPercentage 止损价随市场价自动跟踪
触价限价 LimitIfTouchedOrder TriggerPrice+LimitPrice 触及触发价后挂限价单
开盘市价 MarketOnOpenOrder 下一交易日开盘成交
收盘市价 MarketOnCloseOrder SubmissionTimeBuffer 当日收盘成交(需提前 15.5 分钟)
期权行权 OptionExerciseOrder 无(数量为正) 行权产生标的买卖
组合市价 ComboMarketOrder GroupOrderManager 多腿组合按市价
组合限价 ComboLimitOrder GroupOrderManager+LimitPrice 整组合按一个限价

LimitOrder.cs:26:

26 public class LimitOrder : Order 32 public decimal LimitPrice { get; internal set; } // 限价 37 public override OrderType Type => OrderType.Limit; 58 public LimitOrder(Symbol symbol, decimal quantity, decimal limitPrice, DateTime time, ...) 61 LimitPrice = limitPrice;

StopMarketOrder.cs:26(止损市价,只多一个 StopPrice):

26 public class StopMarketOrder : Order 32 public decimal StopPrice { get; internal set; } // 止损触发价 37 public override OrderType Type => OrderType.StopMarket; 58 public StopMarketOrder(Symbol symbol, decimal quantity, decimal stopPrice, DateTime time, ...) 61 StopPrice = stopPrice;

StopLimitOrder.cs:26(止损限价,既有 StopPrice 又有 LimitPrice,还多一个 StopTriggered 状态位记录"是否已触发"):

32 public decimal StopPrice { get; internal set; } 38 public bool StopTriggered { get; internal set; } // 是否已转为限价单 44 public decimal LimitPrice { get; internal set; } 49 public override OrderType Type => OrderType.StopLimit;

OptionExerciseOrder.cs:26(期权行权,字段最少——只靠 Symbol 携带期权合约信息,Quantity 表示行权合约数):

26 public class OptionExerciseOrder : Order 44 public OptionExerciseOrder(Symbol symbol, decimal quantity, DateTime time, ...) 52 public override OrderType Type => OrderType.OptionExercise;

ComboOrder.cs:24(组合单基类,引入 GroupOrderManager 管理多腿,Quantity 不是绝对数量而是"腿比例 × 组合总量"):

24 public abstract class ComboOrder : Order 34 public override decimal Quantity 36 get => _ratio.GetOrderLegGroupQuantity(GroupOrderManager).Normalize(); 40 internal set => _ratio = value.GetOrderLegRatio(GroupOrderManager);

💡 钻取要点:Order.IsMarketable(Order.cs:210)是个聪明属性——市价单与组合市价单永远可成交,限价单则要看"限价是否已穿越当前买卖盘"(买单 LimitPrice >= AskPrice、卖单 LimitPrice <= BidPrice)。这个判断用 OrderSubmissionData 记录的提交时刻报价,而不是实时报价,避免后续行情变化导致判断漂移。

四、下单便捷方法:QCAlgorithm.Trading

用户不直接 new Order,而是调 Algorithm/QCAlgorithm.Trading.cs 的便捷方法。最常用的是 MarketOrder(QCAlgorithm.Trading.cs:241):

241 public OrderTicket MarketOrder(Symbol symbol, decimal quantity, bool asynchronous = false, string tag = "", IOrderProperties orderProperties = null) 243 var security = GetSecurityForOrder(symbol); 246 if (security.Type != SecurityType.Future && security.Type != SecurityType.FutureOption) 250 if (!security.Exchange.ExchangeOpen) // 市场关闭 252 var mooTicket = MarketOnOpenOrder(security.Symbol, quantity, ...); // 自动转 MOO 258 return mooTicket; 268 if (!LiveMode && !security.Exchange.Hours.IsMarketAlwaysOpen && IsDailyResolutionOnly(security.Symbol)) // 仅日线订阅 270 var convertedTicket = IsWithinMarketOnCloseSubmissionBuffer(security) 271 ? MarketOnOpenOrder(...) // 接近收盘转 MOO 272 : MarketOnCloseOrder(...); // 否则转 MOC 283 var request = CreateSubmitOrderRequest(OrderType.Market, security, quantity, tag, orderProperties ?? DefaultOrderProperties?.Clone(), asynchronous); 286 var ticket = SubmitOrderRequest(request);

注意 250-258 行的智能转换:市场关闭时,市价单自动转成 MarketOnOpenOrder(避免成交在陈旧价);268-280 行:仅日线订阅时,市价单转成 MarketOnCloseOrder(避免成交在昨日收盘价)。这些"自动转换"是 Lean 体贴用户的细节。

Order(symbol, quantity)(QCAlgorithm.Trading.cs:180)是 MarketOrder 的别名:

180 public OrderTicket Order(Symbol symbol, decimal quantity) 182 return MarketOrder(symbol, quantity);

LimitOrder(QCAlgorithm.Trading.cs:473)与 StopMarketOrder(QCAlgorithm.Trading.cs:525)模式一致:取 security → CreateSubmitOrderRequestSubmitOrderRequest:

473 public OrderTicket LimitOrder(Symbol symbol, decimal quantity, decimal limitPrice, ...) 476 var request = CreateSubmitOrderRequest(OrderType.Limit, security, quantity, tag, 477 orderProperties ?? DefaultOrderProperties?.Clone(), asynchronous, limitPrice: limitPrice); 479 return SubmitOrderRequest(request); 525 public OrderTicket StopMarketOrder(Symbol symbol, decimal quantity, decimal stopPrice, ...) 528 var request = CreateSubmitOrderRequest(OrderType.StopMarket, security, quantity, tag, 529 orderProperties ?? DefaultOrderProperties?.Clone(), asynchronous, stopPrice: stopPrice); 531 return SubmitOrderRequest(request);

SetHoldings(QCAlgorithm.Trading.cs:1547)按"占总资产百分比"下单,内部先调 CalculateOrderQuantity 把百分比换算成绝对数量,再走市价链路:

1547 public List<OrderTicket> SetHoldings(Symbol symbol, decimal percentage, bool liquidateExistingHoldings = false, ...) 1549 return SetHoldingsImpl(symbol, CalculateOrderQuantity(symbol, percentage), liquidateExistingHoldings, asynchronous, tag, orderProperties);

💡 钻取要点:SetHoldings("AAPL", 0.1) 表示"把 AAPL 调仓到占总资产 10%";SetHoldings("AAPL", 2) 表示 2 倍杠杆满仓。它内部用 CalculateOrderQuantity 反算"还需要买卖多少股"(目标持仓 - 当前持仓),如果 liquidateExistingHoldings: true 还会先清空其他持仓。这是"目标仓位"语义,与 MarketOrder 的"增量数量"语义截然不同。

五、CreateSubmitOrderRequest 与 PreOrderChecks

所有便捷方法都汇聚到 CreateSubmitOrderRequest(QCAlgorithm.Trading.cs:1708)与 SubmitOrderRequest(QCAlgorithm.Trading.cs:1018):

1708 private SubmitOrderRequest CreateSubmitOrderRequest(OrderType orderType, Security security, decimal quantity, string tag, IOrderProperties properties, bool asynchronous, decimal stopPrice = 0m, decimal limitPrice = 0m, ...) 1712 return new SubmitOrderRequest(orderType, security.Type, security.Symbol, quantity, stopPrice, limitPrice, triggerPrice, trailingAmount, trailingAsPercentage, UtcTime, tag, properties, groupOrderManager, asynchronous); 1018 public OrderTicket SubmitOrderRequest(SubmitOrderRequest request) 1020 var response = PreOrderChecks(request); // 预检 1021 if (response.IsError) return OrderTicket.InvalidSubmitRequest(Transactions, request, response); 1027 return Transactions.AddOrder(request); // 进入事务管理器

PreOrderChecksImpl(QCAlgorithm.Trading.cs:1050)是下单的"安全阀":

1052 if (IsWarmingUp) return OrderResponse.WarmingUp(request); // 预热期禁下单 1060 if (!Securities.TryGetValue(request.Symbol, out security)) 1062 return OrderResponse.MissingSecurity(request); // 标的未订阅 1066 if (request.Quantity == 0) return OrderResponse.ZeroQuantity(request); // 数量为0 1071 if (Math.Abs(request.Quantity) < security.SymbolProperties.LotSize) 1073 return OrderResponse.Error(request, OrderResponseErrorCode.OrderQuantityLessThanLotSize, ...);

四道关卡:① 预热期(IsWarmingUp)② 标的已订阅 ③ 数量非零 ④ 数量不少于最小手数(LotSize)。任一不过直接返回错误票据,不进入事务管理器。通过后调 Transactions.AddOrder(request),由 SecurityTransactionManager 把请求交给第 3 章的 ITransactionHandler(回测走 BacktestingTransactionHandler,实盘走 BrokerageTransactionHandler)落地。

六、IOrderProperties 与 OrderTicket

OrderProperties.cs:24(订单属性,默认实现):

24 public class OrderProperties : IOrderProperties 29 public TimeInForce TimeInForce { get; set; } // 有效期(GTC/Day/GTD) 35 public Exchange Exchange { get; set; } // 交易所 42 TimeInForce = TimeInForce.GoodTilCanceled; // 默认 GTC

除了通用字段,每个券商都有专属属性类(InteractiveBrokersOrderPropertiesBinanceOrderPropertiesIndiaOrderProperties...),用来塞券商特殊参数(如 IB 的 OutsideRegularTradingHours、币安的 IsPostOnly)。订单通过 Order.Properties 持有它,TimeInForce 也挂在 Properties 上。

OrderTicket(OrderTicket.cs:29)是用户手里的"订单回执",实时跟踪订单状态:

29 public sealed class OrderTicket 53 public int OrderId { get => _submitRequest.OrderId; } 61 public OrderStatus Status { get => _order == null ? OrderStatus.New : _order.Status; } 98 public decimal AverageFillPrice { get => _fillState.AverageFillPrice; } // 平均成交价 110 public decimal QuantityFilled { get => _fillState.QuantityFilled; } // 已成交数量

Ticket 不是订单本身的拷贝,而是一个实时视图——它持有 _order 引用和 _fillState,订单在引擎内部状态变化时通过 Update(update) 同步刷新 Ticket。用户代码可以:ticket.Status 查状态、ticket.AverageFillPrice 查成交均价、ticket.Update(new UpdateOrderFields{ LimitPrice = ... }) 改单、ticket.Cancel() 撤单。QuantityFilled - SubmitRequest.Quantity 即剩余数量。

七、订单序列化与 OrderEvent

订单要持久化(结果文件)和跨进程传输(实盘 API),靠 OrderJsonConverterOrder 多态序列化成 JSON——type 字段标记子类,反序列化时按 type 走 CreateOrder 工厂。Serialization/SerializedOrderEvent.csOrderEvent 的可序列化投影(下节讲 OrderEvent)。

本节要点回顾

  1. Common/Orders:约 1.5 万行、80+ 文件,分订单类型/请求响应/票据事件/属性序列化四组,加 Fills/Fees/Slippage/TimeInForces/OptionExercise 五个子目录。
  2. Order 抽象基类:统一字段(Id/Symbol/Quantity/Status/Time/Properties/Direction),两个抽象成员 TypeClone,静态工厂 CreateOrder 按 OrderType 实例化子类。
  3. 八种订单类型:Market/Limit/StopMarket/StopLimit/TrailingStop/LimitIfTouched/MarketOnOpen/MarketOnClose/OptionExercise/ComboMarket/ComboLimit,各自只多专属字段。
  4. 下单链路:便捷方法(MarketOrder/LimitOrder/SetHoldings)→ CreateSubmitOrderRequestPreOrderChecksImpl(预热/订阅/数量/手数四关)→ Transactions.AddOrder → TransactionHandler。
  5. 智能转换:市场关闭时市价单自动转 MOO,仅日线订阅时转 MOC,避免成交在陈旧价。
  6. SetHoldings 是"目标百分比"语义,内部用 CalculateOrderQuantity 反算增量,与 MarketOrder 的"绝对数量"语义不同。
  7. IOrderProperties 携带 TimeInForce 与券商专属参数,默认 GTC。
  8. OrderTicket 是实时视图,跟踪 Status/AverageFillPrice/QuantityFilled,支持 Update/Cancel 操作。

下一节,我们钻进 Fills 子目录——ImmediateFillModel/FillModel/PartialFillModel 如何用历史 bar 算出成交价,以及 OrderEvent 成交事件与 TradeBuilder 交易构建器。


作者与出处
原作者: 灏天文库
整理: 灏天文库整理
本站整理收录,版权归原作者/开源协议所有;欢迎通过原文链接访问源仓库。
发布者: 作者: 灏天文库 转发
评论区 (0)
U