You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

将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 of smooth2 to sma_n1[index] instead of the first smoothed value smooth1[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_n1 calculation to reuse the precomputed sma_closeMinusSma1 value, 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.

火山引擎 最新活动