Replies

BJORNBERNAU
22 May 2023, 09:02

RE:

firemyst said:

You could try adjusting your code so that your bots and indicators read/write your parameters to a json file.

Since you test your stuff in indicators first, the only actual input parameters that would have to be kept up to date are those for the indicator.

When your indicator runs, just write your parameters out to the json file.

Then when you start your bots, read in the json file to set all the parameters you need to. What I mean by that is, for example, you won't have to save the ticker-symbol nor the timeframe in the json parameter file, because you'll obviously set your bot instance to use the particular symbol/forex pair and timeframe you want to run against.

However, other parameters, like an EMA period or BB Std Dev, you'll probably want those saved to the json file.

 

 

Thank you very much! 

This may well work, but why all this bother about a theme that really must be quite central to all of us who develp indicators to be tested and run with the bot?

We get it, for sure(!), that receive hundreds of suggestions for your platform, which only long term could be implemented !

But is this really problematic to include the same snippet in your platform-code for Indicator as for cBot, so we may save and load - in seconds? 

Cordially, 

Björn Bernau 

 


@BJORNBERNAU

BJORNBERNAU
15 Mar 2022, 11:12 ( Updated at: 21 Dec 2023, 09:22 )

RE: RE: RE:

amusleh said:

BJORNBERNAU said:

amusleh said:

Hi,

The code post button:

Regarding OnBar issue, it depends on your indicator code, OnBar is called whenever a new bar opens, and access LastValue of your indicator means that you are trying to get the indicator output for newly created bar, which most probably will be NAN.

Test your indicator on cTrader Visual back test mode, you will see that your indicator only works properly for historical bars, not for newly created bars.

 

Okay, so how can I access historical data with the onBar method in cBot? 

Hi,

You can use any value of your indicator outputs inside OnBar, if you want to use historical values just pass the index of value to output Last method or with [].

The issue is not the cBot or OnBar, the issue if your indicator, fix your indicator first and then use it on a cBot.

 

Hi

 

I really cannot see the problem with the Indicator.

It produces a perfect array of alternating sell and buy signal.

Using different indices for the Last bar just delays the signal to the cBot.

There is now only one sell and liquidation signal relayed to cBot, then it arrests.

Why does cBot not receive the following signals?

 

