Help with difference between indicator and robot behaviour

Created at 12 Jun 2014, 00:37
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!
PR

Prospect

Joined 21.03.2014

Help with difference between indicator and robot behaviour
12 Jun 2014, 00:37


Hi all,

This is probably something obvious, whatever it is, it's eluding me at the moment.

I've been playing around with an MACD type indicator in order to learn the platform really. To visualise how a robot referencing the indicator might behave I wrote another indicator which references the MACD type indicator and just draws a vertical green or red line when the signal line crosses in either direction, green when a long position should be opened, red for short.

This is what it looks like:

I've then tried to take the code from the reference indicator and create a robot, but the behaviour during backtesting is very different and I was hoping someone could help me with why?

The "U shape" pattern around the 15th May for example, what the indicator looks like it should do = great, what the robot does, not so great. Any ideas?

Indicator code:

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

namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC)]
    public class MDCD : Indicator
    {
        [Parameter()]
        public DataSeries Source { get; set; }

        [Parameter(DefaultValue = 100)]
        public int percentPeriod { get; set; }

        [Parameter(DefaultValue = 9)]
        public double EMAperiod { get; set; }

        [Output("MDMACD", Color = Colors.Blue)]
        public IndicatorDataSeries MDMACD { get; set; }

        [Output("MDEMA", Color = Colors.Red)]
        public IndicatorDataSeries MDEMAResult { get; set; }


        private double exp, MD12, MD26;
        private IndicatorDataSeries MD12Result, MD26Result;


        protected override void Initialize()
        {
            exp = 2 / (EMAperiod + 1);

            MD12 = 12;
            MD26 = 26;

            MD12Result = CreateDataSeries();
            MD26Result = CreateDataSeries();
        }

        public override void Calculate(int index)
        {
            MD12Result[index] = MD(MD12 * percentPeriod / 100, MD12Result[index - 1], Source[index]);
            MD26Result[index] = MD(MD26 * percentPeriod / 100, MD26Result[index - 1], Source[index]);

            MDMACD[index] = MD12Result[index] - MD26Result[index];
            MDEMAResult[index] = MDEMA(MDMACD[index - 1], MDMACD[index]);
        }

        public double MD(double ratio, double previousValue, double input)
        {
            if (double.IsNaN(previousValue))
            {
                return input;
            }
            else
            {
                double currentValue = previousValue + (input - previousValue) / ratio * Math.Pow((input / previousValue), 4);
                return currentValue;
            }
        }

        public double MDEMA(double previousValue, double input)
        {
            if (double.IsNaN(previousValue))
            {
                return input;
            }
            else
            {
                double EMA = (input - previousValue) * exp + previousValue;
                return EMA;
            }
        }
    }
}

Reference indicator code:

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


namespace cAlgo
{
    [Indicator(IsOverlay = false, TimeZone = TimeZones.UTC)]
    public class NewIndicator : Indicator
    {
        [Parameter()]
        public DataSeries Source { get; set; }

        [Parameter(DefaultValue = 100)]
        public int percentPeriod { get; set; }

        [Parameter(DefaultValue = 9)]
        public double EMAperiod { get; set; }

        [Output("MDMACD", Color = Colors.Blue)]
        public IndicatorDataSeries MDResult { get; set; }

        [Output("MDEMA", Color = Colors.Red)]
        public IndicatorDataSeries SignalResult { get; set; }

        MDCD mdcd;

        protected override void Initialize()
        {
            mdcd = Indicators.GetIndicator<MDCD>(Source, percentPeriod, EMAperiod);
        }

        public override void Calculate(int index)
        {
            double previousSignalval = mdcd.MDEMAResult[index - 1];
            double currentSignalval = mdcd.MDEMAResult[index];

            double previousMDval = mdcd.MDMACD[index - 1];
            double currentMDval = mdcd.MDMACD[index];

            if (previousSignalval > previousMDval && (currentSignalval == currentMDval || currentSignalval < currentMDval))
            {
                ChartObjects.DrawVerticalLine("vLine" + index, index, Colors.Green, 1, LineStyle.Dots);
            }

            if (previousSignalval < previousMDval && (currentSignalval == currentMDval || currentSignalval > currentMDval))
            {
                ChartObjects.DrawVerticalLine("vLine2" + index, index, Colors.Red, 1, LineStyle.Dots);
            }

            MDResult[index] = mdcd.MDMACD[index];
            SignalResult[index] = mdcd.MDEMAResult[index];
        }
    }
}

