LAZY LOADING REVISITED ....

Created at 22 Feb 2022, 15:49
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!
BJ

BJORNBERNAU

Joined 21.07.2020

LAZY LOADING REVISITED ....
22 Feb 2022, 15:49


For quite a long time now, I've tried to solve this problem with 'lazy loading', that is said from some in the community to be an easy one. 

I have constructed a really easy code to alternate between a sell (SELL) and a liquidation (LIQ) signal from an Indicator. But the Robot then clusters them together in blocks instead of alternating in-between them, as can be seen far below. 

I hereby submit the codes for both programs and hope to receive "the easy" solution, after weeks of trials to try to overcome these 'basics'. 

It would be extremely helpful if i could get clear guidance to this issue and maybe it should be included in your guide for programming, since I believe that a lot of traders have been stuck with this issue for hundreds of hours, needlessly. 

 

Sincerely, 

 

Björn Bernau 

 

**********************

 

     namespace cAlgo

{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SELL_LIQ : Indicator
    {

        ////  SELL SIGNAL  ////


        [Output("sell_ONE", PlotType = PlotType.Points, LineColor = "#B511F7", Thickness = 4)]
        public IndicatorDataSeries sell_ONE { get; set; }

        [Output("liq_ONE", PlotType = PlotType.Points, LineColor = "#FF7CFC00", Thickness = 4)]
        public IndicatorDataSeries liq_ONE { get; set; }


        ////   BOLLINGER    //// 

        [Parameter("Source")]
        public DataSeries Source { get; set; }

        [Parameter("BandPeriods", DefaultValue = 16)]
        public int BandPeriod { get; set; }

        [Parameter("Std", DefaultValue = 1.6)]
        public double std { get; set; }

        [Parameter("MAType")]
        public MovingAverageType MAType { get; set; }


        private BollingerBands boll;


        protected override void Initialize()
        {
            boll = Indicators.BollingerBands(Source, BandPeriod, std, MAType);
        }

        int HIGHstartCountIndexZERO = 0;
        double d = double.NaN;


        public override void Calculate(int index)
        {
            liquidator(index);
        }

        private void liquidator(int index)
        {



            var high = 0;


            double high0 = Bars.HighPrices[index - 0];
            double high1 = Bars.HighPrices[index - 1];
            double high2 = Bars.HighPrices[index - 2];
            double high3 = Bars.HighPrices[index - 3];
            double high4 = Bars.HighPrices[index - 4];
            double close0 = Bars.ClosePrices[index - 0];

            var BBT2 = boll.Top[index - 2];


            if (high4 <= high2)
                if (high3 <= high2)
                    if (high2 > BBT2)
                        if (high2 >= high1)
                            if (high2 >= close0)
                            {
                                high = 1;
                            }

            if (high == 1)
            {
                HIGHstartCountIndexZERO += 1;
            }



            if (high == 0)
            {
                sell_ONE[index - 0] = d;
            }

            if (high == 0)
            {
                liq_ONE[index - 0] = d;
            }



            if (high == 1)
                if (HIGHstartCountIndexZERO % 2 != 0)
                {
                    sell_ONE[index - 0] = Bars.HighPrices[index - 0];
                }


            if (high == 1)
                if (HIGHstartCountIndexZERO % 2 == 0)
                {
                    liq_ONE[index - 0] = Bars.HighPrices[index - 0];
                }

        }
    }
}

 

**************

 

 

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SELL_LIQ_220220 : Robot
    {

        ////////////////////////////////////
        /////   TRADING PARAMETERS    //////
        ////////////////////////////////////

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

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

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


        ////////////////////////////
        ////   INITIAL PARAM    //// 

        [Parameter("Source")]
        public DataSeries Source { get; set; }

        [Parameter("BandPeriods", DefaultValue = 16)]
        public int BandPeriod { get; set; }

        [Parameter("Std", DefaultValue = 1.6)]
        public double std { get; set; }

        [Parameter("MAType")]
        public MovingAverageType MAType { get; set; }


        //////////////////////////////
        ////       LITTERALS      //// 

        [Parameter("littFACTOR", DefaultValue = 5)]
        public double littFACTOR { get; set; }

        private SELL_LIQ S2;

        protected override void OnStart()
        {
            S2 = Indicators.GetIndicator<SELL_LIQ>(Source, BandPeriod, std, MAType);
        }

        protected override void OnBar()
        {

            var a = S2.sell_ONE.Last(0);
            var b = S2.liq_ONE.Last(0);

            if (!double.IsNaN(S2.sell_ONE.Last(0)) == true)
            {
                Print("SELL    ", Bars.Count, "      ", S2.sell_ONE);
            }

            if (!double.IsNaN(S2.liq_ONE.Last(0)) == true)
            {
                Print("LIQ    ", Bars.Count, "      ", S2.liq_ONE);
            }
        }
    }
}

 

