Indicator giving different results in the chart window compared to reading the value via code in back testing - Help!

Created at 28 Jun 2018, 22:02
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!
CT

ctid418503

Joined 04.05.2018

Indicator giving different results in the chart window compared to reading the value via code in back testing - Help!
28 Jun 2018, 22:02


Hi,

I'm writting a cBot based on my VWAP indicator:

https://ctdn.com/algos/indicators/show/1745

But I see a different value in the chart window compared to reading the value programatically:

                if (buy_tradeflg == true && Positions.Count == 0 && MarketSeries.Close.Last(1) > vwap.Result.Last(1) && MarketSeries.Low.Last(1) < vwap.Result.Last(1))
                {
                    Print("MarketSeries.Close.Last(1) {0} MarketSeries.Low.Last(1) {1} vwap.Result.Last(1) {2}", MarketSeries.Close.Last(1), MarketSeries.Low.Last(1), vwap.Result.Last(1));
                    double StopLoss = (Math.Abs(MarketSeries.Low.Last(1) - MarketSeries.High.Last(1)) / Symbol.PipSize) * 3;

                    TradeResult tres = ExecuteMarketOrder(TradeType.Sell, Symbol, 100000, "VB", StopLoss, 9999);
                    if (tres.IsSuccessful != true)
                        Print("Error executing market order");
                    buy_tradeflg = false;
                }

So I'm basically saying if MarketSeries.Close.Last(1) is above the vwap.Result.Last(1) and the MarketSeries.Low.Last(1) is below the vwap.Result.Last(1), i.e. the last candle broke through the vwap and closed above it, then execute the market order.  However look here:

 


@ctid418503
Replies

PanagiotisCharalampous
29 Jun 2018, 10:47

Hi ctid418503,

Can you share with us the cBot code as wel as the backtesting parameters so that we can reproduce this behavior?

Best Regards,

Panagiotis


@PanagiotisCharalampous

ctid418503
29 Jun 2018, 11:41

Sure.  The parameters are:

[ChartParameters]
Symbol = GBPUSD
Timeframe = m5

[cBotParameters]
SessionStart = 8
SessionLen = 8

  • 10,000 starting capital
  • Tick Data from Server
  • Commision: 35

