Bug when using Account.Equity

Created at 09 Oct 2013, 12:27
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!
JO

jobenb

Joined 07.10.2013

Bug when using Account.Equity
09 Oct 2013, 12:27


Hi

 

I have a method like so:

 

private int GetVolume()
        {
            return (int)((Account.Equity * 100) * 0.01);
        }

that is called in:

 

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

            int volume = GetVolume();

 

This result in the robot taking only one trade when backtesting, however if I change the OnBar() to the following it works:

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

            int volume = 10000;

 

Do you know why? I think it is a bug. I look forward to hear from you.

 

 


@jobenb
Replies

jobenb
09 Oct 2013, 12:29

RE:

jobenb said:

Hi

 

I have a method like so:

 

private int GetVolume()
        {
            return (int)((Account.Equity * 100) * 0.01);
        }

that is called in:

 

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

            int volume = GetVolume();

 

This result in the robot taking only one trade when backtesting, however if I change the OnBar() to the following it works:

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

            int volume = 10000;

 

Do you know why? I think it is a bug. I look forward to hear from you.

 

 

It works meaning that it takes more than just one trade. Seems that something gets locked by calling Account.Equity in OnBar()????


@jobenb

Spotware
11 Oct 2013, 12:52

If you like send us the complete code to engage@spotware.com so that we can investigate this.


@Spotware

jobenb
12 Oct 2013, 05:08

RE:

Spotware said:

If you like send us the complete code to engage@spotware.com so that we can investigate this.

Hi

Here is the code. I find cAlgo to be a lot of buggy and with quite a few memory leaks. Please fix it.

 

// -------------------------------------------------------------------------------
//
//    BrokenRobot version 1 
//
// -------------------------------------------------------------------------------

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

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

        [Parameter("SlippagePips", DefaultValue = 1, MinValue = 0)]
        public int SlippagePips { get; set; }

        [Parameter("Slow Moving Average Period", DefaultValue = 100, MinValue = 2)]
        public int SlowMovingAveragePeriod { get; set; }

        [Parameter("Fast Moving Average Period", DefaultValue = 20, MinValue = 1)]
        public int FastMovingAveragePeriod { get; set; }

        [Parameter("Slow Moving Average Type")]
        public MovingAverageType SlowMovingAverageType { get; set; }

        [Parameter("Fast Moving Average Type")]
        public MovingAverageType FastMovingAverageType { get; set; }

        private MovingAverage _slowMovingAverage;
        private MovingAverage _fastMovingAverage;
        private Position _position;


        protected override void OnPositionOpened(Position openedPosition)
        {
            _position = openedPosition;
        }

        protected override void OnStart()
        {
            _slowMovingAverage = Indicators.MovingAverage(Source, SlowMovingAveragePeriod, SlowMovingAverageType);
            _fastMovingAverage = Indicators.MovingAverage(Source, FastMovingAveragePeriod, FastMovingAverageType);
        }

        protected override void OnPositionClosed(Position position)
        {
            _position = null;
        }

        protected override void OnTick()
        {

        }

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

            // This does not work
            int volume = GetVolume();

            // This works
            //int volume = 10000;

            int lastSlowIndex = _slowMovingAverage.Result.Count - 2;
            int prevSlowIndex = _slowMovingAverage.Result.Count - 3;

            int lastFastIndex = _fastMovingAverage.Result.Count - 2;
            int prevFastIndex = _fastMovingAverage.Result.Count - 3;

            double currentSlowMa = _slowMovingAverage.Result[lastSlowIndex];
            double currentFastMa = _fastMovingAverage.Result[lastFastIndex];

            double previousSlowMa = _slowMovingAverage.Result[prevSlowIndex];
            double previousFastMa = _fastMovingAverage.Result[prevFastIndex];

            bool isLongPositionLastOpened = _position != null && _position.TradeType == TradeType.Buy;
            bool isShortPositionLastOpened = _position != null && _position.TradeType == TradeType.Sell;

            if (currentFastMa > currentSlowMa && previousFastMa <= previousSlowMa && !isLongPositionLastOpened)
            {
                Trade.Send(new MarketOrderRequest(TradeType.Buy, volume) 
                {
                    Label = "r1",
                    SlippagePips = SlippagePips
                });

                Trade.ModifyPosition(_position, Symbol.Bid - 20 * Symbol.PointSize, Symbol.Bid + 20 * Symbol.PointSize);
            }

            if (currentFastMa < currentSlowMa && previousFastMa >= previousSlowMa && !isShortPositionLastOpened)
            {
                Trade.Send(new MarketOrderRequest(TradeType.Sell, volume) 
                {
                    Label = "r1",
                    SlippagePips = SlippagePips
                });

                Trade.ModifyPosition(_position, Symbol.Bid + 20 * Symbol.PointSize, Symbol.Bid - 20 * Symbol.PointSize);
            }
        }

        private int GetVolume()
        {
            return (int)((Account.Equity * 100) * 0.01);
        }
    }
}