BLOCK-wise clustering of results 

 

22/02/2022 00:59:00.000 | Backtesting finished
21/02/2022 11:00:00.000 | LIQ    639      IndicatorDataSeries (Count: 639, LastValue: 1,13634)
21/02/2022 06:00:00.000 | LIQ    634      IndicatorDataSeries (Count: 634, LastValue: 1,13621)
18/02/2022 12:00:00.000 | LIQ    616      IndicatorDataSeries (Count: 616, LastValue: 1,13611)
16/02/2022 22:00:00.000 | LIQ    578      IndicatorDataSeries (Count: 578, LastValue: 1,13821)
16/02/2022 11:00:00.000 | LIQ    567      IndicatorDataSeries (Count: 567, LastValue: 1,13775)
15/02/2022 19:00:00.000 | LIQ    551      IndicatorDataSeries (Count: 551, LastValue: 1,13586)
15/02/2022 16:00:00.000 | LIQ    548      IndicatorDataSeries (Count: 548, LastValue: 1,1322)
15/02/2022 13:00:00.000 | LIQ    545      IndicatorDataSeries (Count: 545, LastValue: 1,13459)
11/02/2022 19:00:00.000 | LIQ    503      IndicatorDataSeries (Count: 503, LastValue: 1,13966)
11/02/2022 16:00:00.000 | LIQ    500      IndicatorDataSeries (Count: 500, LastValue: 1,13888)
10/02/2022 19:00:00.000 | LIQ    479      IndicatorDataSeries (Count: 479, LastValue: 1,14645)
10/02/2022 16:00:00.000 | SELL    476      IndicatorDataSeries (Count: 476, LastValue: 1,14074)
10/02/2022 12:00:00.000 | SELL    472      IndicatorDataSeries (Count: 472, LastValue: 1,14359)
09/02/2022 20:00:00.000 | SELL    456      IndicatorDataSeries (Count: 456, LastValue: 1,14326)
09/02/2022 16:00:00.000 | SELL    452      IndicatorDataSeries (Count: 452, LastValue: 1,14317)
09/02/2022 13:00:00.000 | SELL    449      IndicatorDataSeries (Count: 449, LastValue: 1,14295)
09/02/2022 06:00:00.000 | SELL    442      IndicatorDataSeries (Count: 442, LastValue: 1,14269)
07/02/2022 19:00:00.000 | SELL    407      IndicatorDataSeries (Count: 407, LastValue: 1,14186)
07/02/2022 15:00:00.000 | SELL    403      IndicatorDataSeries (Count: 403, LastValue: 1,14398)
04/02/2022 14:00:00.000 | SELL    378      IndicatorDataSeries (Count: 378, LastValue: 1,14655)
04/02/2022 10:00:00.000 | SELL    374      IndicatorDataSeries (Count: 374, LastValue: 1,14602)
03/02/2022 19:00:00.000 | SELL    359      IndicatorDataSeries (Count: 359, LastValue: 1,14436)
02/02/2022 16:00:00.000 | SELL    332      IndicatorDataSeries (Count: 332, LastValue: 1,13048)
01/02/2022 14:00:00.000 | SELL    306      IndicatorDataSeries (Count: 306, LastValue: 1,12617)
01/02/2022 11:00:00.000 | SELL    303      IndicatorDataSeries (Count: 303, LastValue: 1,12614)
31/01/2022 22:00:00.000 | SELL    290      IndicatorDataSeries (Count: 290, LastValue: 1,12354)
31/01/2022 18:00:00.000 | LIQ    286      IndicatorDataSeries (Count: 286, LastValue: 1,12101)
31/01/2022 11:00:00.000 | LIQ    279      IndicatorDataSeries (Count: 279, LastValue: 1,11747)
28/01/2022 17:00:00.000 | LIQ    261      IndicatorDataSeries (Count: 261, LastValue: 1,11643)
24/01/2022 21:00:00.000 | LIQ    169      IndicatorDataSeries (Count: 169, LastValue: 1,13198)
21/01/2022 17:00:00.000 | LIQ    141      IndicatorDataSeries (Count: 141, LastValue: 1,1346)
21/01/2022 12:00:00.000 | LIQ    136      IndicatorDataSeries (Count: 136, LastValue: 1,13391)
21/01/2022 01:00:00.000 | Backtesting started
 