You can see that order in the picture from the 26th December if you use 25/12/2014 as the start date and 27/12/2014 as the end date assuming your tick data is roughly similar to that from my broker.  But the issue happens throughout the backtesting if you use a longer period.  You would have to install that indicator I linked to above.  Code for the CBot:

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.GMTStandardTime, AccessRights = AccessRights.None)]
    public class VWAPBreakout : Robot
    {

        [Parameter("Session Start Hour", DefaultValue = 8, MinValue = 0, Step = 1)]
        public int SessionStart { get; set; }

        [Parameter("Session Length (Hours)", DefaultValue = 5, MinValue = 0, Step = 1)]
        public int SessionLen { get; set; }

        private MarketSeries seriesD1;

        private TrueRange tr;
        private AverageTrueRange atr;
        private VWAP vwap;
        bool buy_tradeflg = true;
        bool sell_tradeflg = true;

        protected override void OnStart()
        {
            // Put your initialization logic here
            seriesD1 = MarketData.GetSeries(TimeFrame.Daily);
            tr = Indicators.TrueRange(seriesD1);
            atr = Indicators.AverageTrueRange(seriesD1, 14, MovingAverageType.Simple);
            vwap = Indicators.GetIndicator<VWAP>(0, false);
            //Print("VWAP = {0}", vwap.Result[vwap.Result.Count - 1]);
        }

        protected override void OnBar()
        {
            // Put your core logic here
            double ATRange = atr.Result.LastValue;
            double DayRange = tr.Result.LastValue;
            //Print("ATR Range = {0}, Day Range = {1}", ATRval, DayRange);

            double totcnt = 0;
            double belowcnt = 0;
            double abovecnt = 0;

            for (int ii = 0; MarketSeries.OpenTime.Last(ii).Hour > SessionStart || MarketSeries.OpenTime.Last(ii).Minute != 0; ii++)
            {
                //Print("MarketSeries.Close.Last {0} vwap.Result.Last {1}", MarketSeries.Close.Last(ii), vwap.Result.Last(ii));
                if (MarketSeries.Close.Last(ii) < vwap.Result.Last(ii))
                {
                    belowcnt++;
                    //Print("VWAP was above price {0}", MarketSeries.OpenTime.Last(ii).Minute);
                }
                else
                {
                    abovecnt++;
                }

                totcnt++;

            }
            //Print("below count: {0}, total count: {1} --- {2}", belowcnt, totcnt, (belowcnt / totcnt) * 100);
            double abv_percent = 0;
            double blw_percent = 0;
            if (totcnt > 0)
            {
                blw_percent = (belowcnt / totcnt) * 100;
                abv_percent = (abovecnt / totcnt) * 100;
            }

            // Buy logic

            //if (blw_percent > 70 && DayRange < (ATRange * 1.3))
            //    Print("Price below VWAP {0} percent of time", blw_percent);

            if (blw_percent > 70 && Time.Hour > SessionStart + 1 && Time.Hour < SessionStart + SessionLen - 1 && DayRange < (ATRange * 1.3))
            {
                if (buy_tradeflg == true && Positions.Count == 0 && MarketSeries.Close.Last(1) > vwap.Result.Last(1) && MarketSeries.Low.Last(1) < vwap.Result.Last(1))
                {
                    Print("MarketSeries.Close.Last(1) {0} MarketSeries.Low.Last(1) {1} vwap.Result.Last(1) {2}", MarketSeries.Close.Last(1), MarketSeries.Low.Last(1), vwap.Result.Last(1));
                    double StopLoss = (Math.Abs(MarketSeries.Low.Last(1) - MarketSeries.High.Last(1)) / Symbol.PipSize) * 3;

                    TradeResult tres = ExecuteMarketOrder(TradeType.Sell, Symbol, 100000, "VB", StopLoss, 9999);
                    if (tres.IsSuccessful != true)
                        Print("Error executing market order");
                    buy_tradeflg = false;
                }
            }
            if (MarketSeries.Close.Last(0) < vwap.Result.Last(0))
                buy_tradeflg = true;

            // Sell logic

            // if (abv_percent > 70 && DayRange < (ATRange * 1.3))
            //     Print("Price above VWAP {0} percent of time", abv_percent);

            if (abv_percent > 70 && Time.Hour > SessionStart + 1 && Time.Hour < SessionStart + SessionLen - 1 && DayRange < (ATRange * 1.3))
            {
                if (sell_tradeflg == true && Positions.Count == 0 && MarketSeries.Close.Last(1) < vwap.Result.Last(1) && MarketSeries.Close.Last(2) > vwap.Result.Last(2))
                {

                    double StopLoss = (Math.Abs(MarketSeries.Low.Last(1) - MarketSeries.High.Last(1)) / Symbol.PipSize) * 1.5;

                    TradeResult tres = ExecuteMarketOrder(TradeType.Buy, Symbol, 100000, "VB", StopLoss, 9999);
                    if (tres.IsSuccessful != true)
                        Print("Error executing market order");
                    sell_tradeflg = false;
                }
            }
            if (MarketSeries.Close.Last(0) > vwap.Result.Last(0))
                sell_tradeflg = true;


            if (Time.Hour == SessionStart + SessionLen && Time.Minute == 0)
            {

                foreach (var position in Positions)
                {
                    if (position.Label.Equals("VB") && position.SymbolCode == Symbol.Code)
                        ClosePosition(position);
                }

            }



        }

        protected override void OnStop()
        {
            // Put your deinitialization logic here
        }
    }
}

 


@ctid418503

PanagiotisCharalampous
03 Jul 2018, 11:08

Hi ctid418503,

An initial investigation has shown that this is caused by the fact that the cBot and the Indicator are using different timezones. If you can set them to the same timezone the issue will be resolved. In the meanwhile we will investigate further why this happens.

Best Regards,

Panagiotis


@PanagiotisCharalampous

ctid418503
03 Jul 2018, 11:32

Hi Panagiotis,

Thanks for looking into this.  The Indicator and the cBot using different time zones was also my initial thought and I've tried that and it still shows the same effect.  Has someone actually tested that?

If you set the Indicator to use  TimeZones.GMTStandardTime and change the line:

if (MarketSeries.OpenTime[ii].Hour == 0 && MarketSeries.OpenTime[ii].Minute == 0)

to

if (MarketSeries.OpenTime[ii].Hour == 5 && MarketSeries.OpenTime[ii].Minute == 5)

