protected override void OnCalculate(bool fullRecalculation, DataBarUpdateType?updateType) { if (fullRecalculation) { double[] values1 = DataProvider.GetValuesAsDouble(_dataSource, 0, DataProvider.BarCount); Results.AddSetValues("Volume", 0, values1.Length, true, values1); } else { // How many steps to overlap for safety. int overlap = Math.Max(0, Math.Min(5, Results.SetLength - 1)); if (Results.SetLength > DataProvider.BarCount) {// This happens sometimes and causes exception. Results.ClipTo(DataProvider.BarCount); return; } int startIndex = Math.Max(0, Results.SetLength - overlap); int count = DataProvider.BarCount - startIndex; double[] values1 = DataProvider.GetValuesAsDouble(_dataSource, startIndex, count); Results.AddSetValues("Volume", startIndex, count, true, values1); } }
/// <summary> /// /// </summary> protected void PerformCalculation(object[] parametersArray, int beginIdxPosition, int actualStartingIndex) { // This is how the normal call looks like: // TicTacTec.TA.Library.Core.Adx((int)parameters[0], (int)parameters[1], (double[])parameters[2], // (double[])parameters[3], (double[])parameters[4], (int)parameters[5], // out outBeginIdx, out outNBElemenet, (double[])parameters[8]); TicTacTec.TA.Library.Core.RetCode code = (TicTacTec.TA.Library.Core.RetCode) _methodInfo.Invoke(null, parametersArray); int outBeginIdx = (int)parametersArray[beginIdxPosition]; int outNBElement = (int)parametersArray[beginIdxPosition + 1]; lock (this) { for (int i = 0; outNBElement > 0 && i < _outputArraysParameters.Count; i++) { int index = beginIdxPosition + 2 + i; if (parametersArray[index].GetType() == typeof(double[])) {// Double output. Results.AddSetValues(_outputArraysParameters[i].Name, actualStartingIndex + outBeginIdx, outNBElement, true, (double[])parametersArray[index]); } else if (parametersArray[index].GetType() == typeof(int[])) {// Int output. Results.AddSetValues(_outputArraysParameters[i].Name, actualStartingIndex + outBeginIdx, outNBElement, true, GeneralHelper.IntsToDoubles((int[])parametersArray[index])); } } } }
protected override void OnCalculate(bool fullRecalculation, DataBarUpdateType?updateType) { double[] values1, values2; int startingIndex = 0; int indecesCount = DataProvider.BarCount - 1; if (UseOpenClose) { values1 = DataProvider.GetValuesAsDouble(DataBar.DataValueEnum.Open, startingIndex, indecesCount); values2 = DataProvider.GetValuesAsDouble(DataBar.DataValueEnum.Close, startingIndex, indecesCount); } else { values1 = DataProvider.GetValuesAsDouble(DataBar.DataValueEnum.High, startingIndex, indecesCount); values2 = DataProvider.GetValuesAsDouble(DataBar.DataValueEnum.Low, startingIndex, indecesCount); } System.Diagnostics.Debug.Assert(values1.Length == values2.Length); if (indecesCount == 0) { Results.AddSetValues("ZigZag", startingIndex, indecesCount, true, new double[] { }); return; } // This is simple indicator, it can directly write to the signals array. double[] signals = new double[indecesCount]; signals[0] = (double)ZigZagStates.PeakHigh; int lastPeakIndex = 0; ZigZagStates lastPeakState = ZigZagStates.PeakHigh; // Perform actual calculation. for (int i = 0; i < values1.Length; i++) { double requiredDifferenceValue = (SignificancePercentage / 100) * values1[i]; double high = Math.Max(values1[i], values2[i]); double low = Math.Min(values1[i], values2[i]); double lastPeakValue = 0; if (lastPeakState == ZigZagStates.PeakHigh) { lastPeakValue = Math.Max(values1[lastPeakIndex], values2[lastPeakIndex]); } else if (lastPeakState == ZigZagStates.PeakLow) { lastPeakValue = Math.Min(values1[lastPeakIndex], values2[lastPeakIndex]); } bool newLow = (lastPeakState == ZigZagStates.PeakHigh && (lastPeakValue - low >= requiredDifferenceValue)) || (lastPeakState == ZigZagStates.PeakLow && low < lastPeakValue); bool newHigh = (lastPeakState == ZigZagStates.PeakLow && (high - lastPeakValue >= requiredDifferenceValue)) || (lastPeakState == ZigZagStates.PeakHigh && high > lastPeakValue); //System.Diagnostics.Debug.Assert(newLow == false || newHigh == false); if (newLow && newHigh) {// Favor the extension of existing peak in this case. if (lastPeakState == ZigZagStates.PeakHigh) { newLow = false; } else { newHigh = false; } } if (newHigh) { if (lastPeakState == ZigZagStates.PeakHigh) {// Update the high. signals[lastPeakIndex] = (double)ZigZagStates.Default; } else if (lastPeakState == ZigZagStates.PeakLow) {// New high found. lastPeakState = ZigZagStates.PeakHigh; } else { System.Diagnostics.Debug.Fail("Unexpected case."); } lastPeakIndex = i; signals[i] = (double)ZigZagStates.PeakHigh; } else if (newLow) { if (lastPeakState == ZigZagStates.PeakLow) {// Update the low. signals[lastPeakIndex] = (double)ZigZagStates.Default; } else if (lastPeakState == ZigZagStates.PeakHigh) {// New low found. lastPeakState = ZigZagStates.PeakLow; } lastPeakIndex = i; signals[lastPeakIndex] = (double)ZigZagStates.PeakLow; } } // Finish with a signal. if (signals[signals.Length - 1] == (double)ZigZagStates.Default) { if (lastPeakState == ZigZagStates.PeakHigh) { signals[signals.Length - 1] = (double)ZigZagStates.PeakLow; } else { signals[signals.Length - 1] = (double)ZigZagStates.PeakHigh; } } // Finally create the results, that shows a line moving between the peak values - like a proper ZigZag indicator. lastPeakIndex = 0; lastPeakState = ZigZagStates.PeakHigh; double[] results = new double[indecesCount]; for (int i = 1; i < signals.Length; i++) { if (signals[i] != (double)ZigZagStates.Default) { double lastPeakValue, currentPeakValue; if (lastPeakState == ZigZagStates.PeakHigh) { lastPeakValue = Math.Max(values1[lastPeakIndex], values2[lastPeakIndex]); currentPeakValue = Math.Min(values1[i], values2[i]); } else { lastPeakValue = Math.Min(values1[lastPeakIndex], values2[lastPeakIndex]); currentPeakValue = Math.Max(values1[i], values2[i]); } double[] midValues = MathHelper.CreateConnectionValues(lastPeakValue, currentPeakValue, i - lastPeakIndex); midValues.CopyTo(results, lastPeakIndex); lastPeakIndex = i; lastPeakState = (ZigZagStates)signals[i]; } } Results.AddSetValues("ZigZag", startingIndex, indecesCount - 1, true, results); // Only after we add the operationResult set, the signals become available. Signals.Signals = signals; }