第 4 章 · 03 Trading/Universe/History/Indicators 各 partial 本节摘要:本节钻取主类之外的几个关键 partial 文件,把用户最常用的 API 一次讲清: (下单: / / / / / )、 (订阅: / / / / )、 (历史: 多重载/ / )、 (指标工厂: / / / / )、 ( / )、 (框架五段)。本节只给 API 地图与关键代码,下单撮合细节在第 7 章、指标内部在第 8 章、框架五段在第 9 章。 内容来源:原项目源码 (2000+ 行)、 、 (700+ 行)、 (3000+ 行)、 、 。 ⚠️ 注意:本节是 API 横扫,每个 partial 都值得单独深挖。
本节摘要:本节钻取主类之外的几个关键 partial 文件,把用户最常用的 API 一次讲清:
QCAlgorithm.Trading.cs(下单:SetHoldings/Order/MarketOrder/LimitOrder/StopMarketOrder/Liquidate)、QCAlgorithm.Universe.cs(订阅:AddEquity/AddForex/AddOption/AddFuture/AddCrypto)、QCAlgorithm.History.cs(历史:History<T>多重载/GetLastKnownPrices/WarmUpIndicator)、QCAlgorithm.Indicators.cs(指标工厂:SMA/EMA/RSI/MACD/Bollinger)、QCAlgorithm.Plotting.cs(Plot/AddChart)、QCAlgorithm.Framework.cs(框架五段)。本节只给 API 地图与关键代码,下单撮合细节在第 7 章、指标内部在第 8 章、框架五段在第 9 章。
内容来源:原项目源码
Algorithm/QCAlgorithm.Trading.cs(2000+ 行)、QCAlgorithm.Universe.cs、QCAlgorithm.History.cs(700+ 行)、QCAlgorithm.Indicators.cs(3000+ 行)、QCAlgorithm.Plotting.cs、QCAlgorithm.Framework.cs。
⚠️ 注意:本节是 API 横扫,每个 partial 都值得单独深挖。下单的具体撮合逻辑、指标的数学实现、框架五段的协作机制分别在后续章节展开,本节只看"用户视角"的 API 形态。
阅读完本节,你应当能够:
SetHoldings 与 MarketOrder 的区别(百分比再平衡 vs 绝对手数)。AddEquity/AddForex/AddOption/AddFuture/AddCrypto 订阅各类资产。History<T> 拉历史数据,知道有哪些常用重载。SMA/EMA/RSI 工厂方法建指标,知道框架会自动管理预热。SetAlpha/SetUniverseSelection/SetPortfolioConstruction/SetExecution/SetRiskManagement)的存在。Trading partial 提供两大类下单 API:百分比再平衡和绝对手数。绝对手数又分多种订单类型。
百分比再平衡 SetHoldings(QCAlgorithm.Trading.cs:1547):
1547 public List<OrderTicket> SetHoldings(Symbol symbol, decimal percentage, bool liquidateExistingHoldings = false, bool asynchronous = false, string tag = null, IOrderProperties orderProperties = null) 1548 { 1549 return SetHoldingsImpl(symbol, CalculateOrderQuantity(symbol, percentage), liquidateExistingHoldings, asynchronous, tag, orderProperties); 1550 }
percentage 是 0~1 的目标权重(可加杠杆 >1),内部 CalculateOrderQuantity 把权重换算成目标手数,再与现有持仓求差发市价单。SetHoldingsImpl 还做了"如果交易所未开盘则改发 MarketOnOpenOrder"的细节(L1586-1593)。
绝对手数订单族(节选,都是 [DocumentationAttribute(TradingAndOrders)]):
| 方法 | 行号 | 含义 |
|---|---|---|
Order(symbol, quantity) |
L196 | 通用下单,quantity 正买负卖 |
Buy(symbol, quantity) |
L80 | 买入(等价 Order 正数) |
Sell(symbol, quantity) |
L143 | 卖出(等价 Order 负数) |
MarketOrder(symbol, quantity) |
L241 | 市价单 |
LimitOrder(symbol, quantity, limitPrice) |
L473 | 限价单 |
StopMarketOrder(symbol, quantity, stopPrice) |
L525 | 止损市价单 |
StopLimitOrder(symbol, quantity, stopPrice, limitPrice) |
L711 | 止损限价单 |
TrailingStopOrder(...) |
L585 | 追踪止损单 |
MarketOnOpenOrder(...) |
L337 | 开市市价单 |
MarketOnCloseOrder(...) |
L388 | 收市市价单 |
LimitIfTouchedOrder(...) |
L769 | 触及限价单 |
每种都有 int/double/decimal 三套重载。Buy/Sell 都委托给 Order:Buy = Order(正数)、Sell = Order(负数)。
清仓 Liquidate(QCAlgorithm.Trading.cs:1325):
1325 public List<OrderTicket> Liquidate(Symbol symbol = null, bool asynchronous = false, string tag = null, IOrderProperties orderProperties = null)
不传 symbol 就清掉所有持仓;传 symbol 只清那一个。常用于"止损全平""月末清仓"。
💡 钻取要点:
SetHoldings是高层 API(用户算权重),MarketOrder是低层 API(用户算手数)。新用户用SetHoldings更不易错;精确控制手数/订单类型的策略(期权价差、配对交易)用低层。所有订单最终都进Transactions.AddOrder进入交易管理器(第 7 章)。
主类 QCAlgorithm.cs:2120 起提供各类资产的订阅方法,内部都委托给通用 AddSecurity<T>:
2120 public Equity AddEquity(string ticker, Resolution? resolution = null, string market = null, bool fillForward = true, decimal leverage = Security.NullLeverage, bool extendedMarketHours = false, DataNormalizationMode? dataNormalizationMode = null) 2121 { 2122 return AddSecurity<Equity>(SecurityType.Equity, ticker, resolution, market, fillForward, leverage, extendedMarketHours, normalizationMode: dataNormalizationMode); 2123 }
方法族(都在主类 QCAlgorithm.cs,universe 命名的 partial 主要管 Universe 概念对象):
| 方法 | 资产 | 示例 |
|---|---|---|
AddEquity("SPY", Resolution.Minute) |
美股 | SPY/AAPL |
AddForex("EURUSD") |
外汇 | EURUSD/USDJPY |
AddCfd("XAUUSD") |
差价合约 | 黄金/原油 |
AddOption("SPY") |
期权 | 美股期权链 |
AddFuture(Futures.Indices.SP500EMini) |
期货 | ES 期货 |
AddCrypto("BTCUSD") |
加密货币 | BTC/ETH |
AddIndex("SPX") |
指数 | SPX/VIX |
AddSecurity(symbol, resolution) |
通用 | Symbol 已知时 |
每个方法内部都会:1) 用 Symbol.Create 建 Symbol;2) 用 SecurityService 创建 Security 对象塞到 Securities;3) 把订阅配置塞到 SubscriptionManager。_locked 后再调会触发 DataManager 监听 UniverseManager 变化动态加订阅(第 5 章)。
💡 钻取要点:
fillForward: true(默认)是第 5 章讲的 Fill-Forward——缺失数据时用上一根填充,保证时间序列连续。extendedMarketHours: false(默认)只给盘中数据,设 true 才有盘前盘后。
History partial 提供 20+ 个重载,分三类返回类型:
// 1. 返回 IEnumerable<Slice> —— 与 OnData 收到的 Slice 同构,跨多 symbol 263 public IEnumerable<Slice> History(int periods, Resolution? resolution = null, ...) 487 public IEnumerable<TradeBar> History(Symbol symbol, int periods, ...) // 2. 返回 IEnumerable<DataDictionary<T>> —— 按 symbol 分组的强类型字典 411 public IEnumerable<DataDictionary<T>> History<T>(IEnumerable<Symbol> symbols, int periods, ...) // 3. 返回 IEnumerable<T> —— 单 symbol 单类型 546 public IEnumerable<T> History<T>(Symbol symbol, DateTime start, DateTime end, ...)
常用调用方式:
// 拉 SPY 最近 14 天日线 var bars = History<TradeBar>(_spy, 14, Resolution.Daily); // 拉多 symbol 最近 10 根分钟 bar var dicts = History<TradeBar>(new[] { spy, aapl }, 10, Resolution.Minute); // 拉 1 年 Slice(任意类型混在一起) var slices = History(TimeSpan.FromDays(365), Resolution.Daily);
GetLastKnownPrices(QCAlgorithm.History.cs:715):
715 public IEnumerable<BaseData> GetLastKnownPrices(Security security) 727 public IEnumerable<BaseData> GetLastKnownPrices(Symbol symbol)
返回"当前时刻之前最近的一条已知数据",用于初始化指标或决策需要最新价的场景。
WarmUpIndicator(QCAlgorithm.History.cs):用历史数据预热指标,让指标在回测开始时就已 ready(不用等 N 根 bar 才出第一个值)。常见用法 WarmUpIndicator(symbol, sma, Resolution.Daily)。
💡 钻取要点:History 不会触发 OnData——它是"主动查询",直接从磁盘/缓存读历史切片返回 IEnumerable。底层共用 DataFeed 的
IHistoryProvider(第 6 章)。
Indicators partial 是最大的 partial(3000+ 行,80+ 指标)。每个指标都是一个工厂方法,内部 new 指标对象 + InitializeIndicator(自动注册 Consolidator + 预热)。以 SMA 为例(QCAlgorithm.Indicators.cs:2195):
2195 public SimpleMovingAverage SMA(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, decimal> selector = null) 2196 { 2197 var name = CreateIndicatorName(symbol, $"SMA({period})", resolution); 2198 var simpleMovingAverage = new SimpleMovingAverage(name, period); 2199 InitializeIndicator(simpleMovingAverage, resolution, selector, symbol); 2200 return simpleMovingAverage; 2201 }
四步:1) 起名;2) new 指标对象;3) InitializeIndicator 自动注册到算法(绑定 Consolidator,数据来了自动更新);4) 返回。用户不需要手动喂数据,框架每个 Slice 自动更新。
常用指标工厂(全部 [DocumentationAttribute(Indicators)]):
| 工厂 | 类 | 行号 |
|---|---|---|
SMA(symbol, period) |
SimpleMovingAverage | L2195 |
EMA(symbol, period) |
ExponentialMovingAverage | L811 |
RSI(symbol, period) |
RelativeStrengthIndex | L1959 |
MACD(symbol, fast, slow, signal) |
MovingAverageConvergenceDivergence | L1398 |
BB(symbol, period, k) |
BollingerBands | L402 |
DEMA/TEMA/ZLEMA |
双/三/零滞后 EMA | L753/L2465/L3056 |
MOMERSION/CRSI/SRSI |
衍生 RSI | L1668/L640/L2062 |
RegisterIndicator(symbol, indicator, consolidator) 是手动注册的低层 API(工厂方法内部用)。指标对象本身在 QuantConnect.Indicators 命名空间,第 8 章详讲数学实现。
💡 钻取要点:工厂方法把"new 指标 + 注册 + 预热"打包,用户一行就能用。但理解底层
RegisterIndicator+ResolveConsolidator才能调试"为什么指标不更新"这类问题——通常是 Symbol/Resolution 没对上订阅。
Plotting(QCAlgorithm.Plotting.cs)极简:
56 public void AddChart(Chart chart) 68 public void Plot(string series, decimal value) 174 public void Plot(string chart, string series, decimal value)
Plot("My SMA", sma.Current.Value) 在图表上加一条线。AddChart 加自定义多 series 图表。Lean 默认会画"Strategy Equity"和"Daily Benchmark"两条,用户 Plot 的会追加。
Framework(QCAlgorithm.Framework.cs)提供框架五段的 setter:
271 public void SetUniverseSelection(IUniverseSelectionModel universeSelection) 307 public void SetAlpha(IAlphaModel alpha) 343 public void SetPortfolioConstruction(IPortfolioConstructionModel portfolioConstruction) 354 public void SetExecution(IExecutionModel execution) 365 public void SetRiskManagement(IRiskManagementModel riskManagement)
这是 Lean 的"框架模式"——把策略拆成五段:选股(Alpha)→ 选宇宙(UniverseSelection)→ 组合构建(PortfolioConstruction)→ 执行(Execution)→ 风险管理(RiskManagement)。每段实现一个接口,框架协调它们生成 Insight → 目标持仓 → 订单。第 9 章详讲。不用框架也能写策略(像 BasicTemplateAlgorithm 那样直接 SetHoldings),框架是为复杂多标的策略准备的模块化方案。
主类构造函数里默认装了五个 Null 实现(QCAlgorithm.cs:246-250):NullAlphaModel/NullPortfolioConstructionModel/ImmediateExecutionModel/NullRiskManagementModel/NullUniverseSelectionModel,确保不用框架时也不报错。
SetHoldings(百分比再平衡,高层)vs MarketOrder/LimitOrder/StopMarketOrder(绝对手数,低层),Liquidate 清仓,十几种订单类型都有 int/double/decimal 重载。AddEquity/AddForex/AddOption/AddFuture/AddCrypto 等订阅各类资产,内部都委托 AddSecurity<T>,默认 fillForward=true。Slice/DataDictionary<T>/T 三类;GetLastKnownPrices 拿最新已知;WarmUpIndicator 预热指标。Plot/AddChart 极简绘图。SetAlpha/SetUniverseSelection/SetPortfolioConstruction/SetExecution/SetRiskManagement),第 9 章详讲。下一章,我们钻取第 5 层——数据流与时间同步。QCAlgorithm 的 OnData 收到的 Slice 是怎么从磁盘/实时源一步步合成出来的,DataFeed/Synchronizer/TimeSlice 的生产者消费者链全程拆解。