/// <summary> /// the Holt trend-adjusted EMA [email protected] /// </summary> /// <returns></returns> public HoltEMA HoltEMA(Data.IDataSeries input, double alpha, double gamma) { if (cacheHoltEMA != null) { for (int idx = 0; idx < cacheHoltEMA.Length; idx++) { if (Math.Abs(cacheHoltEMA[idx].Alpha - alpha) <= double.Epsilon && Math.Abs(cacheHoltEMA[idx].Gamma - gamma) <= double.Epsilon && cacheHoltEMA[idx].EqualsInput(input)) { return(cacheHoltEMA[idx]); } } } lock (checkHoltEMA) { checkHoltEMA.Alpha = alpha; alpha = checkHoltEMA.Alpha; checkHoltEMA.Gamma = gamma; gamma = checkHoltEMA.Gamma; if (cacheHoltEMA != null) { for (int idx = 0; idx < cacheHoltEMA.Length; idx++) { if (Math.Abs(cacheHoltEMA[idx].Alpha - alpha) <= double.Epsilon && Math.Abs(cacheHoltEMA[idx].Gamma - gamma) <= double.Epsilon && cacheHoltEMA[idx].EqualsInput(input)) { return(cacheHoltEMA[idx]); } } } HoltEMA indicator = new HoltEMA(); indicator.BarsRequired = BarsRequired; indicator.CalculateOnBarClose = CalculateOnBarClose; #if NT7 indicator.ForceMaximumBarsLookBack256 = ForceMaximumBarsLookBack256; indicator.MaximumBarsLookBack = MaximumBarsLookBack; #endif indicator.Input = input; indicator.Alpha = alpha; indicator.Gamma = gamma; Indicators.Add(indicator); indicator.SetUp(); HoltEMA[] tmp = new HoltEMA[cacheHoltEMA == null ? 1 : cacheHoltEMA.Length + 1]; if (cacheHoltEMA != null) { cacheHoltEMA.CopyTo(tmp, 0); } tmp[tmp.Length - 1] = indicator; cacheHoltEMA = tmp; return(indicator); } }
/// <summary> /// Called on each bar update event (incoming tick) /// </summary> protected override void OnBarUpdate() { // http://www2.gsu.edu/~dscthw/8110/Chapter8.pdf double alpha = 2.0 / (1 + Period); double gamma = 2.0 / (1 + TrendPeriod); if (CurrentBar == 0) { HoltEMA.Set(Input[0]); trend.Set(0.0); return; } double holt = alpha * Input[0] + (1 - alpha) * (HoltEMA[1] + trend[1]); HoltEMA.Set(holt); trend.Set(gamma * (holt - HoltEMA[1]) + (1 - gamma) * trend[1]); }