Here’s the 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 COMPOSITEliveTEST_BBc_RED : Indicator
    {


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

        //////////////   22-03-15   /////////////////

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

        [Output("lineDARKred", PlotType = PlotType.DiscontinuousLine, LineColor = "#FF800001", Thickness = 1)]
        public IndicatorDataSeries lineDARKred { get; set; }


        ////   BOLLINGER    //// 



        //////////////////////////////
        ////       PARAMETERS      //// 

        [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; }

        [Parameter(DefaultValue = 100, MinValue = 50)]
        public int Period { get; set; }


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

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


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

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


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

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



        private BollingerBands boll;

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


        int high = 0;
        int highCOUNTER_A = 0;
        int highCOUNTER_B = 0;

        int HIGHstartCountIndexZERO = 0;

        int retrace = 2;


        public override void Calculate(int index)
        {
            highMARKET(index, high, highCOUNTER_A, highCOUNTER_B);
        }


        protected internal void highMARKET(int index, int high, int highCOUNTER_A, int highCOUNTER_B)
        {
            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 BBT1 = boll.Top[index - 1];
            var BBT2 = boll.Top[index - 2];
            var BBM1 = boll.Main[index - 1];


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


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


            {
                if (high == 1)
                    if (HIGHstartCountIndexZERO % 2 != 0)
                    {
                        highCOUNTER_A = 1;
                    }



                if (high == 1)
                    if (HIGHstartCountIndexZERO % 2 == 0)
                    {
                        highCOUNTER_B = 1;
                    }

            }

            HIGHprimaryINDEX(index, high, highCOUNTER_A, highCOUNTER_B);
        }


        int highA1 = 0;
        int highB1 = 0;

        double initHA1 = 0;
        double initHB1 = 0;
        bool pingORDER_1H = false;

        protected internal void HIGHprimaryINDEX(int index, int high, int highCOUNTER_A, int highCOUNTER_B)
        {
            {

                ////   INITIATION SIGNALS   ////


                if (highCOUNTER_A == 1)
                {
                    highA1 = index - retrace;
                }

                if (highCOUNTER_B == 1)
                {
                    highB1 = index - retrace;
                }

                initHA1 = Bars.HighPrices[highA1];
                initHB1 = Bars.HighPrices[highB1];

                if (highA1 > highB1)
                {
                    pingORDER_1H = false;
                }

                if (highA1 < highB1)
                    if (initHA1 > initHB1)
                    {
                        pingORDER_1H = true;
                    }
                //
                //
                projDETECTOR_1H(index, highA1, highB1, pingORDER_1H);
            }
        }


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




        //  bool highchannel1 = false;
        bool NXTchan1H = false;
        double Gradient1H = 0;
        double prevGRAD1H = 0;
        double lastGRAD1H = 0;
        double chklastGRAD1H = 0;


        int R1H = 0;
        int S1H = 0;
        double HA1 = 0;
        double HB1 = 0;

        bool downTILT1 = false;

        int O1H = 0;
        double proj1H = double.NaN;

        string prevA1H = null;
        string prevB1H = null;
        int chkA1H = 0;
        int chkB1H = 0;

        int CHNcount1H = 0;
        string DRWchn1H = null;

        private DateTime _lastBarOpenTime1H;

        private bool isSell1 = false;

        double d = double.NaN;

        //   int N = 1;


        protected internal void projDETECTOR_1H(int index, int highA1, int highB1, bool pingORDER_1H)
        {
            {

                //////////////////////////////////////////
                /////   FIX SUPPORT POINTS A and B   /////
                //////////////////////////////////////////

                chkA1H = Convert.ToInt16(prevA1H);
                chkB1H = Convert.ToInt16(prevB1H);


                //////////////////////////////////////////
                ////////        NEW CHANNEL       ////////
                //////////////////////////////////////////

                if (pingORDER_1H == true)
                    if (highA1 > chkA1H)
                        if (highB1 > chkB1H)
                        {
                            NXTchan1H = true;
                            proj1H = 0;
                            O1H = 0;
                        }


                //////////////////////////////////////////
                ////////       DEFINE CHANNEL     ////////
                //////////////////////////////////////////


                if (pingORDER_1H == true)
                    if (NXTchan1H == true)
                    {
                        HA1 = Bars.HighPrices[highA1];
                        HB1 = Bars.HighPrices[highB1];

                        R1H = highA1;
                        S1H = highB1;

                        prevA1H = Convert.ToString(highA1);
                        prevB1H = Convert.ToString(highB1);

                        Gradient1H = (HB1 - HA1) / (S1H - R1H);

                        prevGRAD1H = Gradient1H;
                    }


                lastGRAD1H = prevGRAD1H;


                if (chklastGRAD1H <= lastGRAD1H)
                {
                    lastGRAD1H = chklastGRAD1H;
                }


                if (Gradient1H < 0)
                    if (Gradient1H <= lastGRAD1H)
                    {
                        downTILT1 = true;
                    }


                if (Gradient1H > lastGRAD1H)
                {
                    downTILT1 = false;
                }


                //////////////////////////////////////////////
                ////////        CONSTRUCT CHANNEL     ////////
                //////////////////////////////////////////////


                if (downTILT1 == true)
                {
                    CHNcount1H += 1;

                    DRWchn1H = "highChannel_1 " + CHNcount1H;
                    Chart.DrawTrendLine(DRWchn1H, R1H, HA1, S1H, HB1, Color.MediumSlateBlue);

                    O1H += 1;
                    proj1H = ((Gradient1H * (O1H - 1)) + HB1);
                    lineDARKred[index - 2] = proj1H;
                }


                //////////////////////////////////////////
                //////////////////////////////////////////
                //////////////////////////////////////////
                //////////////////////////////////////////
                //////////////////////////////////////////
                //////////////////////////////////////////
                //////////////////////////////////////////
                ////////        INT RETRACERS     ////////
                //////////////////////////////////////////
                //////////////////////////////////////////
                //////////////////////////////////////////
                //////////////////////////////////////////
                //////////////////////////////////////////
                //////////////////////////////////////////
                //////////////////////////////////////////

                int sellRETR = 2;
                int liqRETR = 1;




                /////////////////////////////////////////////////
                ////////       SIGNAL - ONCE ON BAR      ////////
                /////////////////////////////////////////////////


                if (Bars.OpenTimes[index] != _lastBarOpenTime1H)
                {
                    _lastBarOpenTime1H = Bars.OpenTimes[index];

                    if (!double.IsNaN(sell_ONE.Last(sellRETR)))
                    {
                        isSell1 = true;
                    }


                    if (!double.IsNaN(liq_sellONE.Last(sellRETR)))
                    {
                        isSell1 = false;
                    }
                }


                //////////////////////////////////////////
                ////////        NaN - SIGNAL      ////////
                //////////////////////////////////////////

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

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





                //////////////////////////////////////////
                ////////       SELL - SIGNAL      ////////
                //////////////////////////////////////////

                if (!isSell1)
                    if (downTILT1 == true)
                    {
                        sell_ONE[index - sellRETR] = Bars.HighPrices[index - sellRETR];
                        Print("    SELL    ", index, "       ", sell_ONE, "       ", sell_ONE.Last(sellRETR));

                    }



                ///////////////////////////////////////////////
                ////////       CLOSE TRADE SIGNAL      ////////
                ///////////////////////////////////////////////

                var opencncl_1H = Bars.OpenPrices[index - 0];
                var closecncl_1H = Bars.ClosePrices[index - 0];

                if (isSell1)
                    if (proj1H > 0)
                        if (opencncl_1H < closecncl_1H)
                            if (closecncl_1H > proj1H)
                            {
                                liq_sellONE[index - liqRETR] = Bars.HighPrices[index - liqRETR];
                                Print("    LIQ    ", index, "         ", liq_sellONE, "     ", liq_sellONE.Last(liqRETR));


                                R1H = 0;
                                S1H = 0;
                                HA1 = 0;
                                HB1 = 0;

                                O1H = 0;
                                proj1H = 0;
                                Gradient1H = 0;

                                NXTchan1H = false;

                                downTILT1 = false;


                            }




            }
        }
    }
}





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_LIVEtest_BBC_RED : 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; }


        ////////////////////////////////////
        /////    SIGNAL PARAMETERS    //////
        ////////////////////////////////////


        [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; }

        [Parameter(DefaultValue = 100, MinValue = 50)]
        public int Period { get; set; }

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

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

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

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


        ////////////////////////////////////
        /////    OUTPUT PARAMETERS    //////
        ////////////////////////////////////

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

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


        private COMPOSITEliveTEST_BBc_RED S2;

        protected override void OnStart()
        {
            S2 = Indicators.GetIndicator<COMPOSITEliveTEST_BBc_RED>(Source, BandPeriod, std, MAType, Period, littFACTOR, thresherValue, lastINDEX, zeroINDEX);
        }

        //    double d = double.NaN;

        int S = 2;
        int L = 2;

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

            var a = S2.sell_ONE.Last(S);
            var bMIN1 = S2.liq_sellONE.Last(-1);
            var b0 = S2.liq_sellONE.Last(0);
            var b1 = S2.liq_sellONE.Last(1);
            var b2 = S2.liq_sellONE.Last(2);
            var b3 = S2.liq_sellONE.Last(3);


            //   Print(Bars.Count, "    ", a, "    ", b1, "    ", b2, "    ", b3);


            if (!double.IsNaN(S2.sell_ONE.Last(S)) == true)
            {
                Print(Bars.Count, "   sell   ", a, "    ", b1, "    ", b2, "    ", b3);
                //     Print("    SELL    ", Bars.Count, "     ", S2.sell_ONE.Last(S));
            }

            if (!double.IsNaN(S2.liq_sellONE.Last(L)) == true)
            {
                Print(Bars.Count, "   liq   ", a, "    ", b1, "    ", b2, "    ", b3);
                //         Print("    LIQ     ", Bars.Count, "     ", S2.liq_sellONE.Last(1));
            }


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

                ExecuteMarketOrder(TradeType.Sell, Symbol.Name, 1000, POS, StopLoss, LIMIT);

                //    Print("ROBOT SELL    ", Bars.Count, "      ", S2.sell_ONE, "    ", POS);

            }


            if (!double.IsNaN(S2.liq_sellONE.Last(L)) == true)
                foreach (var POS in Positions)
                {

                    n += 1;
                    string LIQ = "liquid no " + n;

                    ClosePosition(POS);
                }

        }
    }
}



 