So that the indicator is working with GMT but resetting the calculation at 5am (simulating EST) and rerun the same test I outlined above you will get the same difference between the chart and what the Cbot reads programmatically.  So it doesn't seem to be that.  I've just repeated this test now incase I was mistaken and it does the same thing.

Cheers


@ctid418503

PanagiotisCharalampous
03 Jul 2018, 11:50

Hi ctid418503,

Can you try setting both on UTC?

Best Regards,

Panagiotis


@PanagiotisCharalampous

ctid418503
03 Jul 2018, 12:40

Hi,

Setting both to UTC removes the discrepancy between the chart and what the Cbot reads programmatically.  However, as I am sure you appreciate, this is not a complete solution.  We don't want to have to manually code the Cbots and indicators to take care of all the different dates for Daylight Saving Time and adjust accordingly.  This is what the Timezone setting should do for us isn't it?  It seems that this is quite a dangerous bug.

I am assuming this only affects custom indicators - are all the standard ones using only UTC?

Please keep us updated on when a permanent fix will be available.

Thanks


@ctid418503

PanagiotisCharalampous
03 Jul 2018, 12:43

Hi ctid418503,

I mentioned above that we are still investigating this issue. 

Best Regards,

Panagiotis


@PanagiotisCharalampous

ctid418503
03 Jul 2018, 12:52

Thanks for your support.  I didn't indend to sound pushy.  It's just that I have a lot of cBots which work with different session start and end times and I'm not sure whether I should set them all to UTC and then do a lot of coding work to manually handle DST or wait for a fix.


@ctid418503

PanagiotisCharalampous
03 Jul 2018, 17:45

Hi ctid418503,

The discrepancy is caused by the fact that indicators referenced from a cBot take the timezone of the cBot and this is also related to the way you calculate VWAP. If the VWAP is considering the days based on different timezones then the results will be different.  If you want your indicator in the cBot to yield the same results to the indicator of the chart, then the cBot should operate on the same timezone as the indicator on the chart.

Best Regards,

Panagiotis


@PanagiotisCharalampous

ctid418503
03 Jul 2018, 18:33

indicators referenced from a cBot take the timezone of the cBot

Ok, understood.  I didn't know that.  

But..

If you want your indicator in the cBot to yield the same results to the indicator of the chart, then the cBot should operate on the same timezone as the indicator on the chart

Why did it show the same issue when I had both the Cbot and the Indicator set to GMT?  So in that case, if I understood, the Indicator used in the Cbot will use GMT because it inherited it from the Cbot, and the indicator on the chart will also use GMT because won't it use use the Timezone declared in the indicator (also GMT)?


@ctid418503

ctid418503
04 Jul 2018, 11:51

I'm sorry.  I think that there was some kind of refresh issue.  When I tried again after setting both the indicator and the Cbot to GMT and rebooted my computer I no longer see a difference between the chart and what the Cbot is reading.  Normally when I recompile an indicator already on a chart I see the changes reflected immediately, however I think it must be hanging onto the timezone even after a recompile so perhaps removing the indictor from the chart and re-adding it will work or restarting CTrader.


@ctid418503

ctid418503
04 Jul 2018, 14:45

It seems really difficult to make a Cbot react to a change in code in an indicator which I think has lead to alot of the confusion.  If I recompile an indicator I see the change reflected immediately after in the chart window but the Cbot still uses the old version.  I tried without succes:

  • Removing the Cbot instance and re-adding it
  • Closing and restarting Ctrader/Calgo
  • Rebooting the computer

None of these actually did anything.  I finally got it to react to the changes by deleting the Cbot and creating a new one, pasting the Cbot code in and recompiling.  Is there an easier way?

Thanks


@ctid418503

PanagiotisCharalampous
04 Jul 2018, 14:55

Hi ctid418503,

Did you try recompiling the cBot as well each time you make a change in the indicator?

Best Regards,

Panagiotis


@PanagiotisCharalampous

ctid418503
04 Jul 2018, 17:09

I won't have done because the red asterisk thing which appears when the Cbot needs rebuilding doesn't appear if the indicator is changed.

I have tried that now, and it does work.  I needed to add a character to the Cbot and then delete it to make it think it has changed for the Build icon to become active.

Thanks a lot!


@ctid418503