@BJORNBERNAU
Replies

PanagiotisCharalampous
22 Feb 2022, 17:20

Hi Bjorn,

Your problem has nothing to do with lazy loading. Instead this happens because of a poorly programmed indicator. You problem is here.

   if (high == 1)
            {
                HIGHstartCountIndexZERO += 1;
            }

You cannot do this since the Calculate is called many times during a current candle's life. It is clearly described here. This variable will just produce nonsense. What you actually need to do is to keep the state of the last selection. Here is a very rough solution. The code is still poor but I do not have the time to rewrite the entire indicator. It's just an example of how you need to handle this

            if (Bars.OpenTimes[index] != _lastBarOpenTime)
            {
                _lastBarOpenTime = Bars.OpenTimes[index];
                if (!double.IsNaN(sell_ONE.Last(1)))
                {
                    isBuy = true;
                }
                if (!double.IsNaN(liq_ONE.Last(1)))
                {
                    isBuy = false;
                }
            }

Here is the full source code

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

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SELL_LIQ : Indicator
    {
        ////  SELL SIGNAL  ////

        [Output("sell_ONE", PlotType = PlotType.Points, LineColor = "#B511F7", Thickness = 4)]
        public IndicatorDataSeries sell_ONE { get; set; }

        [Output("liq_ONE", PlotType = PlotType.Points, LineColor = "#FF7CFC00", Thickness = 4)]
        public IndicatorDataSeries liq_ONE { get; set; }

        ////   BOLLINGER    ////

        [Parameter("Source")]
        public DataSeries Source { get; set; }

        [Parameter("BandPeriods", DefaultValue = 16)]
        public int BandPeriod { get; set; }

        [Parameter("Std", DefaultValue = 1.6)]
        public double std { get; set; }

        [Parameter("MAType")]
        public MovingAverageType MAType { get; set; }

        private BollingerBands boll;
        private bool isBuy;

        protected override void Initialize()
        {
            boll = Indicators.BollingerBands(Source, BandPeriod, std, MAType);
        }

        private int HIGHstartCountIndexZERO = 0;
        private double d = double.NaN;
        private DateTime _lastBarOpenTime;

        public override void Calculate(int index)
        {
            liquidator(index);
        }

        private void liquidator(int index)
        {
            if (Bars.OpenTimes[index] != _lastBarOpenTime)
            {
                _lastBarOpenTime = Bars.OpenTimes[index];
                if (!double.IsNaN(sell_ONE.Last(1)))
                {
                    isBuy = true;
                }
                if (!double.IsNaN(liq_ONE.Last(1)))
                {
                    isBuy = false;
                }
            }

            var high = 0;

            double high0 = Bars.HighPrices[index - 0];
            double high1 = Bars.HighPrices[index - 1];
            double high2 = Bars.HighPrices[index - 2];
            double high3 = Bars.HighPrices[index - 3];
            double high4 = Bars.HighPrices[index - 4];
            double close0 = Bars.ClosePrices[index - 0];

            var BBT2 = boll.Top[index - 2];

            if (high4 <= high2)
                if (high3 <= high2)
                    if (high2 > BBT2)
                        if (high2 >= high1)
                            if (high2 >= close0)
                            {
                                high = 1;
                            }

            if (high == 0)
            {
                sell_ONE[index - 0] = d;
            }

            if (high == 0)
            {
                liq_ONE[index - 0] = d;
            }

            if (high == 1)
                if (!isBuy)
                {
                    sell_ONE[index - 0] = Bars.HighPrices[index - 0];
                }

            if (high == 1)
                if (isBuy)
                {
                    liq_ONE[index - 0] = Bars.HighPrices[index - 0];
                }
        }
    }
}

and here are the results

Best Regards,

Panagiotis 

Join us on Telegram and Facebook


@PanagiotisCharalampous

BJORNBERNAU
25 Feb 2022, 12:01 ( Updated at: 21 Dec 2023, 09:22 )

RE:

PanagiotisCharalampous said:

Hi Bjorn,

Your problem has nothing to do with lazy loading. Instead this happens because of a poorly programmed indicator. You problem is here.

   if (high == 1)
            {
                HIGHstartCountIndexZERO += 1;
            }