@BJORNBERNAU

BJORNBERNAU
15 Mar 2022, 09:51 ( Updated at: 21 Dec 2023, 09:22 )

RE:

amusleh said:

Hi,

The code post button:

Regarding OnBar issue, it depends on your indicator code, OnBar is called whenever a new bar opens, and access LastValue of your indicator means that you are trying to get the indicator output for newly created bar, which most probably will be NAN.

Test your indicator on cTrader Visual back test mode, you will see that your indicator only works properly for historical bars, not for newly created bars.

 

Okay, so how can I access historical data with the onBar method in cBot? 


@BJORNBERNAU

BJORNBERNAU
15 Mar 2022, 09:41

RE:

amusleh said:

Hi,

First of all there is a button on editor for posting code, please use it next time!

Your indicator is not consistent with it's output, if you give the same data twice it will return different outputs each time.

You are using OnBar method of cBot, and you are using Last value of indicator outputs, which are not complete and it will always return NAN inside OnBar.

Here are some recommendation for you:

  • If you have time and interest to continue writing C# code, then stop developing cBots/Indicators and instead put some time to learn C# and .NET basics, there are a ton of materials available for free on internet that you can use
  • In case you don't have time or the interest, you can contact one of our consultant companies or post a job request
  • Start small, if you copy some piece of code from one place and another from another place and put it inside a cTrader indicator it will not work
  • When asking help or support, be specific, you can't post 100s of lines of code and ask us to find the issue for you

 

Thank you. 

Where is this posting button? I have a 'submit' button. 

Where do you explain in your manuals, that OnBar, is not in the use with Last value are not compatible? 

Panagiotis gave me this code blow, using OnBar and Last values for indicator and cbot. Amongst others some of you suggested that it was a case of lazy loading, which then was refuted by Panagiotis.

In my post I specifically ask for why the signals, in the indicator code, are not transferred to the cbot? Which is written on the forum “I don't get why the signals are not transferred from this IND to the following BOT. Trying to evoke the signal to 'overrun' any misses in the signals by a …

//Björn 

Panagiotis code found here 

https://ctrader.com/forum/cbot-support/37684?page=1#post-2

 


@BJORNBERNAU

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

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

RE: RE:

BJORNBERNAU said:

PanagiotisCharalampous said:

Hi Bjorn,

If you run the cBot using visual backtesting, you will see that the trade is correct based on the signal on the chart

The problem here lies in your indicator's logic. You set a value to the output series when the signal is valid, but you don't set it back to NaN when the signal is invalidated within the same candle. This causes discrepancies between signals calculated in real time and signals calculated for historical bars, because real time bars are calculated. You need to fix this. This problem does not appear with the indicator I provided here.

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

Okay, thank you, I'll look into this! 

I've answered in the link for the code you're referring to. 


@BJORNBERNAU

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

BJORNBERNAU
25 Feb 2022, 11:34 ( Updated at: 21 Dec 2023, 09:22 )

RE:

PanagiotisCharalampous said:

Hi Bjorn,

If you run the cBot using visual backtesting, you will see that the trade is correct based on the signal on the chart

The problem here lies in your indicator's logic. You set a value to the output series when the signal is valid, but you don't set it back to NaN when the signal is invalidated within the same candle. This causes discrepancies between signals calculated in real time and signals calculated for historical bars, because real time bars are calculated. You need to fix this. This problem does not appear with the indicator I provided here.

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

Okay, thank you, I'll look into this! 


@BJORNBERNAU

BJORNBERNAU
25 Feb 2022, 10:27

RE:

PanagiotisCharalampous said:

Hi Björn,

In order to help you  further, you need to provide us with the cBot parameters and dates so that we can reproduce the trades.

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

Thank you! 

Actually I did so above and it is 1 hr

 

ROBOT // to simplify runs in the robot it is made in EURUSD between 13 jan - 21 febr 2022 


@BJORNBERNAU

BJORNBERNAU
25 Feb 2022, 10:03 ( Updated at: 21 Dec 2023, 09:22 )

RE: RE: RE:

BJORNBERNAU said:

BJORNBERNAU said:

PanagiotisCharalampous said:

Hi Björn,

The problem is probably caused by the fact that you are checking the value of the open candle. This can cause trades to open but the signal to disappear until the candle closes. To avoid such issues, you should be checking the values of closed candles i.e. use .Last(1) instead of .Last(0).

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

 

 

Thank you Panagiotis! 

No, I'm sorry to say that that just delays the positions, same issue, the code

  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);
                }

        }

Increasing stop loss to 100 produces that same two issues. 

Stop-out at 52.9 without signal and reversal of sell/liquidation execution by the robot. 


@BJORNBERNAU

BJORNBERNAU
25 Feb 2022, 09:57

RE: RE:

BJORNBERNAU said:

PanagiotisCharalampous said:

Hi Björn,

The problem is probably caused by the fact that you are checking the value of the open candle. This can cause trades to open but the signal to disappear until the candle closes. To avoid such issues, you should be checking the values of closed candles i.e. use .Last(1) instead of .Last(0).

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

 

 

Thank you Panagiotis! 

No, I'm sorry to say that that just delays the positions, same issue, the code

  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

BJORNBERNAU
25 Feb 2022, 09:56

RE:

PanagiotisCharalampous said:

Hi Björn,

