Help: indicator plots different on historical data and in backtesting!

Created at 12 May 2024, 15:23
How’s your experience with the cTrader Platform?
Your feedback is crucial to cTrader's development. Please take a few seconds to share your opinion and help us improve your trading experience. Thanks!
DR

DR.SHADI_JARRAR

Joined 02.05.2024

Help: indicator plots different on historical data and in backtesting!
12 May 2024, 15:23


I made an indicator that looks perfectly as intended in the chart,, but when I play backtesting( wtith a cbot that is based on it) it plots in a different way! I hope anybody can help with this ??  Here is pics of the indicator on the chart with and without backtesting: 

notice the yellow curve of the indicator:now see it in backtesting:


@DR.SHADI_JARRAR
Replies

PanagiotisCharalampous
13 May 2024, 06:12

Hi there,

It looks like a logical bug in your code. Share your indicator code in case somebody can have a look and spot it.

Best regards,

Panagiotis


@PanagiotisCharalampous

DR.SHADI_JARRAR
13 May 2024, 08:57 ( Updated at: 13 May 2024, 10:13 )

RE: Help: indicator plots different on historical data and in backtesting!

PanagiotisCharalampous said: 

Hi there,

It looks like a logical bug in your code. Share your indicator code in case somebody can have a look and spot it.

Best regards,

Panagiotis

thank for your reply .. here is the indicators code: 

using System;
using cAlgo.API;
using cAlgo.API.Internals;
using cAlgo.API.Indicators;
using cAlgo.Indicators;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class DoubleLagEMA : Indicator
    {
        [Parameter("Period", DefaultValue = 3)]
        public int Period { get; set; }

        [Parameter("EMA Period", DefaultValue = 100)]
        public int EMAPeriod { get; set; }

        [Parameter("Rlagema Period", DefaultValue = 60)]
        public int RlagemaPeriod { get; set; }

        [Parameter("Smoothing Period", DefaultValue = 30)]
        public int SmoothingPeriod { get; set; }

        [Parameter("Factor", DefaultValue = 10)]
        public int Factor { get; set; }

        [Output("DLagEMAs", LineColor = "DodgerBlue")]
        public IndicatorDataSeries DLagEMAs { get; set; }

        [Output("Rlagema", LineColor = "Red")]
        public IndicatorDataSeries Rlagema { get; set; }

        [Output("Smooth", LineColor = "Yellow")]
        public IndicatorDataSeries sr { get; set; }

        private ExponentialMovingAverage _ema1;
        private ExponentialMovingAverage _ema2;
        private MovingAverage smoothenedRlagema;
        private MovingAverage _emaRlagema;
        private int barsSinceEvent = 0;
        private AverageTrueRange atr;

        protected override void Initialize()
        {
            _ema1 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, Period);
            _ema2 = Indicators.ExponentialMovingAverage(_ema1.Result, EMAPeriod);
            smoothenedRlagema = Indicators.MovingAverage(Rlagema, SmoothingPeriod, MovingAverageType.Exponential);
            _emaRlagema = Indicators.MovingAverage(Bars.OpenPrices, RlagemaPeriod, MovingAverageType.Exponential);
            atr = Indicators.AverageTrueRange(1000, MovingAverageType.Exponential);
        }

        public override void Calculate(int index)
        {
            DLagEMAs[index] = _ema2.Result[index] + _ema2.Result[index] - _ema1.Result[index];

            if ((Bars.ClosePrices[index] > DLagEMAs[index] && Bars.ClosePrices[index - 1] < DLagEMAs[index - 1]) ||
               (Bars.ClosePrices[index] < DLagEMAs[index] && Bars.ClosePrices[index - 1] > DLagEMAs[index - 1]))
            {
                barsSinceEvent = 0;
            }
            else
            {
                barsSinceEvent++;
            }

            if (barsSinceEvent > Factor * 5)
            {
                barsSinceEvent = Factor * 5;
            }

            var difference2 = Bars.OpenPrices[index] - _emaRlagema.Result[index];
            Rlagema[index] = Bars.OpenPrices[index] + difference2;

            if (Bars.ClosePrices[index] > DLagEMAs[index])
            {
                sr[index] = smoothenedRlagema.Result[index] + atr.Result[index] * (Factor - barsSinceEvent * 0.2);
            }
            else if (Bars.ClosePrices[index] < DLagEMAs[index])
            {
                sr[index] = smoothenedRlagema.Result[index] - atr.Result[index] * (Factor - barsSinceEvent * 0.2);
            }
            else 
            {
                sr[index] = smoothenedRlagema.Result[index];
            }

        }
    }
}

 

 

 

 

and here is the robots code:

 

 

 

 