You cannot do this since the Calculate is called many times during a current candle's life. It is clearly described here. This variable will just produce nonsense. What you actually need to do is to keep the state of the last selection. Here is a very rough solution. The code is still poor but I do not have the time to rewrite the entire indicator. It's just an example of how you need to handle this

            if (Bars.OpenTimes[index] != _lastBarOpenTime)
            {
                _lastBarOpenTime = Bars.OpenTimes[index];
                if (!double.IsNaN(sell_ONE.Last(1)))
                {
                    isBuy = true;
                }
                if (!double.IsNaN(liq_ONE.Last(1)))
                {
                    isBuy = false;
                }
            }

Here is the full source code

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

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SELL_LIQ : Indicator
    {
        ////  SELL SIGNAL  ////

        [Output("sell_ONE", PlotType = PlotType.Points, LineColor = "#B511F7", Thickness = 4)]
        public IndicatorDataSeries sell_ONE { get; set; }

        [Output("liq_ONE", PlotType = PlotType.Points, LineColor = "#FF7CFC00", Thickness = 4)]
        public IndicatorDataSeries liq_ONE { get; set; }

        ////   BOLLINGER    ////

        [Parameter("Source")]
        public DataSeries Source { get; set; }

        [Parameter("BandPeriods", DefaultValue = 16)]
        public int BandPeriod { get; set; }

        [Parameter("Std", DefaultValue = 1.6)]
        public double std { get; set; }

        [Parameter("MAType")]
        public MovingAverageType MAType { get; set; }

        private BollingerBands boll;
        private bool isBuy;

        protected override void Initialize()
        {
            boll = Indicators.BollingerBands(Source, BandPeriod, std, MAType);
        }

        private int HIGHstartCountIndexZERO = 0;
        private double d = double.NaN;
        private DateTime _lastBarOpenTime;

        public override void Calculate(int index)
        {
            liquidator(index);
        }

        private void liquidator(int index)
        {
            if (Bars.OpenTimes[index] != _lastBarOpenTime)
            {
                _lastBarOpenTime = Bars.OpenTimes[index];
                if (!double.IsNaN(sell_ONE.Last(1)))
                {
                    isBuy = true;
                }
                if (!double.IsNaN(liq_ONE.Last(1)))
                {
                    isBuy = false;
                }
            }

            var high = 0;

            double high0 = Bars.HighPrices[index - 0];
            double high1 = Bars.HighPrices[index - 1];
            double high2 = Bars.HighPrices[index - 2];
            double high3 = Bars.HighPrices[index - 3];
            double high4 = Bars.HighPrices[index - 4];
            double close0 = Bars.ClosePrices[index - 0];

            var BBT2 = boll.Top[index - 2];

            if (high4 <= high2)
                if (high3 <= high2)
                    if (high2 > BBT2)
                        if (high2 >= high1)
                            if (high2 >= close0)
                            {
                                high = 1;
                            }

            if (high == 0)
            {
                sell_ONE[index - 0] = d;
            }

            if (high == 0)
            {
                liq_ONE[index - 0] = d;
            }

            if (high == 1)
                if (!isBuy)
                {
                    sell_ONE[index - 0] = Bars.HighPrices[index - 0];
                }

            if (high == 1)
                if (isBuy)
                {
                    liq_ONE[index - 0] = Bars.HighPrices[index - 0];
                }
        }
    }
}

and here are the results

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

No go, I'm sorry to say. 

The code you've revised gives the exact same result. 

Liquidation, despite no liquidation signal. 

