Results from indicator are different on the chart than when used in a robot

Created at 11 Mar 2013, 04:58
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!
lec0456's avatar

lec0456

Joined 14.11.2012

Results from indicator are different on the chart than when used in a robot
11 Mar 2013, 04:58


I have an indicator I use in a robot but the results is posts to the chart are different from the results is provides to my robot.  This is very eratic.  I would really aprieciate some help with this issue as it renders the platform useless.

Here is the code for the indicator:

//#reference: C:\Users\lcespedes\Documents\cAlgo\Sources\Indicators\myMASlope.algo

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

namespace cAlgo.Indicators
{
    [Indicator(IsOverlay = false, ScalePrecision=2)]
    public class myTrend : Indicator
    { 
        [Parameter(DefaultValue = 240)]
        public int paramPeriods {get; set;}
		[Parameter(DefaultValue = .8)]
        public double paramSlopeLimit {get; set;}
        [Parameter(DefaultValue = .05)]
        public double paramSlopeTolerance {get; set;}
        
		[Output("TrendUpPlot", PlotType = PlotType.Points, Thickness = 5, Color = Colors.Green)]
        public IndicatorDataSeries TrendUpIndicator { get; set; }
        [Output("TrendDnPlot", PlotType = PlotType.Points, Thickness = 5, Color = Colors.Red)]
        public IndicatorDataSeries TrendDnIndicator { get; set; }
        [Output("RangingPlot", PlotType = PlotType.Points, Thickness = 5, Color = Colors.White)]
        public IndicatorDataSeries RangingIndicator { get; set; }
        
		private myMASlope maslope;
		private bool isTrendingUp;
		private bool isTrendingDn;
		private bool isRanging;

        protected override void Initialize(){maslope = Indicators.GetIndicator<myMASlope>(paramPeriods,paramSlopeLimit);}

        public override void Calculate(int index)
        {
			//** skip printing bar until moving average data is calculated
			int t0=index;
			if(double.IsNaN(maslope.Result[index]))return;
			
			decimal MASlope=(decimal) maslope.Result[index];

			//if the MA is ranging it must reach a certain slope before considered ranging.
			decimal MAUpTrendLimit=(decimal)paramSlopeLimit;
			decimal MADnTrendLimit=(decimal)paramSlopeLimit;
			
			//Once it is trending in a direction it must reach a certain slope tolerance 
			//past zero before it is considered an end to the trend and begins ranging.
			if (isTrendingUp)MAUpTrendLimit=(decimal)-paramSlopeTolerance;
			if (isTrendingDn)MADnTrendLimit=(decimal)-paramSlopeTolerance;
			
			isTrendingUp =(MASlope>MAUpTrendLimit);
			isTrendingDn =(MASlope<-MADnTrendLimit);
			isRanging = !isTrendingUp && !isTrendingDn;
			
			if (isTrendingUp)TrendUpIndicator[index]=1;
			if (isTrendingDn)TrendDnIndicator[index]=-1;
			if (isRanging)   RangingIndicator[index]=0;
			Print("{0:MM/dd/yyyy HH:mm} Trend:{1} | {2} | {3} | {4}", MarketSeries.OpenTime[t0],paramPeriods,TrendUpIndicator[t0],RangingIndicator[t0],TrendDnIndicator[t0]);

        }
    }
}

Hereis the code for the Robot:

//#reference: C:\Users\lcespedes\Documents\cAlgo\Sources\Indicators\myTrend.algo
using System;
using System.Collections.Generic;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.Indicators;
using cAlgo.API.Requests;
 
namespace cAlgo.Robots
{
    [Robot]
    public class TestTrendBot : Robot
    {
		private myTrend trendShort;
        
        protected override void OnStart(){trendShort = Indicators.GetIndicator<myTrend>(60,1.9,.6);}
        
        protected override void OnBar()
        {
            if (Trade.IsExecuting) return;
 
			int t0 = MarketSeries.Close.Count-1;//** t0 results are not final because the bar has not completed
        	Print("{0:MM/dd/yyyy HH:mm} Shrt:{1} | {2} | {3}", MarketSeries.OpenTime[t0],trendShort.TrendUpIndicator[t0],trendShort.RangingIndicator[t0],trendShort.TrendDnIndicator[t0]);
 
        }
    }
}

Here is the code for the indicator used by the indicator:

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

namespace cAlgo.Indicators
{ 
    [Indicator(IsOverlay = false, ScalePrecision = 2, AutoRescale=true)]
    public class myMASlope : Indicator
    {
	 	[Parameter(DefaultValue = 60)]
        public int Periods { get; set; }
        [Parameter(DefaultValue = 2.4)]
        public double paramLimit { get; set; }
		