The problem is probably caused by the fact that you are checking the value of the open candle. This can cause trades to open but the signal to disappear until the candle closes. To avoid such issues, you should be checking the values of closed candles i.e. use .Last(1) instead of .Last(0).

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

 

 

Thank you Panagiotis! 

No, I'm sorry to say that that just delays the positions, same issue, the code

  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

BJORNBERNAU
25 Feb 2022, 09:39

RE:

amusleh said:

Hi,

Can you tell exactly me what's the issue?

Thank you Amusleh! 

The signals work and are relayed to the robot, mostly in a correct fashion. But now, there are apparently some 'ghost' signals instead. Sell signals are purple and liquidation signals green. 

  1. Second image above after signal 422 brown box - a correctly executed sell signal - the position is liquidated despite no liquidation signal, nor a stop-loss, as seen from the indicator that shows none, next image, after signal 1576 -  blue box.
  2. In addition, after this, the sell and liquidation signals are reversed, seen again in next image, signal 449. 

These two issues are now the most important problems. 

Thank you! 

Björn 


@BJORNBERNAU

BJORNBERNAU
24 Feb 2022, 11:55 ( Updated at: 21 Dec 2023, 09:22 )

RE:

amusleh said:

Hi,

The lazy loading of indicators means that the indicator code is not called/executed unless you access it's data.

By data I mean indicator Outputs / IndicatorDataSeries, if your indicator has no Output then you have to explicitly call the indicator Calculate method.

It's an implementation detail, and it's very rare to face any issue with indicator lazy loading unless you use an indicator without an Output.

 

 

 

 

Hello Amusleh and thank you for your feedback.

Your points are partly spot on and have been further developed. The deterministic signal is enhanced by time specific restrictions as by Panagiotis such as

private DateTime _lastBarOpenTime;

if (Bars.OpenTimes[index] != _lastBarOpenTime)
{
_lastBarOpenTime = Bars.OpenTimes[index];
}
 

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

cTDN Forum - LAZY LOADING REVISITED .... (ctrader.com)

This basically produces working signals from the robot, sell (purple) and liquidation (green signal), stoploss set at 50.

 

Basically…

Because, at the 422 signal, sell is liquidated in the robot shown here, after 36.4 pips, i.e. no stoploss

with a signal that is non-existent in the indicator as show below

 

After this the sell signal is reversed, so that liquidation now is sell, as seen in

This is later, reversed, and again reversed and repeated in another non-existant indicator signal

 

 

THE 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 SELL_LIQ_RED_CTDN_PANAGIOTIS : Indicator
    {

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

        ////  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;
        
        int mm = 0;

        public override void Calculate(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];

            mm += 1;


            if (Bars.OpenTimes[index] != _lastBarOpenTime)
            {

                _lastBarOpenTime = Bars.OpenTimes[index];


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

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

                if (high4 <= high2)
                    if (high3 <= high2)
                        if (high2 > BBT2)
                            if (high2 >= high1)
                                if (high2 >= close0)
                                {
                                    high = 1;
                                    White[index - 0] = Bars.HighPrices[index - 0] + 0.0002;


                                }

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

                //      if (!isBuy)
                if (high == 1)
                    if (HIGHstartCountIndexZERO % 2 != 0)
                    {
                        sell_ONE[index - 0] = Bars.HighPrices[index - 0];
                        //   Print(index, "    SELL   ", sell_ONE);

                        string litt_LIMIT = Convert.ToString((index + 0));
                        var Lindex = Chart.DrawText("litt_LIMIT" + mm, litt_LIMIT, index - 2, sell_ONE[index] + 0.005, Color.DimGray);
                    }


                //   if (isBuy)
                if (high == 1)
                    if (HIGHstartCountIndexZERO % 2 == 0)
                    {
                        liq_ONE[index - 0] = Bars.HighPrices[index - 0];
                        //     Print(index, "    LIQ     ", liq_ONE);

                        string litt_LIMIT2 = Convert.ToString((index + 0));
                        var Lindex2 = Chart.DrawText("litt_LIMIT" + mm, litt_LIMIT2, index - 2, liq_ONE[index] + 0.005, Color.DimGray);
                    }

            }
        }
    }
}

 

The lazy loading should be overcome by directly addressing the Calculate method in Robot as below by

 

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

ROBOT // to simplify runs in the robot it is made in EURUSD between 13 jan - 21 febr 2022 

 

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_220220_panagiotis : 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_RED_CTDN_PANAGIOTIS S2;

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

        double d = double.NaN;


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

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


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

            if (!double.IsNaN(S2.sell_ONE.Last(0)) == 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(0)) == true)

                foreach (var position in Positions)
                {

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

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

        }
    }
}

 

 

 


@BJORNBERNAU

BJORNBERNAU
22 Feb 2022, 14:32

RE: RE: RE: RE: RE: RE:

BJORNBERNAU said:

firemyst said:

BJORNBERNAU said:

Thank you! Well, I tried it. This does not change it. The code is now the following 

 

protected override void OnBar()
        {

            double a = S2.sell_ONE.Last(0);
            a = S2.liq_ONE.Last(0);

            double b = S2.liq_ONE.Last(0);
            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);
            }

        }

 

Resulting in this data stream - a block-wise procurement of SELL and LIQ. 

 

  double b = S2.liq_ONE.Last(0);
            b = S2.liq_ONE.Last(0);

WHY ARE YOU DOING THIS?! Not only are you assigning the same value to "b" twice, but you're also declaring a new variable, of which there's no need to declare a new "double b".

As I said, who cares if "a" gets overwritten with a new value?? -- you don't care about the value, and you never use it again. Don't take up extra computing resources by declaring another "double" that's not going to be used anywhere and that you're just assigning the same value to it twice in a row.

As for your overall print statements, it is working now. Your original issue was it kept printing "LastValue: NaN". It no longer does that. That issue is resolved.

If there's other logic issues in your indicator code, you'll have to figure those out or ask for help from others. :-)

 

What does your code mean? 

If we declare 

          double a = S2.sell_ONE.Last(0);
            a = S2.liq_ONE.Last(0);