Robot code:

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC)]
    public class MDCDcBot001 : Robot
    {
        [Parameter()]
        public DataSeries Source { get; set; }

        [Parameter("EMA Period", DefaultValue = 9)]
        public double EMAperiod { get; set; }

        [Parameter("% of MD Period", DefaultValue = 100)]
        public int percentPeriod { get; set; }

        [Parameter(DefaultValue = 10000, MinValue = 0)]
        public int Volume { get; set; }


        private Position position;
        private MDCD mdcd;

        protected override void OnStart()
        {
            Positions.Opened += Positions_Opened;

            mdcd = Indicators.GetIndicator<MDCD>(Source, percentPeriod, EMAperiod);
        }

        protected override void OnTick()
        {
            if (Trade.IsExecuting)
                return;

            int lastIndex = mdcd.MDMACD.Count - 1;
            int prevIndex = mdcd.MDMACD.Count - 2;

            bool isLongPositionOpen = position != null && position.TradeType == TradeType.Buy;
            bool isShortPositionOpen = position != null && position.TradeType == TradeType.Sell;

            double previousSignalval = mdcd.MDEMAResult[prevIndex];
            double currentSignalval = mdcd.MDEMAResult[lastIndex];

            double previousMDval = mdcd.MDMACD[prevIndex];
            double currentMDval = mdcd.MDMACD[lastIndex];

            if (previousSignalval > previousMDval && (currentSignalval == currentMDval || currentSignalval < currentMDval) && !isLongPositionOpen)
            {
                Print("BUY - preSignal:{0} preMD:{1} curSignal:{2} curMD:{3}", previousSignalval, previousMDval, currentSignalval, currentMDval);

                ClosePosition();
                Buy();
            }

            if (previousSignalval < previousMDval && (currentSignalval == currentMDval || currentSignalval > currentMDval) && !isShortPositionOpen)
            {
                Print("SELL - preSignal:{0} preMD:{1} curSignal:{2} curMD:{3}", previousSignalval, previousMDval, currentSignalval, currentMDval);
                ClosePosition();
                Sell();
            }


        }


        private void ClosePosition()
        {
            if (position != null)
            {
                ClosePosition(position);
                position = null;
            }
        }

        private void Buy()
        {
            ExecuteMarketOrder(TradeType.Buy, Symbol, Volume);
        }


        private void Sell()
        {
            ExecuteMarketOrder(TradeType.Sell, Symbol, Volume);
        }


        private void Positions_Opened(PositionOpenedEventArgs args)
        {
            position = args.Position;
        }


    }
}

 


@Prospect
Replies

Spotware
12 Jun 2014, 09:28

You can try to use OnBar method instead of OnTick. Please don't forget that last bar is not formed in OnBar method and you need to take values from previous index.


@Spotware

Prospect
13 Jun 2014, 12:13

RE:

Spotware said:

You can try to use OnBar method instead of OnTick. Please don't forget that last bar is not formed in OnBar method and you need to take values from previous index.

OK, that makes sense, I'll give it ago with something like this?


            int lastIndex = MarketSeries.Close - 2;
            int prevIndex = MarketSeries.Close - 3;

Thanks.


@Prospect

Prospect
13 Jun 2014, 12:14

RE: RE:

badmonkeyface said:

Spotware said:

You can try to use OnBar method instead of OnTick. Please don't forget that last bar is not formed in OnBar method and you need to take values from previous index.

OK, that makes sense, I'll give it ago with something like this?


            int lastIndex = MarketSeries.Close - 2;
            int prevIndex = MarketSeries.Close - 3;

Thanks.

This is what I meant:

            int lastIndex = MarketSeries.Close.Count - 2;
            int prevIndex = MarketSeries.Close.Count - 3;

 


@Prospect

Prospect
13 Jun 2014, 12:26

That's looking better now. Thanks.


@Prospect