using System;
using cAlgo.API;
using cAlgo.API.Indicators;

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class DoubleLagEMARobot : Robot
    {
        private DoubleLagEMA _doubleLagEMA;
        private const double LotSize = 0.1;

        protected override void OnStart()
        {
            _doubleLagEMA = Indicators.GetIndicator<DoubleLagEMA>(3, 100, 60, 30, 10);
            
        }

        protected override void OnBar()
        {             int index = Bars.ClosePrices.Count - 1;

            // Closing previous sell position and opening new buy position if the previous bar closes above and the bar before it closes below Dlagemas
            if (Bars.ClosePrices[index-1] < _doubleLagEMA.DLagEMAs[index-1] && Bars.ClosePrices[index] > _doubleLagEMA.DLagEMAs[index])
            {
                CloseSellPositions();
                ExecuteMarketOrder(TradeType.Buy, Symbol, LotSize, "Buy");
            }
            // Closing previous buy position and opening new sell position if the previous bar closes below and the bar before it closes above Dlagemas
            else if (Bars.ClosePrices[index-1] > _doubleLagEMA.DLagEMAs[index-1] && Bars.ClosePrices[index] < _doubleLagEMA.DLagEMAs[index])
            {
                CloseBuyPositions();
                ExecuteMarketOrder(TradeType.Sell, Symbol, LotSize, "Sell");
            }
        }

        protected override void OnTick()
        {  int index = Bars.ClosePrices.Count - 1;
            // Closing all buy positions if high price rises above sr and sr is higher than Dlagemas
            if (Symbol.Bid > _doubleLagEMA.sr[index] && _doubleLagEMA.sr[index] > _doubleLagEMA.DLagEMAs[index])
            {
                CloseBuyPositions();
            }

            // Closing all sell positions if low price drops below sr and sr is lower than Dlagemas
            if (Symbol.Ask < _doubleLagEMA.sr[index] && _doubleLagEMA.sr[index] < _doubleLagEMA.DLagEMAs[index])
            {
                CloseSellPositions();
            }
        }

        private void CloseBuyPositions()
        {
            foreach (var position in Positions.FindAll("Buy", Symbol, TradeType.Buy))
            {
                ClosePosition(position);
            }
        }

        private void CloseSellPositions()
        {
            foreach (var position in Positions.FindAll("Sell", Symbol, TradeType.Sell))
            {
                ClosePosition(position);
            }
        }
    }
}


@DR.SHADI_JARRAR

PanagiotisCharalampous
13 May 2024, 10:27

Hi there,

Calculate() method is called once per bar for historical bars and once per tick for live bars. The part below will behave differently when the method is called once per bar, compared to once per tick

            if ((Bars.ClosePrices[index] > DLagEMAs[index] && Bars.ClosePrices[index - 1] < DLagEMAs[index - 1]) ||
               (Bars.ClosePrices[index] < DLagEMAs[index] && Bars.ClosePrices[index - 1] > DLagEMAs[index - 1]))
            {
                barsSinceEvent = 0;
            }
            else
            {
                barsSinceEvent++;
            }

You need to rethink your logic and make sure this part is called only once for each bar.

Best regards,

Panagiotis


@PanagiotisCharalampous

DR.SHADI_JARRAR
13 May 2024, 18:33

RE: Help: indicator plots different on historical data and in backtesting!

PanagiotisCharalampous said: 

Hi there,

Calculate() method is called once per bar for historical bars and once per tick for live bars. The part below will behave differently when the method is called once per bar, compared to once per tick

            if ((Bars.ClosePrices[index] > DLagEMAs[index] && Bars.ClosePrices[index - 1] < DLagEMAs[index - 1]) ||               (Bars.ClosePrices[index] < DLagEMAs[index] && Bars.ClosePrices[index - 1] > DLagEMAs[index - 1]))            {                barsSinceEvent = 0;            }            else            {                barsSinceEvent++;            }

You need to rethink your logic and make sure this part is called only once for each bar.

Best regards,

Panagiotis

Thanks for your response, I really did my best several ways but couldnt solve it yet, can you suggest anyway to do it!


@DR.SHADI_JARRAR

PanagiotisCharalampous
14 May 2024, 05:41

RE: RE: Help: indicator plots different on historical data and in backtesting!

DR.SHADI_JARRAR said: 

PanagiotisCharalampous said: 

Hi there,

Calculate() method is called once per bar for historical bars and once per tick for live bars. The part below will behave differently when the method is called once per bar, compared to once per tick

            if ((Bars.ClosePrices[index] > DLagEMAs[index] && Bars.ClosePrices[index - 1] < DLagEMAs[index - 1]) ||               (Bars.ClosePrices[index] < DLagEMAs[index] && Bars.ClosePrices[index - 1] > DLagEMAs[index - 1]))            {                barsSinceEvent = 0;            }            else            {                barsSinceEvent++;            }

You need to rethink your logic and make sure this part is called only once for each bar.

Best regards,

Panagiotis

Thanks for your response, I really did my best several ways but couldnt solve it yet, can you suggest anyway to do it!

You can use a parameter that registers at which index the last addition was made and not call that part of the code until the index changes.


@PanagiotisCharalampous