@jobenb

jobenb
12 Oct 2013, 05:13

RE: RE:

jobenb said:

Spotware said:

If you like send us the complete code to engage@spotware.com so that we can investigate this.

Hi

Here is the code. I find cAlgo to be a lot of buggy and with quite a few memory leaks. Please fix it.

 

// -------------------------------------------------------------------------------
//
//    BrokenRobot version 1 
//
// -------------------------------------------------------------------------------

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

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

        [Parameter("SlippagePips", DefaultValue = 1, MinValue = 0)]
        public int SlippagePips { get; set; }

        [Parameter("Slow Moving Average Period", DefaultValue = 100, MinValue = 2)]
        public int SlowMovingAveragePeriod { get; set; }

        [Parameter("Fast Moving Average Period", DefaultValue = 20, MinValue = 1)]
        public int FastMovingAveragePeriod { get; set; }

        [Parameter("Slow Moving Average Type")]
        public MovingAverageType SlowMovingAverageType { get; set; }

        [Parameter("Fast Moving Average Type")]
        public MovingAverageType FastMovingAverageType { get; set; }

        private MovingAverage _slowMovingAverage;
        private MovingAverage _fastMovingAverage;
        private Position _position;


        protected override void OnPositionOpened(Position openedPosition)
        {
            _position = openedPosition;
        }

        protected override void OnStart()
        {
            _slowMovingAverage = Indicators.MovingAverage(Source, SlowMovingAveragePeriod, SlowMovingAverageType);
            _fastMovingAverage = Indicators.MovingAverage(Source, FastMovingAveragePeriod, FastMovingAverageType);
        }

        protected override void OnPositionClosed(Position position)
        {
            _position = null;
        }

        protected override void OnTick()
        {

        }

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

            // This does not work
            int volume = GetVolume();

            // This works
            //int volume = 10000;

            int lastSlowIndex = _slowMovingAverage.Result.Count - 2;
            int prevSlowIndex = _slowMovingAverage.Result.Count - 3;

            int lastFastIndex = _fastMovingAverage.Result.Count - 2;
            int prevFastIndex = _fastMovingAverage.Result.Count - 3;

            double currentSlowMa = _slowMovingAverage.Result[lastSlowIndex];
            double currentFastMa = _fastMovingAverage.Result[lastFastIndex];

            double previousSlowMa = _slowMovingAverage.Result[prevSlowIndex];
            double previousFastMa = _fastMovingAverage.Result[prevFastIndex];

            bool isLongPositionLastOpened = _position != null && _position.TradeType == TradeType.Buy;
            bool isShortPositionLastOpened = _position != null && _position.TradeType == TradeType.Sell;

            if (currentFastMa > currentSlowMa && previousFastMa <= previousSlowMa && !isLongPositionLastOpened)
            {
                Trade.Send(new MarketOrderRequest(TradeType.Buy, volume) 
                {
                    Label = "r1",
                    SlippagePips = SlippagePips
                });

                Trade.ModifyPosition(_position, Symbol.Bid - 20 * Symbol.PointSize, Symbol.Bid + 20 * Symbol.PointSize);
            }

            if (currentFastMa < currentSlowMa && previousFastMa >= previousSlowMa && !isShortPositionLastOpened)
            {
                Trade.Send(new MarketOrderRequest(TradeType.Sell, volume) 
                {
                    Label = "r1",
                    SlippagePips = SlippagePips
                });

                Trade.ModifyPosition(_position, Symbol.Bid + 20 * Symbol.PointSize, Symbol.Bid - 20 * Symbol.PointSize);
            }
        }

        private int GetVolume()
        {
            return (int)((Account.Equity * 100) * 0.01);
        }
    }
}

 

 

 

 

 

 

Also using Account.Balance instead of Account.Equity produces a similar outcome. To me it seems as a thread locking issue.


@jobenb

Spotware
14 Oct 2013, 10:28

Volume needs to be rounded to 1000.

private int GetVolume()
{
    return ((int)(Account.Equity * 0.001) * 1000);
}

 


@Spotware

jobenb
14 Oct 2013, 14:46

RE:

Spotware said:

Volume needs to be rounded to 1000.

private int GetVolume()
{
    return ((int)(Account.Equity * 0.001) * 1000);
}

 

Excellent! Thank you! :-)


@jobenb