将BigBeluga Two Pole Oscillator Pine脚本转换为cTrader C#指标后曲线不平滑的问题排查求助
专家回答
Answer
The jagged curve issue stems from critical errors in your two-pole filter implementation—you're not correctly applying the recursive smoothing logic that makes the original indicator's output smooth. Here's the breakdown and fixed code:
1. Core Errors Identified
- Broken Recursive Smoothing: You used the current index's unassigned
smooth1[index]/smooth2[index]values in the smoothing formula, which skips the recursive smoothing entirely. This results in a raw, unfiltered signal that looks jagged. - Incorrect Initial Value for
smooth2: You set the initial value ofsmooth2tosma_n1[index]instead of the first smoothed valuesmooth1[index], breaking the second pass of filtering.
2. Fixed Indicator Code
Here's the corrected version with key fixes highlighted:
using cAlgo.API; using cAlgo.API.Indicators; using cAlgo.API.Internals; namespace cAlgo.Indicators { [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.FullAccess)] public class TwoPoleOscillator : Indicator { [Parameter("Filter Length", DefaultValue = 20, MinValue = 1)] public int length { get; set; } // === OUTPUTS === [Output("two_p", LineColor = "#55ffda", Thickness = 1)] public IndicatorDataSeries two_p { get; set; } [Output("two_pp")] public IndicatorDataSeries two_pp { get; set; } [Output("buy", PlotType = PlotType.Points, LineColor = "#55ffda", Thickness = 3)] public IndicatorDataSeries buy_plot { get; set; } [Output("sell", PlotType = PlotType.Points, LineColor = "#8c5bff", Thickness = 3)] public IndicatorDataSeries sell_plot { get; set; } // === SERIES === private IndicatorDataSeries sma_n1; private IndicatorDataSeries sma_closeMinusSma1; private IndicatorDataSeries smooth1; private IndicatorDataSeries smooth2; private SimpleMovingAverage sma1; private SimpleMovingAverage sma_norm; private StandardDeviation stdev_norm; protected override void Initialize() { #if DEBUG var result = System.Diagnostics.Debugger.Launch(); #endif sma_n1 = CreateDataSeries(); sma_closeMinusSma1 = CreateDataSeries(); smooth1 = CreateDataSeries(); smooth2 = CreateDataSeries(); sma1 = Indicators.SimpleMovingAverage(Bars.ClosePrices, 25); sma_norm = Indicators.SimpleMovingAverage(sma_closeMinusSma1, 25); stdev_norm = Indicators.StandardDeviation(sma_closeMinusSma1, 25, MovingAverageType.Simple); } public override void Calculate(int index) { // Skip early bars where 25-period SMA/STD has no valid data if (index < 25) { sma_closeMinusSma1[index] = double.NaN; sma_n1[index] = double.NaN; smooth1[index] = double.NaN; smooth2[index] = double.NaN; two_p[index] = double.NaN; two_pp[index] = double.NaN; return; } // === CALCULATIONS === sma_closeMinusSma1[index] = Bars.ClosePrices[index] - sma1.Result[index]; // Simplify: Reuse precomputed value to avoid redundant calculations sma_n1[index] = (sma_closeMinusSma1[index] - sma_norm.Result[index]) / stdev_norm.Result[index]; // === TWO-POLE FILTER (FIXED) === double alpha = 2.0 / (length + 1); // First pass smoothing: use lagged smooth1 value for recursive filtering if (double.IsNaN(smooth1[index - 1])) smooth1[index] = sma_n1[index]; else smooth1[index] = (1 - alpha) * smooth1[index - 1] + alpha * sma_n1[index]; // Second pass smoothing: use lagged smooth2 value and current smooth1 value if (double.IsNaN(smooth2[index - 1])) smooth2[index] = smooth1[index]; else smooth2[index] = (1 - alpha) * smooth2[index - 1] + alpha * smooth1[index]; two_p[index] = smooth2[index]; two_pp[index] = index >= 4 ? two_p[index - 4] : double.NaN; // === SIGNALS === bool buy = index > 4 && two_p[index - 1] < two_pp[index - 1] && two_p[index] > two_pp[index] && two_p[index] < 0; bool sell = index > 4 && two_p[index - 1] > two_pp[index - 1] && two_p[index] < two_pp[index] && two_p[index] > 0; buy_plot[index] = buy ? two_p[index] : double.NaN; sell_plot[index] = sell ? two_p[index] : double.NaN; } } }
3. Additional Improvements
- Added a check to skip early bars (index < 25) where 25-period SMA/STD indicators don't have valid data, preventing NaN/infinite values.
- Simplified the
sma_n1calculation to reuse the precomputedsma_closeMinusSma1value, reducing redundant computations. - Fixed the recursive smoothing logic to use lagged values (
smooth1[index-1]/smooth2[index-1]) for proper filtering.
With these fixes, your indicator should produce the same smooth, fluid curves as the original Pine Script version.