		[Output("MA Slope", PlotType = PlotType.Histogram, Thickness = 2, Color = Colors.Purple)]
        public IndicatorDataSeries Result { get; set; }
        [Output("UpperLimit", PlotType = PlotType.Line, LineStyle=LineStyle.DotsRare,Thickness = 1, Color = Colors.Red)]
        public IndicatorDataSeries UpperLimit { get; set; }
        [Output("LowerLimit", PlotType = PlotType.Line, LineStyle=LineStyle.DotsRare, Thickness = 1, Color = Colors.Red)]
        public IndicatorDataSeries LowerLimit { get; set; }
        [Output("Peak", PlotType = PlotType.Line, LineStyle=LineStyle.DotsRare,Thickness = 1, Color = Colors.Red)]
        public IndicatorDataSeries Peak { get; set; }
        [Output("Valley", PlotType = PlotType.Line, LineStyle=LineStyle.DotsRare, Thickness = 1, Color = Colors.Red)]
        public IndicatorDataSeries Valley { get; set; }
        [Output("Center", LineStyle=LineStyle.DotsRare, Color = Colors.White)]
        public IndicatorDataSeries CenterLine { get; set; }
        
		private SimpleMovingAverage MA;

        protected override void Initialize(){MA = Indicators.SimpleMovingAverage(MarketSeries.Open,Periods);}

        public override void Calculate(int index)
        { 
			int t0 = index;
			int t1 = t0 - 1;
			 
			if(t1<0)return;//** prevent crash caused by posibly using a negetive index value
			
			if(double.IsNaN(MA.Result[t1]))return; //** skip printing bar until moving average data is calculated

//Print("{0,20} | {1,20} | {2,20}",MarketSeries.OpenTime[t0],MA.Result[t0],Math.Round((MA.Result[t0]-MA.Result[t1])/Symbol.PointSize,2));

			//Peak[index]=5;// equal to half a pip
	        //Valley[index]=-5; 
	        UpperLimit[index]=paramLimit;
			LowerLimit[index]=-paramLimit;
			CenterLine[index]=0;
			Result[index]= Math.Round((MA.Result[t0]-MA.Result[t1])/Symbol.PointSize,2);
        }
    }
}




@lec0456
Replies

cAlgo_Fanatic
11 Mar 2013, 11:07

Hello,

The print statements from the indicator and the robot match. If this is not the issue please provide us with some more information (i.e. a screenshot indicating the difference or some more explanation).

Also please ensure you are using the same parameters for the indicator and the robot as the default parameters for the myTrend are not the same used in the Robot:

trendShort = Indicators.GetIndicator<myTrend>(60, 1.9, .6);

Whereas, the myTrend default parameters are: 240, 0.8,0.05


@cAlgo_Fanatic

lec0456
11 Mar 2013, 18:54 ( Updated at: 21 Dec 2023, 09:20 )

RE:
cAlgo_Fanatic said:

Hello,

The print statements from the indicator and the robot match. If this is not the issue please provide us with some more information (i.e. a screenshot indicating the difference or some more explanation).

Also please ensure you are using the same parameters for the indicator and the robot as the default parameters for the myTrend are not the same used in the Robot:

trendShort = Indicators.GetIndicator<myTrend>(60, 1.9, .6);

Whereas, the myTrend default parameters are: 240, 0.8,0.05

ok yes, I used the correct parameters for the indicator as in the robot (60,1.9,.6)  If you look at 3/7/13 at 8am the indicator shows 0 or ranging but the print statement in the robot shows -1 or down trend.

Realize I simplified the robot so you could troubleshoot the issue but it does more stuff than just print.  

Right, so if you backtest the robot you will see print statements from the robot and the indicator and they match.  But if you apply the indicator to the chart you get different results.

Capture1 shows the indicator as applied to the chart, make note of the log at time 3/7/13 8am trend is indicating 0

Now look at the Robot, Capture 1a shows the trend as -1

 

See what I mean??


@lec0456

lec0456
12 Mar 2013, 00:34 ( Updated at: 21 Dec 2023, 09:20 )

OK, I did some more troubleshooting and what is happenening is that your indicator simplemoving average is giving different values to the robots than outputing to the chart.

So, first you can forget the my trend indicator I sent you it is not the issue.

I placed a print statement in the MASlope indicator, like so:

 Print("{0,20:MM/dd/yyyy HH:mm} | {1,20} | {2,20} | {3,20}",MarketSeries.OpenTime[t0],MA.Result[t0],MA.Result[t1],Math.Round((MA.Result[t0]-MA.Result[t1])/Symbol.PointSize,2));

 

In the robot I took out the print statement and placed a dummy variable to read the indicator otherwise it will not print in the log, like so:

             double test=trendShort.TrendDnIndicator[t0];

The log of the indicator looks like this

:

The log of the robot looks like this:

 

The values for the moving averages are different! So the slopes are different and thats why my trend indicator was acting erratic.  


@lec0456

cAlgo_Fanatic
12 Mar 2013, 11:53 ( Updated at: 21 Dec 2023, 09:20 )

Please remove all the code except for the print statements which should be identical in order to verify that the indicator produces the same results.

These are the logs for Period 60 m1 timeframe:

 

The code:

Indicator:

        [Parameter(DefaultValue = 60)]
        public int Periods { get; set; }

        private SimpleMovingAverage MA;
	int t0 = -1;
		
        protected override void Initialize() 
        { 
             MA = Indicators.SimpleMovingAverage(MarketSeries.Open, Periods); 
} public override void Calculate(int index) { if(!IsRealTime) return; if(t0!= index) // Force to print only once per bar { t0 = index; int t1 = t0 - 1; Print("{0,20} | {1,20} | {2,20} | {3,20} ",MarketSeries.OpenTime[t0],MA.Result[t0], MA.Result[t1],Math.Round((MA.Result[t0]-MA.Result[t1])/Symbol.PointSize,2)); } }


The Robot:

        SimpleMovingAverage MA;

        protected override void OnStart() 
        {
		MA = Indicators.SimpleMovingAverage(MarketSeries.Open, 60);
        }

        protected override void OnBar()
        {
            int t0 = MarketSeries.Close.Count - 1;//** t0 results are not final because the bar has not completed
            int t1 = t0-1;
            Print("{0,20} | {1,20} | {2,20} | {3,20} ",MarketSeries.OpenTime[t0],MA.Result[t0], MA.Result[t1],Math.Round((MA.Result[t0]-MA.Result[t1])/Symbol.PointSize,2));
        }




@cAlgo_Fanatic

lec0456
12 Mar 2013, 19:15

But you are not using the indicator as a reference in the robot! you are recalculating within the robot.  that defeats the whole purpose of having indicators!  also the values do not differ throughout the whole series some times they are the same and sometimes they are not.  Thats what makes it erratic.  Also are you only testing this in realtime because I have been backtesting?  I see the IsRealTime statement in your indicator, thats why I'm asking?

But I am going to strip down both the indicator and the robot and send you the code with the results...give me a couple hours...


@lec0456

lec0456
12 Mar 2013, 19:17

i like the way you get the indicator to only print once,  could you explain how that works??  I never understood why it printed twice in the first place...


@lec0456

lec0456
13 Mar 2013, 01:25 ( Updated at: 21 Dec 2023, 09:20 )

The erratic behavior is repeating itself

Ok so I created simplifed indicators and robots and the sma's are still giving differnet results...

Here is the code for the indicator I used:

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

namespace cAlgo.Indicators
{ 
    [Indicator(IsOverlay = false)]
    public class testMASlopeIndicator : Indicator
    {
		[Output("MA Slope", PlotType = PlotType.Histogram, Thickness = 2, Color = Colors.Purple)]
        public IndicatorDataSeries Result { get; set; }
        
		private SimpleMovingAverage SMA;
		int t0=-1;

        protected override void Initialize(){SMA=Indicators.SimpleMovingAverage(MarketSeries.Open,60);}
        
        public override void Calculate(int index)
        { 
			if(t0!=index)
			{
				t0 = index;
				int t1 = t0 - 1;
				 
				if(t1<0)return;//** prevent crash caused by posibly using a negetive index value
				
				if(double.IsNaN(SMA.Result[t1]))return; //** skip printing bar until moving average data is calculated
	
				Print("{0,20:MM/dd/yyyy HH:mm} |  MA {1,30} | {2,30} | {3,30}",MarketSeries.OpenTime[t0],SMA.Result[t0],SMA.Result[t1],Math.Round((SMA.Result[t0]-SMA.Result[t1])/Symbol.PointSize,2)); 
				Result[index]= Math.Round((SMA.Result[t0]-SMA.Result[t1])/Symbol.PointSize,2);
        	}
        }
    }
}

Here is the code for the robot i used:

//#reference: C:\Users\lcespedes\Documents\cAlgo\Sources\Indicators\testMASlopeIndicator.algo
using System;
using System.Collections.Generic;
using cAlgo.API;
using cAlgo.API.Indicators;
using cAlgo.Indicators;
using cAlgo.API.Requests;
 
namespace cAlgo.Robots
{
    [Robot]
    public class TestMASlopeBot : Robot
    {
		private testMASlopeIndicator slope;
        
        protected override void OnStart(){ slope = Indicators.GetIndicator<testMASlopeIndicator>();}
        
        protected override void OnBar()
        {
            if (Trade.IsExecuting) return;
 
			int t0=MarketSeries.Close.Count-1;//** t0 results are not final because the bar has not completed
        	double test=slope.Result[t0];
        } 
    }  
}

I backtested for the last 7 days, used 60 periods for the SMA, Market Open data and 1 minute time frame. Here are the results for 7:32am and 8am for the robot and indicator...

 

Slope Robot @732am on 3/7/13

Slope Indicator @8am on 3/7/13

Slope Robot @8am on 3/7/13

 

Do you see how sometimes the values are the same and sometimes they differ? If you notice the numbers don't get back in sync until 7:46am. Do you see what I'm talking about now?


@lec0456

lec0456
13 Mar 2013, 01:29

BTW, this is using ICmarkets data and that first log is the Slope Indicator @7:34am on 3/7/13


@lec0456

lec0456
13 Mar 2013, 01:30

RE:
lec0456 said:

BTW, this is using ICmarkets data and that first log is the Slope Indicator @7:34am on 3/7/13

I mean 7:32am


@lec0456

cAlgo_Fanatic
13 Mar 2013, 12:09

RE:
lec0456 said:

i like the way you get the indicator to only print once,  could you explain how that works??  I never understood why it printed twice in the first place...

int t0 = -1 // initialize field to -1 
//...

// Force to print only once per bar within Calculate(int index)
if(t0!= index) // if global field is not equal to index
{
	t0 = index;  
Print... // etc. }

Since the Calculate() event is called on each tick that means that it will execute the code multiple times per bar. In order to Print only once per bar just add the print statement within an if statement to check if the index is not the same as with the previous call. The global field t0 will be assigned to value of the parameter index if they are not the same and the print will execute. The next call will not execute the print statement if t0 equals index since the condition will fail.

 


@cAlgo_Fanatic

cAlgo_Fanatic
13 Mar 2013, 12:13

RE: RE:
lec0456 said:
lec0456 said:

BTW, this is using ICmarkets data and that first log is the Slope Indicator @7:34am on 3/7/13

I mean 7:32am

So far we cannot reproduce the issue. We will continue testing and if something is identified we will let you know.
Regards,


@cAlgo_Fanatic

lec0456
13 Mar 2013, 18:32 ( Updated at: 21 Dec 2023, 09:20 )

Actually, I checked the results for your exact indicator and robot and at 7:32am on 3/713 it causes the same issue. So, you don't even have to have a reference to the custom indicator.  

 

So, the SimpleMovingAverage is not giving the same results as robots when backtesting.  Could you please send me screen shots of your results for 3/7/13at 7:32 am for each?  and could you please use ICmarkets data.


@lec0456

lec0456
13 Mar 2013, 18:33

Oh, the only thing I changed, obviously, was removing the IsRealTime statment in order to backtest


@lec0456

lec0456
13 Mar 2013, 19:16

And BTW, the differences are all throughout the data

 

Just by spot checking:

on 3/6/13 at 12:06am,12:10-12am,1:07am,1:13am,1:39am,2:28-30am, 3/11/13 5:45am, 5:54am

This issue exists and is real


@lec0456

lec0456
13 Mar 2013, 19:26

I will tell you what I think the issue could be...Using a double to hold all indicator values will introduce randomness in calculations because the use of decimals and division are not precise with doubles.  With C# You need to use decimal data type.  Thats just a hunch...


@lec0456

lec0456
13 Mar 2013, 20:25

I ran the same tests against FXPro data and the indicator and the Robot SMA's match.  I notice the versions of cAlgo are different.  the version of FXpro cAlgo is 1.0.26115 and ICMarkets cAlgo is 1.0.26114.  Don't know if that is the difference  but you can clearly see that IC Markets is giving different values for SMA between the indicators and Robots. please investigate!


@lec0456

cAlgo_Fanatic
14 Mar 2013, 14:18

We are investigating the issue and will let you know. 

 


@cAlgo_Fanatic

cAlgo_Development
14 Mar 2013, 15:33

Bug is reproduced and will be fixed

The reason of this incorrect behavior is a bug in our tick generation algorithm used in backtesting. We generate ticks using Minute trend bars. And in rare cases when one bar contains only two or three ticks, algorithm generates ticks so that last tick is goes to next bar. For that bar you can see that close price is incorrect and for next bar, open price is incorrect.

Fix for this bug will be released approximately in two weeks.

Thank you very much for this report.


@cAlgo_Development

lec0456
15 Mar 2013, 05:23

Fantastic! I'm just glad we were able to get to the bottom of this.  because in general I love the platform, it has a lot of potential!


@lec0456

lec0456
26 Apr 2013, 06:38

has this bug been fixed?

has this bug been fixed?


@lec0456

cAlgo_Development
29 Apr 2013, 17:54

Yes, the fix must be already released. Please check that results are the same now.


@cAlgo_Development