does this mean that we INVOKE both SELL and LIQ - which is forcing the bot to retrieve both SELL and LIQ? 

When I apply your code it liberates the below, if that is not true for you, please post the code for both the bot and indicator, so I am sure to see your point. 

Thank you!

 

21/02/2022 00:59:00.000 | Backtesting finished
18/02/2022 12:00:00.000 | LIQ    640      IndicatorDataSeries (Count: 640, LastValue: 1,13611)
16/02/2022 22:00:00.000 | LIQ    602      IndicatorDataSeries (Count: 602, LastValue: 1,13821)
16/02/2022 11:00:00.000 | LIQ    591      IndicatorDataSeries (Count: 591, LastValue: 1,13775)
15/02/2022 19:00:00.000 | LIQ    575      IndicatorDataSeries (Count: 575, LastValue: 1,13586)
15/02/2022 16:00:00.000 | LIQ    572      IndicatorDataSeries (Count: 572, LastValue: 1,1322)
15/02/2022 13:00:00.000 | LIQ    569      IndicatorDataSeries (Count: 569, LastValue: 1,13459)
11/02/2022 19:00:00.000 | LIQ    527      IndicatorDataSeries (Count: 527, LastValue: 1,13966)
11/02/2022 16:00:00.000 | LIQ    524      IndicatorDataSeries (Count: 524, LastValue: 1,13888)
10/02/2022 19:00:00.000 | LIQ    503      IndicatorDataSeries (Count: 503, LastValue: 1,14645)
10/02/2022 16:00:00.000 | SELL    500      IndicatorDataSeries (Count: 500, LastValue: 1,14074)
10/02/2022 12:00:00.000 | SELL    496      IndicatorDataSeries (Count: 496, LastValue: 1,14359)
09/02/2022 20:00:00.000 | SELL    480      IndicatorDataSeries (Count: 480, LastValue: 1,14326)
09/02/2022 16:00:00.000 | SELL    476      IndicatorDataSeries (Count: 476, LastValue: 1,14317)
09/02/2022 13:00:00.000 | SELL    473      IndicatorDataSeries (Count: 473, LastValue: 1,14295)
09/02/2022 06:00:00.000 | SELL    466      IndicatorDataSeries (Count: 466, LastValue: 1,14269)
07/02/2022 19:00:00.000 | SELL    431      IndicatorDataSeries (Count: 431, LastValue: 1,14186)
07/02/2022 15:00:00.000 | SELL    427      IndicatorDataSeries (Count: 427, LastValue: 1,14398)
04/02/2022 14:00:00.000 | SELL    402      IndicatorDataSeries (Count: 402, LastValue: 1,14655)
04/02/2022 10:00:00.000 | SELL    398      IndicatorDataSeries (Count: 398, LastValue: 1,14602)
03/02/2022 19:00:00.000 | SELL    383      IndicatorDataSeries (Count: 383, LastValue: 1,14436)
02/02/2022 16:00:00.000 | SELL    356      IndicatorDataSeries (Count: 356, LastValue: 1,13048)
01/02/2022 14:00:00.000 | SELL    330      IndicatorDataSeries (Count: 330, LastValue: 1,12617)
01/02/2022 11:00:00.000 | SELL    327      IndicatorDataSeries (Count: 327, LastValue: 1,12614)
31/01/2022 22:00:00.000 | SELL    314      IndicatorDataSeries (Count: 314, LastValue: 1,12354)
31/01/2022 18:00:00.000 | LIQ    310      IndicatorDataSeries (Count: 310, LastValue: 1,12101)
31/01/2022 11:00:00.000 | LIQ    303      IndicatorDataSeries (Count: 303, LastValue: 1,11747)
28/01/2022 17:00:00.000 | LIQ    285      IndicatorDataSeries (Count: 285, LastValue: 1,11643)
24/01/2022 21:00:00.000 | LIQ    193      IndicatorDataSeries (Count: 193, LastValue: 1,13198)
21/01/2022 17:00:00.000 | LIQ    165      IndicatorDataSeries (Count: 165, LastValue: 1,1346)
21/01/2022 12:00:00.000 | LIQ    160      IndicatorDataSeries (Count: 160, LastValue: 1,13391)
20/01/2022 11:00:00.000 | LIQ    135      IndicatorDataSeries (Count: 135, LastValue: 1,13476)
20/01/2022 04:00:00.000 | LIQ    128      IndicatorDataSeries (Count: 128, LastValue: 1,13549)
20/01/2022 01:00:00.000 | Backtesting started
 

 

 

The code does not ALTERNATE between SELL and LIQ. 


@BJORNBERNAU

BJORNBERNAU
22 Feb 2022, 14:22

RE: RE: RE: RE: RE:

firemyst said:

BJORNBERNAU said:

Thank you! Well, I tried it. This does not change it. The code is now the following 

 

protected override void OnBar()
        {

            double a = S2.sell_ONE.Last(0);
            a = S2.liq_ONE.Last(0);

            double b = S2.liq_ONE.Last(0);
            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);
            }

        }

 

Resulting in this data stream - a block-wise procurement of SELL and LIQ. 

 

  double b = S2.liq_ONE.Last(0);
            b = S2.liq_ONE.Last(0);

WHY ARE YOU DOING THIS?! Not only are you assigning the same value to "b" twice, but you're also declaring a new variable, of which there's no need to declare a new "double b".

As I said, who cares if "a" gets overwritten with a new value?? -- you don't care about the value, and you never use it again. Don't take up extra computing resources by declaring another "double" that's not going to be used anywhere and that you're just assigning the same value to it twice in a row.

As for your overall print statements, it is working now. Your original issue was it kept printing "LastValue: NaN". It no longer does that. That issue is resolved.

If there's other logic issues in your indicator code, you'll have to figure those out or ask for help from others. :-)

 

What does your code mean? 

If we declare 

          double a = S2.sell_ONE.Last(0);
            a = S2.liq_ONE.Last(0);

does this mean that we INVOKE both SELL and LIQ - which is forcing the bot to retrieve both SELL and LIQ? 

