In Automate: ctrader indicator has 1 tick each bar, but cbot has two tick each bar

Created at 26 Oct 2023, 17:24
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!
HA

Hansen

Joined 30.01.2023

In Automate: ctrader indicator has 1 tick each bar, but cbot has two tick each bar
26 Oct 2023, 17:24


Reproduce step:

  1. click Automate button
  2. debug any indicator, you will see Calculate method only receive OLHC data when the bar is closed. 
  3. debug any cbot, you will see OnBar method will receive two tick OLHC data, first one occur when the bar is open, second one close the bar.

this behavior make my indicaor open position signal is diff from cbot. pls help me.

Related question:

I find indicatordataseries with output attribute has a side effort to call Cacluate method of indicator. 

such as 

 Class MyIndicator{
 	[Output(UpperBoundLineName, LineStyle = LineStyle.DotsRare, LineColor = "Pink")]
  	public IndicatorDataSeries UpperBound { get; set; }
  }

when i use indicator on my cbot, i do not want indicator use the bar which only have open price, so in the OnBar method, i minus 2 to assure bar has all the data.

such as

    class MyBot{
    	protected override void OnBar()
    	{
        	var index = Bars.Count - 2;


	
        	foreach (var baseStrategy in _baseStrategies)
        	{
            	baseStrategy.Run(index);
            	// will call UpperBound[index] in the trading logic
        	}
    	}
    }

but i find when i call MyIndicator with index 100, because i use `var index = Bars.Count - 2;`, the latest count is 101, and MyIndicator will use 101 to calc and the bar only have openprice, this behavior really confuse me. 

my question is 

  1. how to let my indicator and bot use bar with correct close price. Should i call MyIndicator.Calculate(index) in the OnBar method of my cbot and avoid use IndicatorDataSeries with output attribute, i do can use Dictionary insterad of IndicatorDataSeries
  2. After digging into cbot logic, I just want to know which method is best practice to implement a cbot with custom indcator. I mean Custom Indicator behavior as same as it be used in the cbot.

Best Wishes,

Hansen

 

 


@Hansen
Replies

Hansen
26 Oct 2023, 17:34 ( Updated at: 21 Dec 2023, 09:23 )

GPT3.5 answer...

@Hansen

PanagiotisChar
27 Oct 2023, 05:50

Hi Hansen,

Maybe it is better to provide a specific example demonstrating what you are looking at, since what you write is not true

  1. debug any indicator, you will see Calculate method only receive OLHC data when the bar is closed. 

This is not how it works. Calculate is called once for every historical bar and on every tick for the current bar. If you keep executing the Calculate until the bar is closed, then the value for the current bar will become equivalent to the closed bar.

  1. debug any cbot, you will see OnBar method will receive two tick OLHC data, first one occur when the bar is open, second one close the bar.

OnBar is called once every time a new bar is opened.


@PanagiotisChar

Hansen
31 Oct 2023, 01:23 ( Updated at: 21 Dec 2023, 09:23 )

RE: In Automate: ctrader indicator has 1 tick each bar, but cbot has two tick each bar

PanagiotisChar said: 

Hi Hansen,

Maybe it is better to provide a specific example demonstrating what you are looking at, since what you write is not true

  1. debug any indicator, you will see Calculate method only receive OLHC data when the bar is closed. 

This is not how it works. Calculate is called once for every historical bar and on every tick for the current bar. If you keep executing the Calculate until the bar is closed, then the value for the current bar will become equivalent to the closed bar.

  1. debug any cbot, you will see OnBar method will receive two tick OLHC data, first one occur when the bar is open, second one close the bar.

OnBar is called once every time a new bar is opened.

Sorry for not being clear,let me show you code, this code is from sample ema, i just add a print

// -------------------------------------------------------------------------------------------------
//
//    This code is a cTrader Automate API example.
//    
//    All changes to this file might be lost on the next application update.
//    If you are going to modify this file please make a copy using the "Duplicate" command.
//
// -------------------------------------------------------------------------------------------------

using cAlgo.API;

namespace cAlgo
{
    [Indicator(IsOverlay = true, TimeZone = TimeZones.UTC, AutoRescale = false, AccessRights = AccessRights.None)]
    public class SampleEMA : Indicator
    {
        [Parameter("Source")]
        public DataSeries Source { get; set; }

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

        [Output("Main", LineColor = "Turquoise")]
        public IndicatorDataSeries Result { get; set; }

        private double exp;

        protected override void Initialize()
        {
            exp = 2.0 / (Periods + 1);
        }

        public override void Calculate(int index)
        {
            Print($"Bars.HighPrices[{index}]={Bars.HighPrices[index]}, Bars.LowPrices[{index}]={Bars.LowPrices[index]}, Bars.OpenPrices[{index}]={Bars.OpenPrices[index]}, Bars.ClosePrices[{index}]={Bars.ClosePrices[index]}");
            var previousValue = Result[index - 1];

            if (double.IsNaN(previousValue))
                Result[index] = Source[index];
            else
                Result[index] = Source[index] * exp + previousValue * (1 - exp);
        }
    }
}

 

the result is 

you can see all the history data only have one output, which behavior will diff if you refer the indicator in the bot, so the calc results

will diff in the end.

I have a work around method for the behavior,  in the indicator method i add this code

        public override void Calculate(int index)
        {
            if (!IsInRealTime)
            {
                try
                {
                 
                    if (Bars.LowPrices[index] == Bars.HighPrices[index]
                        && Bars.LowPrices[index] == Bars.ClosePrices[index]
                        && Bars.LowPrices[index] == Bars.OpenPrices[index]
                       )
                    {
                        return;
                    }

                    ...
                }
                finally
                {
                    IsInRealTime = false;
                }
            }
        }

My purpose is let my backtest result as  same as real transaction, in order to avoid tick data infulence result, i also minus 2 of index in the cbot, is this the best practice? I think this is really ticky, so may ctrader team could give more complex examples.

    protected override void OnBar()
    {

        var index = Bars.Count - 2;
        ...
    }

@Hansen

PanagiotisChar
31 Oct 2023, 07:29

Hi there,

I still do not understand the problem since you did not provide enough information to reproduce it. If you share the cBot code that reproduces the problem I can advise further.


@PanagiotisChar