/// <summary> /// Called on each bar update event (incoming tick) /// </summary> protected override void OnCalculate() { int temp_signal_value = 0; double actualhigh = High[0]; double actuallow = Low[0]; if (this.Type == enum_swingray_type.open) { actualhigh = Open[0]; actuallow = Open[0]; } else if (this.Type == enum_swingray_type.close) { actualhigh = Close[0]; actuallow = Close[0]; } // build up cache of recent High and Low values // code devised from default Swing Indicator by marqui@BMT, 10-NOV-2010 lastHighCache.Add(actualhigh); if (lastHighCache.Count > (2 * strength) + 1) { lastHighCache.RemoveAt(0); // if cache is filled, drop the oldest value } lastLowCache.Add(actuallow); if (lastLowCache.Count > (2 * strength) + 1) { lastLowCache.RemoveAt(0); } // if (lastHighCache.Count == (2 * strength) + 1) // wait for cache of Highs to be filled { // test for swing high bool isSwingHigh = true; double swingHighCandidateValue = (double)lastHighCache[strength]; for (int i = 0; i < strength; i++) { if ((double)lastHighCache[i] >= swingHighCandidateValue - double.Epsilon) { isSwingHigh = false; // bar(s) to right of candidate were higher } } for (int i = strength + 1; i < lastHighCache.Count; i++) { if ((double)lastHighCache[i] > swingHighCandidateValue - double.Epsilon) { isSwingHigh = false; // bar(s) to left of candidate were higher } } // end of test if (isSwingHigh) { lastSwingHighValue = swingHighCandidateValue; } if (isSwingHigh) // if we have a new swing high then we draw a ray line on the chart { AddChartRay("highRay" + (ProcessingBarIndex - strength), false, strength, lastSwingHighValue, 0, lastSwingHighValue, swingHighColor, DashStyle.Solid, 1); RayObject newRayObject = new RayObject("highRay" + (ProcessingBarIndex - strength), strength, lastSwingHighValue, 0, lastSwingHighValue); swingHighRays.Push(newRayObject); // store a reference so we can remove it from the chart later } else if (actualhigh > lastSwingHighValue) // otherwise, we test to see if price has broken through prior swing high { if (swingHighRays.Count > 0) // just to be safe { //IRay currentRay = (IRay)swingHighRays.Pop(); // pull current ray from stack RayObject currentRay = (RayObject)swingHighRays.Pop(); // pull current ray from stack if (currentRay != null) { if (enableAlerts) { ShowAlert("Swing High at " + currentRay.Y1 + " broken", GlobalUtilities.GetSoundfile(this.Soundfile)); } temp_signal_value = 1; if (keepBrokenLines) // draw a line between swing point and break bar { int barsAgo = currentRay.BarsAgo1; ITrendLine newLine = AddChartLine("highLine" + (ProcessingBarIndex - barsAgo), false, barsAgo, currentRay.Y1, 0, currentRay.Y1, swingHighColor, DashStyle.Dot, 2); } RemoveChartDrawing(currentRay.Tag); if (swingHighRays.Count > 0) { //IRay priorRay = (IRay)swingHighRays.Peek(); RayObject priorRay = (RayObject)swingHighRays.Peek(); lastSwingHighValue = priorRay.Y1; // needed when testing the break of the next swing high } else { lastSwingHighValue = double.MaxValue; // there are no higher swings on the chart; reset to default } } } } } if (lastLowCache.Count == (2 * strength) + 1) // repeat the above for the swing lows { // test for swing low bool isSwingLow = true; double swingLowCandidateValue = (double)lastLowCache[strength]; for (int i = 0; i < strength; i++) { if ((double)lastLowCache[i] <= swingLowCandidateValue + double.Epsilon) { isSwingLow = false; // bar(s) to right of candidate were lower } } for (int i = strength + 1; i < lastLowCache.Count; i++) { if ((double)lastLowCache[i] < swingLowCandidateValue + double.Epsilon) { isSwingLow = false; // bar(s) to left of candidate were lower } } // end of test for low if (isSwingLow) { lastSwingLowValue = swingLowCandidateValue; } if (isSwingLow) // found a new swing low; draw it on the chart { AddChartRay("lowRay" + (ProcessingBarIndex - strength), false, strength, lastSwingLowValue, 0, lastSwingLowValue, swingLowColor, DashStyle.Solid, 1); RayObject newRayObject = new RayObject("lowRay" + (ProcessingBarIndex - strength), strength, lastSwingLowValue, 0, lastSwingLowValue); swingLowRays.Push(newRayObject); } else if (actuallow < lastSwingLowValue) // otherwise test to see if price has broken through prior swing low { if (swingLowRays.Count > 0) { //IRay currentRay = (IRay)swingLowRays.Pop(); RayObject currentRay = (RayObject)swingLowRays.Pop(); if (currentRay != null) { if (enableAlerts) { ShowAlert("Swing Low at " + currentRay.Y1 + " broken", GlobalUtilities.GetSoundfile(this.Soundfile)); } temp_signal_value = -1; if (keepBrokenLines) // draw a line between swing point and break bar { int barsAgo = currentRay.BarsAgo1; ITrendLine newLine = AddChartLine("highLine" + (ProcessingBarIndex - barsAgo), false, barsAgo, currentRay.Y1, 0, currentRay.Y1, swingLowColor, DashStyle.Dot, 2); } RemoveChartDrawing(currentRay.Tag); if (swingLowRays.Count > 0) { //IRay priorRay = (IRay)swingLowRays.Peek(); RayObject priorRay = (RayObject)swingLowRays.Peek(); lastSwingLowValue = priorRay.Y1; // price level of the prior swing low } else { lastSwingLowValue = double.MinValue; // no swing lows present; set this to default value } } } } } if (enablesignalline) { SignalLine.Set(temp_signal_value); } else { this.SwingHighs.Set(lastSwingHighValue); this.SwingLows.Set(lastSwingLowValue); this.PriceLines.Set(InSeries[0]); } //Set the color PlotColors[0][0] = this.Signal; OutputDescriptors[0].PenStyle = DashStyle.Solid; OutputDescriptors[0].Pen.Width = this.Plot0Width; PlotColors[1][0] = this.swingHighColor; OutputDescriptors[1].PenStyle = DashStyle.Solid; OutputDescriptors[1].Pen.Width = this.Plot0Width; PlotColors[2][0] = this.swingLowColor; OutputDescriptors[2].PenStyle = DashStyle.Solid; OutputDescriptors[2].Pen.Width = this.Plot0Width; PlotColors[3][0] = this.Signal; OutputDescriptors[3].PenStyle = DashStyle.Solid; OutputDescriptors[3].Pen.Width = this.Plot0Width; }