When I apply your code it liberates the below, if that is not true for you, please post the code for both the bot and indicator, so I am sure to see your point. 

Thank you!

 

21/02/2022 00:59:00.000 | Backtesting finished
18/02/2022 12:00:00.000 | LIQ    640      IndicatorDataSeries (Count: 640, LastValue: 1,13611)
16/02/2022 22:00:00.000 | LIQ    602      IndicatorDataSeries (Count: 602, LastValue: 1,13821)
16/02/2022 11:00:00.000 | LIQ    591      IndicatorDataSeries (Count: 591, LastValue: 1,13775)
15/02/2022 19:00:00.000 | LIQ    575      IndicatorDataSeries (Count: 575, LastValue: 1,13586)
15/02/2022 16:00:00.000 | LIQ    572      IndicatorDataSeries (Count: 572, LastValue: 1,1322)
15/02/2022 13:00:00.000 | LIQ    569      IndicatorDataSeries (Count: 569, LastValue: 1,13459)
11/02/2022 19:00:00.000 | LIQ    527      IndicatorDataSeries (Count: 527, LastValue: 1,13966)
11/02/2022 16:00:00.000 | LIQ    524      IndicatorDataSeries (Count: 524, LastValue: 1,13888)
10/02/2022 19:00:00.000 | LIQ    503      IndicatorDataSeries (Count: 503, LastValue: 1,14645)
10/02/2022 16:00:00.000 | SELL    500      IndicatorDataSeries (Count: 500, LastValue: 1,14074)
10/02/2022 12:00:00.000 | SELL    496      IndicatorDataSeries (Count: 496, LastValue: 1,14359)
09/02/2022 20:00:00.000 | SELL    480      IndicatorDataSeries (Count: 480, LastValue: 1,14326)
09/02/2022 16:00:00.000 | SELL    476      IndicatorDataSeries (Count: 476, LastValue: 1,14317)
09/02/2022 13:00:00.000 | SELL    473      IndicatorDataSeries (Count: 473, LastValue: 1,14295)
09/02/2022 06:00:00.000 | SELL    466      IndicatorDataSeries (Count: 466, LastValue: 1,14269)
07/02/2022 19:00:00.000 | SELL    431      IndicatorDataSeries (Count: 431, LastValue: 1,14186)
07/02/2022 15:00:00.000 | SELL    427      IndicatorDataSeries (Count: 427, LastValue: 1,14398)
04/02/2022 14:00:00.000 | SELL    402      IndicatorDataSeries (Count: 402, LastValue: 1,14655)
04/02/2022 10:00:00.000 | SELL    398      IndicatorDataSeries (Count: 398, LastValue: 1,14602)
03/02/2022 19:00:00.000 | SELL    383      IndicatorDataSeries (Count: 383, LastValue: 1,14436)
02/02/2022 16:00:00.000 | SELL    356      IndicatorDataSeries (Count: 356, LastValue: 1,13048)
01/02/2022 14:00:00.000 | SELL    330      IndicatorDataSeries (Count: 330, LastValue: 1,12617)
01/02/2022 11:00:00.000 | SELL    327      IndicatorDataSeries (Count: 327, LastValue: 1,12614)
31/01/2022 22:00:00.000 | SELL    314      IndicatorDataSeries (Count: 314, LastValue: 1,12354)
31/01/2022 18:00:00.000 | LIQ    310      IndicatorDataSeries (Count: 310, LastValue: 1,12101)
31/01/2022 11:00:00.000 | LIQ    303      IndicatorDataSeries (Count: 303, LastValue: 1,11747)
28/01/2022 17:00:00.000 | LIQ    285      IndicatorDataSeries (Count: 285, LastValue: 1,11643)
24/01/2022 21:00:00.000 | LIQ    193      IndicatorDataSeries (Count: 193, LastValue: 1,13198)
21/01/2022 17:00:00.000 | LIQ    165      IndicatorDataSeries (Count: 165, LastValue: 1,1346)
21/01/2022 12:00:00.000 | LIQ    160      IndicatorDataSeries (Count: 160, LastValue: 1,13391)
20/01/2022 11:00:00.000 | LIQ    135      IndicatorDataSeries (Count: 135, LastValue: 1,13476)
20/01/2022 04:00:00.000 | LIQ    128      IndicatorDataSeries (Count: 128, LastValue: 1,13549)
20/01/2022 01:00:00.000 | Backtesting started
 

 

 

 


@BJORNBERNAU

BJORNBERNAU
22 Feb 2022, 12:55

RE: RE: RE:

firemyst said:

BJORNBERNAU said:

So the "forcing" is actually happening in the Robot, not the Indicator?

Yes. You don't need to do it in the indicator. The indicator always gets its own values. However, to save on resources, the robots don't load indicator data until they're actually needed. That's why you need to force it to load to tell the robot it's needed.

Then you have to convert the double.IsNaN(S2.liq_ONE[indicatorIndex]

into 

double.IsNaN(a) == false

is it or how does the Robot find "a"?

You do not care about "a" any more as I said previously.

"a" is just used as some place to force a value to be returned from the indicator.

Now that the indicator data has been loaded by the bot, you can go about getting any values you want from the indicator. Nothing else in the code needs to be changed unless you need data from other indicators.

 

Thank you! Well, I tried it. This does not change it. The code is now the following 

 

protected override void OnBar()
        {

            double a = S2.sell_ONE.Last(0);
            a = S2.liq_ONE.Last(0);

            double b = S2.liq_ONE.Last(0);
            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);
            }

        }

 

Resulting in this data stream - a block-wise procurement of SELL and LIQ. 

 

