第 7 章 · 01 Indicators 项目与指标基类


文档摘要

第 7 章 · 01 Indicators 项目与指标基类 本节摘要:本节钻取 Lean 的第 7 层——Indicators 项目(约 3.1 万行、231 个 .cs 文件、166+ 个指标)。从 AbsolutePriceOscillator 绝对价格振荡、BollingerBands 布林带、MACD、RSI,到 ConnorsRSI、CoppockCurve、ChandeKrollStop,覆盖趋势/动量/波动/成交量/统计五大类;另有 CandlestickPatterns 子目录收录 Doji 十字星、Hammer 锤子、ShootingStar 流星、Engulfing 吞没等 K 线形态,识别后返回 CandlestickPattern。

第 7 章 · 01 Indicators 项目与指标基类

本节摘要:本节钻取 Lean 的第 7 层——Indicators 项目(约 3.1 万行、231 个 .cs 文件、166+ 个指标)。从 AbsolutePriceOscillator 绝对价格振荡、BollingerBands 布林带、MACD、RSI,到 ConnorsRSI、CoppockCurve、ChandeKrollStop,覆盖趋势/动量/波动/成交量/统计五大类;另有 CandlestickPatterns 子目录收录 Doji 十字星、Hammer 锤子、ShootingStar 流星、Engulfing 吞没等 K 线形态,识别后返回 CandlestickPattern。统一基类是 IndicatorBase<T>,核心机制是 Update(input)——接收一个数据点,内部更新状态,返回当前值;IsReady 判断窗口是否填满。指标分 DataPoint 型(只吃单一价 close)和 Bar 型(吃 OHLCV 的 TradeBar/QuoteBar),由 Consolidator 聚合器把高频数据聚成低频再喂指标。读完本节,你掌握了 Lean 指标体系的骨架与 Update 机制。

内容来源:原项目源码 Indicators/IndicatorBase.csBarIndicator.csIndicator.csRelativeStrengthIndex.csCandlestickPatterns/CandlestickPattern.cs,以及 Indicators 目录结构,精读并套用体系化模板。

⚠️ 注意:本节聚焦指标基类与 Update 机制(怎么手动 new 指标 + Update),便捷工厂方法(SMA/EMA 一行创建)在下一节。

学习目标

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

  1. 认识 Indicators 项目的 166+ 指标与五大分类。
  2. 读懂 IndicatorBase<T>Update(input) 机制。
  3. 区分 DataPoint 型(Indicator)与 Bar 型(BarIndicator)。
  4. 解释 IsReady 与 WarmUpPeriod 的判满逻辑。
  5. 理解 Consolidator 如何把数据喂给指标。
  6. 说出 CandlestickPatterns 子目录的形态识别返回值。

一、Indicators 项目:166+ 指标的家

Indicators/ 下一级有 166 个 .cs 文件(加上 CandlestickPatterns 子目录共 231 个),按功能粗分:

分类 代表指标
趋势 SimpleMovingAverage / ExponentialMovingAverage / DoubleExponentialMovingAverage / HullMovingAverage / KaufmanAdaptiveMovingAverage / ArnaudLegouxMovingAverage / MACD / IchimokuKinkoHyo
动量 RelativeStrengthIndex / Momentum / RateOfChange / CommodityChannelIndex / ChandeMomentumOscillator / ConnorsRelativeStrengthIndex / CoppockCurve / WilliamsPercentR / AwesomeOscillator
波动 BollingerBands / AverageTrueRange / StandardDeviation / DonchianChannel / KeltnerChannels / ChandeKrollStop / ChoppinessIndex / MassIndex
成交量 Volume / OnBalanceVolume / AccumulationDistribution / ChaikinMoneyFlow / MoneyFlowIndex / ForceIndex / KlingerVolumeOscillator / ArmsIndex
统计/其他 Beta / Alpha / Correlation / Covariance / HurstExponent / LogReturn / LeastSquaresMovingAverage / AugenPriceSprite / AutoRegressiveIntegratedMovingAverage

文件名即指标名,一目了然。CompositeIndicator.cs 支持指标间的加减乘除组合(见下一节 IndicatorExtensions)。

二、IndicatorBase:统一基类

Indicators/IndicatorBase.cs:28(非泛型基类,放公共字段):

28 public abstract partial class IndicatorBase : WindowBase<IndicatorDataPoint>, IIndicator 35 public ISet<IDataConsolidator> Consolidators { get; } // 关联的聚合器(便于反注册) 41 public override IndicatorDataPoint Previous { get; } // 上一个值 46 public string Name { get; protected set; } 51 public long Samples { get; internal set; } // 已处理样本数 56 public abstract bool IsReady { get; } // 是否就绪 61 public event IndicatorUpdatedHandler Updated; // 更新事件 101 public abstract bool Update(IBaseData input); // 喂数据的入口

