Unit CCI; { The formula comes from: http://www.stockcharts.com/education/IndicatorAnalysis/indic_CCI.html } Interface Uses GenericDataNodes; Function CreateCCiFactory(Minutes : Integer; Bars : Integer = 20) : IGenericDataNodeFactory; Implementation Uses DataNodes, StandardCandles, StandardPlaceHolders, DebugOutput, Math, SysUtils; Type TCCI = Class(TGenericDataNode) Private CandleData : TStandardCandles; FValid : Boolean; FBarCount : Integer; FValue : Double; PreviousEpoch : Cardinal; Procedure VerifyCurrent; Public Function IsValid : Boolean; Override; Protected Constructor Create(Params : TParamList); Override; Published Function GetDouble : Double; Override; End; Procedure TCCI.VerifyCurrent; Function TypicalPrice(Const Candle : TSingleCandle) : Double; Begin { TypicalPrice } Result := (Candle.High + Candle.Low + Candle.Close) / 3.0 End; { TypicalPrice } Var Candles : TCandleArray; I : Integer; LastTypicalPrice, SMATP, MeanDeviation : Double; Begin { TCCI.VerifyCurrent } SetLength(Candles, 0); // Silly compiler warning. If PreviousEpoch <> CandleData.Epoch Then Begin PreviousEpoch := CandleData.Epoch; FValid := False; FValue := 0.0; Try Candles := CandleData.GetHistory; If (Length(Candles) >= FBarCount) Then Begin LastTypicalPrice := TypicalPrice(Candles[Pred(Length(Candles))]); SMATP := LastTypicalPrice; For I := Length(Candles) - FBarCount To Length(Candles) - 2 Do SMATP := SMATP + TypicalPrice(Candles[I]); SMATP := SMATP / FBarCount; MeanDeviation := 0; For I := Length(Candles) - FBarCount To Pred(Length(Candles)) Do MeanDeviation := MeanDeviation + Abs(TypicalPrice(Candles[I]) - SMATP); MeanDeviation := MeanDeviation / FBarCount; FValue := (LastTypicalPrice - SMATP) / 0.015 / MeanDeviation; FValid := True End Except On Ex : Exception Do DebugOutputWindow.AddMessage(Ex, 'TCCI.VerifyCurrent') End End End; { TCCI.VerifyCurrent } Function TCCI.IsValid : Boolean; Begin VerifyCurrent; Result := FValid End; Function TCCI.GetDouble : Double; Begin VerifyCurrent; Result := FValue End; Constructor TCCI.Create(Params : TParamList); Var Symbol : String; MinutesPerBar : Integer; Link : TDataNodeLink; Begin Assert(Length(Params)=3, 'Expected params: (Symbol, Minutes/Bar, Bars)'); Symbol := Params[0]; MinutesPerBar := Params[1]; FBarCount := Params[2]; Assert(FBarCount > 2); Inherited Create; TStandardCandles.Find(Symbol, MinutesPerBar, NotifyListeners, CandleData, Link); AddAutoLink(Link) End; Function CreateCciFactory(Minutes, Bars : Integer) : IGenericDataNodeFactory; Begin Result := TGenericDataNodeFactory.CreateWithArgs(TCCI, StandardSymbolPlaceholder, Minutes, Bars) End; Initialization TGenericDataNodeFactory.StoreFactory('CCI3', CreateCCIFactory(3)); End.