21/02/2022 00:59:00.000 | Backtesting finished
18/02/2022 12:00:00.000 | LIQ    640      IndicatorDataSeries (Count: 640, LastValue: 1,13611)
16/02/2022 22:00:00.000 | LIQ    602      IndicatorDataSeries (Count: 602, LastValue: 1,13821)
16/02/2022 11:00:00.000 | LIQ    591      IndicatorDataSeries (Count: 591, LastValue: 1,13775)
15/02/2022 19:00:00.000 | LIQ    575      IndicatorDataSeries (Count: 575, LastValue: 1,13586)
15/02/2022 16:00:00.000 | LIQ    572      IndicatorDataSeries (Count: 572, LastValue: 1,1322)
15/02/2022 13:00:00.000 | LIQ    569      IndicatorDataSeries (Count: 569, LastValue: 1,13459)
11/02/2022 19:00:00.000 | LIQ    527      IndicatorDataSeries (Count: 527, LastValue: 1,13966)
11/02/2022 16:00:00.000 | LIQ    524      IndicatorDataSeries (Count: 524, LastValue: 1,13888)
10/02/2022 19:00:00.000 | LIQ    503      IndicatorDataSeries (Count: 503, LastValue: 1,14645)
10/02/2022 16:00:00.000 | SELL    500      IndicatorDataSeries (Count: 500, LastValue: 1,14074)
10/02/2022 12:00:00.000 | SELL    496      IndicatorDataSeries (Count: 496, LastValue: 1,14359)
09/02/2022 20:00:00.000 | SELL    480      IndicatorDataSeries (Count: 480, LastValue: 1,14326)
09/02/2022 16:00:00.000 | SELL    476      IndicatorDataSeries (Count: 476, LastValue: 1,14317)
09/02/2022 13:00:00.000 | SELL    473      IndicatorDataSeries (Count: 473, LastValue: 1,14295)
09/02/2022 06:00:00.000 | SELL    466      IndicatorDataSeries (Count: 466, LastValue: 1,14269)
07/02/2022 19:00:00.000 | SELL    431      IndicatorDataSeries (Count: 431, LastValue: 1,14186)
07/02/2022 15:00:00.000 | SELL    427      IndicatorDataSeries (Count: 427, LastValue: 1,14398)
04/02/2022 14:00:00.000 | SELL    402      IndicatorDataSeries (Count: 402, LastValue: 1,14655)
04/02/2022 10:00:00.000 | SELL    398      IndicatorDataSeries (Count: 398, LastValue: 1,14602)
03/02/2022 19:00:00.000 | SELL    383      IndicatorDataSeries (Count: 383, LastValue: 1,14436)
02/02/2022 16:00:00.000 | SELL    356      IndicatorDataSeries (Count: 356, LastValue: 1,13048)
01/02/2022 14:00:00.000 | SELL    330      IndicatorDataSeries (Count: 330, LastValue: 1,12617)
01/02/2022 11:00:00.000 | SELL    327      IndicatorDataSeries (Count: 327, LastValue: 1,12614)
31/01/2022 22:00:00.000 | SELL    314      IndicatorDataSeries (Count: 314, LastValue: 1,12354)
31/01/2022 18:00:00.000 | LIQ    310      IndicatorDataSeries (Count: 310, LastValue: 1,12101)
31/01/2022 11:00:00.000 | LIQ    303      IndicatorDataSeries (Count: 303, LastValue: 1,11747)
28/01/2022 17:00:00.000 | LIQ    285      IndicatorDataSeries (Count: 285, LastValue: 1,11643)
24/01/2022 21:00:00.000 | LIQ    193      IndicatorDataSeries (Count: 193, LastValue: 1,13198)
21/01/2022 17:00:00.000 | LIQ    165      IndicatorDataSeries (Count: 165, LastValue: 1,1346)
21/01/2022 12:00:00.000 | LIQ    160      IndicatorDataSeries (Count: 160, LastValue: 1,13391)
20/01/2022 11:00:00.000 | LIQ    135      IndicatorDataSeries (Count: 135, LastValue: 1,13476)
20/01/2022 04:00:00.000 | LIQ    128      IndicatorDataSeries (Count: 128, LastValue: 1,13549)
20/01/2022 01:00:00.000 | Backtesting started
 


@BJORNBERNAU

BJORNBERNAU
22 Feb 2022, 12:26

RE:

firemyst said:

protected override void OnTick()
        {
            //This is all you would have had to do:
            double a = S2.sell_ONE.Last(0);
            a = S2.liq_ONE.Last(0);
            //That's it! Now the Calculate method has been 
            //forced to calculate for each sell_One and liq_one.
            //You can now get any values from your indicator
            //and they will be readily available.
             


            var index = Bars.Count - 1;

            var indicatorIndex = index - 2;

            Chart.RemoveObject(indicatorIndex.ToString());

            if (double.IsNaN(S2.sell_ONE[indicatorIndex]) == false)
            {
                Chart.DrawVerticalLine(indicatorIndex.ToString(), Bars.OpenTimes[indicatorIndex], Color.FromHex("#B511F7"));
            }
            else if (double.IsNaN(S2.liq_ONE[indicatorIndex]) == false)
            {
                Chart.DrawVerticalLine(indicatorIndex.ToString(), Bars.OpenTimes[indicatorIndex], Color.FromHex("#FF7CFC00"));
            }
        }

See code example above. It's not really necessary with amusleh's rewrite, but it illustrates the point. It's literally that simple. You'd have to do that for any other custom indicator you need values for.

Advice is to put all those calls into one method, and then just call the method at OnTick, OnBar, or whenever you'll need values from your indicators.

 

So the "forcing" is actually happening in the Robot, not the Indicator?