IndicatorBase.cs:164(泛型基类,带输入类型):

164 public abstract class IndicatorBase<T> : IndicatorBase 165 where T : IBaseData 186 public override bool Update(IBaseData input) 273 protected abstract decimal ComputeNextValue(T input); // 子类实现:算下一个值

核心抽象就两个:

  • Update(input):外部喂一个数据点进来。
  • ComputeNextValue(input):子类实现的"怎么算"。

基类 Update 做通用工作:防重复、防倒序(191-197 行的 forward-only 检查)、计 Samples、调子类 ComputeNextValue、写 Current、触发 Updated 事件。

三、Update 机制:数据进来 → 算新值

Indicators/IndicatorBase.cs:186 完整逻辑:

186 public override bool Update(IBaseData input) 188 T _previousSymbolInput = default(T); 189 if (_previousInput.TryGetValue(input.Symbol.ID, out _previousSymbolInput) 189 && input.EndTime < _previousSymbolInput.EndTime) 191 if (!_loggedForwardOnlyIndicatorError) 193 _loggedForwardOnlyIndicatorError = true; 195 Log.Error($"...This is a forward only indicator..."); // 倒序拒绝 197 return IsReady; 199 if (!ReferenceEquals(input, _previousSymbolInput)) 202 Samples++; // 计数 204 if (!(input is T)) 206 if (typeof(T) == typeof(IndicatorDataPoint)) 208 input = new IndicatorDataPoint(input.Symbol, input.EndTime, input.Value); // 自动装箱 215 _previousInput[input.Symbol.ID] = (T)input; 217 var nextResult = ValidateAndComputeNextValue((T)input); 218 if (nextResult.Status == IndicatorStatus.Success) 220 Current = new IndicatorDataPoint(input.Symbol, input.EndTime, nextResult.Value); 223 OnUpdated(Current); // 触发事件 226 return IsReady;

四步:

  1. 防倒序:Lean 指标是 forward-only,收到比上次更早的数据直接拒绝(避免EMA等递推指标算错)。
  2. 防重复:同一对象引用不重复处理。
  3. 类型适配:若输入不是 T 但 T 是 IndicatorDataPoint,自动把 input 装箱成 IndicatorDataPoint(这样 SMA 收 TradeBar 时自动取 Value)。
  4. 算值 + 触发事件:调 ComputeNextValue,成功就更新 Current 并 fire Updated。

💡 钻取要点:_previousInput 是按 Symbol.ID 存的字典——支持一个指标被多个标的的 Updated 事件级联喂入(IndicatorExtensions 组合时常见)。每个标的独立维护"上次时间",互不干扰。

四、DataPoint 型 vs Bar 型

指标按输入类型分两大族:

Indicators/Indicator.cs:22:

22 public abstract class Indicator : IndicatorBase<IndicatorDataPoint>

Indicators/BarIndicator.cs:25:

25 public abstract class BarIndicator : IndicatorBase<IBaseDataBar>
  • DataPoint 型(Indicator):只吃一个标量值(通常是 close)。代表:SMA、EMA、RSI、MACD、Momentum。
  • Bar 型(BarIndicator):吃完整的 OHLCV bar(实现 IBaseDataBar,即 TradeBar/QuoteBar)。代表:AverageTrueRange(用 HLC)、BollingerBands(用 close 但也接受 bar)、BalanceOfPower(用 OHLC)。

TradeBar/QuoteBar 都实现 IBaseDataBar,所以 Bar 型指标两者都能吃。DataPoint 型指标靠基类的自动装箱(206-208 行)也能吃 bar——它只取 input.Value(即收盘价)。

五、IsReady 与 WarmUpPeriod:就绪判断

IndicatorBase.cs:56:

56 public abstract bool IsReady { get; } // 窗口是否填满

每个指标自己定义 IsReady。看 RSI(Indicators/RelativeStrengthIndex.cs:71):

71 public override bool IsReady => AverageGain.IsReady && AverageLoss.IsReady; 76 public int WarmUpPeriod { get; } // period + 1

RSI 内部由 AverageGain/AverageLoss 两个子指标组成,IsReady 就是两者都 IsReady。WarmUpPeriod(来自 IIndicatorWarmUpPeriodProvider)告诉引擎"至少喂多少个点才 ready"——RSI(14) 的 WarmUpPeriod 是 15。

策略里典型写法:

if (!_rsi.IsReady) return; // 还没攒够 15 根,不算信号不下单 var value = _rsi.Current.Value;

这和 vnpy 的 am.inited 机制(攒够 100 根)是同一思想,只是 Lean 用 IsReady 精确到每个指标自己的周期。

六、ComputeNextValue:子类怎么算

RelativeStrengthIndex.cs:83:

83 protected override decimal ComputeNextValue(IndicatorDataPoint input) 85 if (_previousInput != null && input.Value >= _previousInput.Value) 87 AverageGain.Update(input.EndTime, input.Value - _previousInput.Value); // 涨幅 88 AverageLoss.Update(input.EndTime, 0m); 90 else if (_previousInput != null && input.Value < _previousInput.Value) 92 AverageGain.Update(input.EndTime, 0m); 93 AverageLoss.Update(input.EndTime, _previousInput.Value - input.Value); // 跌幅 96 _previousInput = input; 98 // 防负值(某些 MA 如 DEMA 可能算出负) 100 var averageLoss = AverageLoss < 0 ? 0 : AverageLoss.Current.Value; 101 var averageGain = AverageGain < 0 ? 0 : AverageGain.Current.Value;

RSI 的算法:逐根比较当前价与上一价,涨了把涨幅喂给 AverageGain、跌幅喂给 AverageLoss,最后 100 - 100/(1 + avgGain/avgLoss)。注意它复用了 AverageGain/AverageLoss 两个子指标——Lean 的指标是可组合的,大指标由小指标拼装。

七、Consolidator:把数据喂给指标

指标通常不要 tick 级噪声,要分钟/小时 bar。Consolidator(聚合器)负责把高频数据聚成低频 bar,再喂给指标:

典型手动用法:

var sma = new SimpleMovingAverage(14); var consolidator = new TradeBarConsolidator(TimeSpan.FromMinutes(1)); consolidator.DataConsolidated += (sender, bar) => sma.Update(bar); // 数据流接入 consolidator 后,每分钟一根 bar 喂给 sma

IndicatorBase.Consolidators(35 行)就是用来保存指标关联的 consolidator 引用,方便后续 Unregister(反注册时连同 consolidator 一起拆)。下一节讲的便捷方法 SMA(symbol, 14) 会自动完成这整套接线。

八、CandlestickPatterns:K 线形态子目录

Indicators/CandlestickPatterns/ 下约 60 个形态:Doji(十字星)、Hammer(锤子)、ShootingStar(流星)、Engulfing(吞没)、Harami(孕线)、MorningStar(晨星)、EveningStar(暮星)、ThreeWhiteSoldiers(三白兵)等。

CandlestickPatterns/CandlestickPattern.cs:25(基类,继承 BarIndicator):

25 public abstract class CandlestickPattern : BarIndicator 31 protected CandlestickPattern(string name, int period) : base(name, period) 40 protected static CandleColor GetCandleColor(IBaseDataBar tradeBar) 42 return tradeBar.Close >= tradeBar.Open ? CandleColor.White : CandleColor.Black; 49 protected static decimal GetRealBody(IBaseDataBar tradeBar) 52 return Math.Abs(tradeBar.Close - tradeBar.Open); // 实体 58 protected static decimal GetHighLowRange(IBaseDataBar tradeBar) 60 return tradeBar.High - tradeBar.Low; // 全距

形态识别都基于实体的几个几何量:RealBody(实体)、HighLowRange(全距)、UpperShadow/LowerShadow(上下影线)。识别成功返回 CandlestickPattern(值 > 0 表示看涨形态,< 0 看跌,= 0 不匹配),它本身也是 Indicator,可以塞进策略链路。

💡 钻取要点:K 线形态本质是"模式匹配"指标——输入 TradeBar,输出"是否匹配某形态 + 强度"。Lean 用 talib 风格的 C 函数移植,形态定义参数(实体阈值、影线比例)集中在 CandleSettings,可全局调整。

本节要点回顾

  1. Indicators 项目:约 3.1 万行、231 个 .cs、166+ 指标,分趋势/动量/波动/成交量/统计五类。
  2. IndicatorBase 是统一基类,核心是 Update(input) + 子类 ComputeNextValue(input)
  3. Update 机制:防倒序、防重复、自动装箱、算值、触发 Updated 事件。
  4. DataPoint 型(Indicator) 吃单一价(close),Bar 型(BarIndicator) 吃 OHLCV bar。
  5. IsReady 各指标自定义(RSI = AverageGain && AverageLoss 都 ready);WarmUpPeriod 告诉引擎最小样本数。
  6. 指标可组合:RSI 由 AverageGain/AverageLoss 子指标拼装,大指标套小指标。
  7. Consolidator 把高频聚成低频 bar 再喂指标,IndicatorBase.Consolidators 保存引用便于反注册。
  8. CandlestickPatterns 子目录 60+ 形态,继承 BarIndicator,基于 RealBody/Shadow 几何量识别,返回 CandlestickPattern(正看涨/负看跌)。

下一节,我们看 QCAlgorithm.Indicators.cs——一行 SMA("SPY", 14) 如何自动创建指标、注册 consolidator、预热,极大降低使用门槛。


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