Here is again the indicator and robot code, so we there is no doubt. 

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 sell_liq_panaBASE : Indicator
    {

        /////////////////////////////////////////////
        /////////////////////////////////////////////
        /////////////////////////////////////////////
        /////////////////////////////////////////////
        /////////////////////////////////////////////

        //////////////   22-02-25   /////////////////

        /////////////////////////////////////////////
        /////////////////////////////////////////////
        /////////////////////////////////////////////
        /////////////////////////////////////////////
        /////////////////////////////////////////////

        ////  SELL SIGNAL  ////

        [Output("sell_ONE", PlotType = PlotType.Points, LineColor = "#B511F7", Thickness = 4)]
        public IndicatorDataSeries sell_ONE { get; set; }

        [Output("liq_ONE", PlotType = PlotType.Points, LineColor = "#FF7CFC00", Thickness = 4)]
        public IndicatorDataSeries liq_ONE { get; set; }

        ////   BOLLINGER    ////

        [Parameter("Source")]
        public DataSeries Source { get; set; }

        [Parameter("BandPeriods", DefaultValue = 16)]
        public int BandPeriod { get; set; }

        [Parameter("Std", DefaultValue = 1.6)]
        public double std { get; set; }

        [Parameter("MAType")]
        public MovingAverageType MAType { get; set; }

        private BollingerBands boll;
        private bool isBuy;

        protected override void Initialize()
        {
            boll = Indicators.BollingerBands(Source, BandPeriod, std, MAType);
        }

        //   private int HIGHstartCountIndexZERO = 0;
        private double d = double.NaN;
        private DateTime _lastBarOpenTime;

        public override void Calculate(int index)
        {
            liquidator(index);
        }

        private void liquidator(int index)
        {
            if (Bars.OpenTimes[index] != _lastBarOpenTime)
            {
                _lastBarOpenTime = Bars.OpenTimes[index];
                if (!double.IsNaN(sell_ONE.Last(1)))
                {
                    isBuy = true;
                }
                if (!double.IsNaN(liq_ONE.Last(1)))
                {
                    isBuy = false;
                }
            }

            var high = 0;

            double high0 = Bars.HighPrices[index - 0];
            double high1 = Bars.HighPrices[index - 1];
            double high2 = Bars.HighPrices[index - 2];
            double high3 = Bars.HighPrices[index - 3];
            double high4 = Bars.HighPrices[index - 4];
            double close0 = Bars.ClosePrices[index - 0];

            var BBT2 = boll.Top[index - 2];

            if (high4 <= high2)
                if (high3 <= high2)
                    if (high2 > BBT2)
                        if (high2 >= high1)
                            if (high2 >= close0)
                            {
                                high = 1;
                            }

            if (high == 0)
            {
                sell_ONE[index - 0] = d;
            }

            if (high == 0)
            {
                liq_ONE[index - 0] = d;
            }

            if (high == 1)
                if (!isBuy)
                {
                    sell_ONE[index - 0] = Bars.HighPrices[index - 0];
                }

            if (high == 1)
                if (isBuy)
                {
                    liq_ONE[index - 0] = Bars.HighPrices[index - 0];
                }
        }
    }
}

 

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

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SELL_LIQ_220225_REALpana : Robot
    {

        ////////////////////////////////////
        /////   TRADING PARAMETERS    //////
        ////////////////////////////////////

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

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

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


        ////////////////////////////
        ////   INITIAL PARAM    //// 

        [Parameter("Source")]
        public DataSeries Source { get; set; }

        [Parameter("BandPeriods", DefaultValue = 16)]
        public int BandPeriod { get; set; }

        [Parameter("Std", DefaultValue = 1.6)]
        public double std { get; set; }

        [Parameter("MAType")]
        public MovingAverageType MAType { get; set; }


        //////////////////////////////
        ////       LITTERALS      //// 

        [Parameter("littFACTOR", DefaultValue = 5)]
        public double littFACTOR { get; set; }

        private sell_liq_panaBASE S2;

        protected override void OnStart()
        {
            S2 = Indicators.GetIndicator<sell_liq_panaBASE>(Source, BandPeriod, std, MAType);
        }

        double d = double.NaN;


        int m = 0;
        int n = 0;
        protected override void OnBar()
        {

            var a = S2.sell_ONE.Last(1);
            var b = S2.liq_ONE.Last(1);


            //    m += 1;
            //  string POS = "sell_pos " + m;

            if (!double.IsNaN(S2.sell_ONE.Last(1)) == true)
            {
                m += 1;
                string POS = "sell_pos " + m;

                ExecuteMarketOrder(TradeType.Sell, Symbol.Name, 1000, POS, StopLoss, LIMIT);
                Print("SELL    ", Bars.Count, "      ", S2.sell_ONE, "    ", POS);
            }


            // var POS = Positions.FindAll(posit);

            if (!double.IsNaN(S2.liq_ONE.Last(1)) == true)

                foreach (var position in Positions)
                {

                    n += 1;
                    string LIQ = "liq " + n;

                    ClosePosition(position);
                    Print("LIQ    ", Bars.Count, "      ", S2.liq_ONE, "    ", LIQ);
                }

        }
    }
}

 

 


@BJORNBERNAU

PanagiotisCharalampous
25 Feb 2022, 13:09

Hi Björn,

Which position is this? Dates are not visible. Also did you notice that you use a stop loss in your code?

Best Regards,

Panagiotis 

Join us on Telegram and Facebook


@PanagiotisCharalampous

BJORNBERNAU
25 Feb 2022, 14:17

RE:

PanagiotisCharalampous said:

Hi Björn,

Which position is this? Dates are not visible. Also did you notice that you use a stop loss in your code?

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

 

17 o'clock 31 jan 2022. 

It now seems to work. 

Yes, you're right. I missed the 50 stoploss. It works! 

Thank you for this clear guidance, I wish you a nice weekend!  

 

 


@BJORNBERNAU