Then you have to convert the double.IsNaN(S2.liq_ONE[indicatorIndex]

into 

double.IsNaN(a) == false

is it or how does the Robot find "a"?


@BJORNBERNAU

BJORNBERNAU
22 Feb 2022, 11:27 ( Updated at: 21 Dec 2023, 09:22 )

RE: RE:

BJORNBERNAU said:

amusleh said:

Hi,

I tried to find the issue, there were several issues on your indicator.

First it's repints, it returns data for two previous bar, and in cBot you are trying to get the current bar, that's one issue.

The other one is related to your indicator HIGHstartCountIndexZERO variable, this causes not deterministic results between cBot indicator and the one you attached on the chart.

Try my attached versions of your indicator and cBot, and you will see that their results will match on visual back test.

Indicator:

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

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SELL_LIQ : Indicator
    {
        [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; }

        [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);
        }

        private int HIGHstartCountIndexZERO = 0;

        public override void Calculate(int index)
        {
            sell_ONE[index - 2] = double.NaN;
            liq_ONE[index - 2] = double.NaN;

            var high = 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 close = Bars.ClosePrices[index];

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

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

            if (high == 0)
            {
                sell_ONE[index - 2] = double.NaN;
                liq_ONE[index - 2] = double.NaN;
            }
            else if (high == 1)
            {
                // I changed the logic here to find what's causing the discrepancy
                // between bot and indicator outputs
                if (Bars.ClosePrices[index - 2] > Bars.OpenPrices[index - 2])
                {
                    sell_ONE[index - 2] = Bars.HighPrices[index - 2];
                }
                else
                {
                    liq_ONE[index - 2] = Bars.LowPrices[index - 2];
                }

                //HIGHstartCountIndexZERO += 1;

                //if (HIGHstartCountIndexZERO % 2 != 0)
                //{
                //    sell_ONE[index - 2] = Bars.HighPrices[index - 2];
                //}
                //else
                //{
                //    liq_ONE[index - 2] = Bars.LowPrices[index - 2];
                //}
            }
        }
    }
}

cBot:

using cAlgo.API;

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SELL_LIQ_220220 : Robot
    {
        [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 SELL_LIQ S2;

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

        protected override void OnTick()
        {
            var index = Bars.Count - 1;

            var indicatorIndex = index - 2;

            Chart.RemoveObject(indicatorIndex.ToString());

            if (double.IsNaN(S2.sell_ONE[indicatorIndex]) == false)
            {
                Chart.DrawVerticalLine(indicatorIndex.ToString(), Bars.OpenTimes[indicatorIndex], Color.FromHex("#B511F7"));
            }
            else if (double.IsNaN(S2.liq_ONE[indicatorIndex]) == false)
            {
                Chart.DrawVerticalLine(indicatorIndex.ToString(), Bars.OpenTimes[indicatorIndex], Color.FromHex("#FF7CFC00"));
            }
        }
    }
}

Attach the indicator on visual back test chart, do some back testing on tick data not m1 bars, my result:

cTrader back tester loads some bars without running the cBot on those bars for warming up the indicators.

And if your indicator has some kind of non deterministic code like yours then the results will not match.

You see on my result, the first signal is not marked by cBot, because those bars were loaded by back tester for warm up.

Thank you! 

Interesting set up. The vertical lines though, just flashed up once on back-testing and dissappeared. 

 

So, Firemyst! 

I'm indeed not the professional, as you are, and trying to understand the meaning of the forcing of the Indicator method not to be lazy. How is the configuration made? This does not work

 var a = sell_ONE.Last(0);

            if (high == 1)
                if (HIGHstartCountIndexZERO % 2 != 0)
                {

                    a = sell_ONE.Last(0);
                }

So how should you go about it? 

Thank you!


@BJORNBERNAU

BJORNBERNAU
22 Feb 2022, 11:13 ( Updated at: 21 Dec 2023, 09:22 )

RE:

amusleh said:

Hi,

I tried to find the issue, there were several issues on your indicator.

First it's repints, it returns data for two previous bar, and in cBot you are trying to get the current bar, that's one issue.

The other one is related to your indicator HIGHstartCountIndexZERO variable, this causes not deterministic results between cBot indicator and the one you attached on the chart.

Try my attached versions of your indicator and cBot, and you will see that their results will match on visual back test.

Indicator:

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

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SELL_LIQ : Indicator
    {
        [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; }

        [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);
        }

        private int HIGHstartCountIndexZERO = 0;

        public override void Calculate(int index)
        {
            sell_ONE[index - 2] = double.NaN;
            liq_ONE[index - 2] = double.NaN;

            var high = 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 close = Bars.ClosePrices[index];

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

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

            if (high == 0)
            {
                sell_ONE[index - 2] = double.NaN;
                liq_ONE[index - 2] = double.NaN;
            }
            else if (high == 1)
            {
                // I changed the logic here to find what's causing the discrepancy
                // between bot and indicator outputs
                if (Bars.ClosePrices[index - 2] > Bars.OpenPrices[index - 2])
                {
                    sell_ONE[index - 2] = Bars.HighPrices[index - 2];
                }
                else
                {
                    liq_ONE[index - 2] = Bars.LowPrices[index - 2];
                }

                //HIGHstartCountIndexZERO += 1;

                //if (HIGHstartCountIndexZERO % 2 != 0)
                //{
                //    sell_ONE[index - 2] = Bars.HighPrices[index - 2];
                //}
                //else
                //{
                //    liq_ONE[index - 2] = Bars.LowPrices[index - 2];
                //}
            }
        }
    }
}

cBot:

using cAlgo.API;

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SELL_LIQ_220220 : Robot
    {
        [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 SELL_LIQ S2;

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

        protected override void OnTick()
        {
            var index = Bars.Count - 1;

            var indicatorIndex = index - 2;

            Chart.RemoveObject(indicatorIndex.ToString());

            if (double.IsNaN(S2.sell_ONE[indicatorIndex]) == false)
            {
                Chart.DrawVerticalLine(indicatorIndex.ToString(), Bars.OpenTimes[indicatorIndex], Color.FromHex("#B511F7"));
            }
            else if (double.IsNaN(S2.liq_ONE[indicatorIndex]) == false)
            {
                Chart.DrawVerticalLine(indicatorIndex.ToString(), Bars.OpenTimes[indicatorIndex], Color.FromHex("#FF7CFC00"));
            }
        }
    }
}

Attach the indicator on visual back test chart, do some back testing on tick data not m1 bars, my result:

cTrader back tester loads some bars without running the cBot on those bars for warming up the indicators.

And if your indicator has some kind of non deterministic code like yours then the results will not match.

You see on my result, the first signal is not marked by cBot, because those bars were loaded by back tester for warm up.

Thank you! 

Interesting set up. The vertical lines though, just flashed up once on back-testing and dissappeared. 

 


@BJORNBERNAU