Big Big Memory Leak

Created at 12 Apr 2014, 03:51
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

Big Big Memory Leak
12 Apr 2014, 03:51


Hi

After a week of trading I wanted to stop my algos in cAlgo and shutdown, but unfortunately cAlgo was completely dead - unresponsive and slow.

So I started up Task Manager (which took about a minute due to cAlgo memory leak) and saw that cAlgo was using almost all of my memory - 15GB!

There is seriously something wrong with the way cAlgo handles its memory.

I did manage to send a Troubleshooting report to you by pressing Shift - Ctrl - Alt - T, so hopefully you can figure it out.

Please investigate and fix this issue ASAP.

Thank you.


@jobenb
Replies

Spotware
14 Apr 2014, 09:47

We can not reproduce such memory leaks by using our built-in samples.

Please review code of your cBots and Custom Indicators and try to find memory leaks there.


@Spotware

jobenb
07 May 2014, 15:56

Review Completed

Hi

I have thoroughly investigated and reviewed my code for any possible memory leak due to possible continuous expansion of a declared list or any other possibility. None were found.

The robot is very high frequency and open many positions at a time resulting in a lot of closed positions in the history as well as open positions over the course of a week of minute bar trading.

This result in Gigabytes of memory used by cAlgo without releasing any. This crash my computer and I have to force it to power off.  I do not use your sample robots for my actual trading, so I am sure that if you use only those for testing for memory leaks that you will find nothing. You need a high frequency robot trading like a mad man. Please test with a robot that open orders every minute and let it run for a week and compare the memory usage. Remember to add about 6 indicators and 2 different MarketSeries declarations; one referring to 1 minutes and the other to an hourly trend.

I really hope you find the cause as I unfortunately do not have access to the cAlgo code.

Thank you for a great platform so by the way. ;-) Just a few teething issues.

Kind regards,

 

Joben


@jobenb

jobenb
10 May 2014, 12:35

Any update from Spotware?


@jobenb

Spotware
12 May 2014, 10:26

Unfortunately we cannot reproduce this issue. If you send code of your cBot to engage@spotware.com it will simplify our search. We will use your cBot only for debugging purposes.


@Spotware

alifarooq
13 May 2014, 23:01

same here.


@alifarooq

AlexanderRC
26 May 2014, 11:59

I far as can tell, each robot runs in its own .Net application domain.

Here is a starting article to monitor memory usage per AppDomain.

http://msdn.microsoft.com/en-us/library/dd997285%28v=vs.110%29.aspx


@AlexanderRC

jobenb
11 Jun 2014, 14:53 ( Updated at: 21 Dec 2023, 09:20 )

Still Memory Problems in Current Release

Hi Guys

There are still memory problems in cAlgo. Unfortunately I cannot provide you with the proprietary algorithms for you to try and reproduce it, however I can show you where values are stored in which variables and try and show you that the memory leak ARE NOT in the robot itself.

Here are al the variables:

protected double CurrentGridSize { get; set; }

protected double? LastGridVolumeIncreasePrice { get; set; }

protected double? LastGridSetPrice { get; set; }

protected List<MovingAverage> FirstHighMovingAverages; ** NO MORE THAN 3 MOVING AVERAGES ARE STORED AND USED

protected List<MovingAverage> FirstLowMovingAverages; ** NO MORE THAN 3 MOVING AVERAGES ARE STORED AND USED

protected List<MovingAverage> SecondHighMovingAverages; ** NO MORE THAN 3 MOVING AVERAGES ARE STORED AND USED

protected List<MovingAverage> SecondLowMovingAverages; ** NO MORE THAN 3 MOVING AVERAGES ARE STORED AND USED

private MarketSeries _firstMovingAverageSeries;

private MarketSeries _secondMovingAverageSeries;

public virtual string FirstMovingAveragePeriods { get; set; }

public virtual MovingAverageType FirstMovingAverageType { get; set; }

public virtual TimeFrame FirstMovingAverageTimeFrame { get; set; }

public virtual string SecondMovingAveragePeriods { get; set; }

public virtual MovingAverageType SecondMovingAverageType { get; set; }

public virtual TimeFrame SecondMovingAverageTimeFrame { get; set; }

public virtual int CloseOrderTrigger { get; set; }

public virtual int GridSizePips { get; set; }

public virtual bool FullGridOrderTrigger { get; set; }

public virtual int VolumeIncrementPips { get; set; }

public virtual bool KeepMaxVolume { get; set; }

public virtual bool IncrementalPipsPerPositionEnabled { get; set; }

public virtual int IncrementalPipsPerPosition { get; set; }

public virtual bool DynamicGridEnabled { get; set; }

public virtual double DynamicGridFactor { get; set; }

[SaveState]

protected long? LastOrderVolume { get; set; }

[SaveState]

protected double? LastOrderPrice { get; set; }

[SaveState]

protected double OpeningBalance { get; set; }

protected double StrategyBalance { get; set; }

[SaveState]

protected TradeType? LastOrderTradeType { get; set; }

[SaveState]

protected TradeType? LastPendingOrderTradeType { get; set; }

[SaveState]

protected double? LastVolumeIncreasePrice { get; set; }

[SaveState]

protected double? LastIncrementVolumeBalance { get; set; }

[SaveState]

protected int LastStopLossPips { get; set; }

[SaveState]

protected int LastTargetPips { get; set; }

protected int LongPositionsCount { get; set; }

protected int ShortPositionsCount { get; set; }

protected string Label { get; set; }

protected int Index { get; set; }

protected bool StopTrailing { get; set; }

protected bool NewBar { get; set; }

[SaveState]

protected DateTime? ProfitTaken { get; set; }

protected List<Func<TradeType?>> Biases { get; set; }

protected List<Func<bool>> Filters { get; set; }

private int _barCount;

private int _lastMonth;

public virtual string AlgoNumber { get; set; }

public virtual int TargetPips { get; set; }

public virtual int MinimumTargetPips { get; set; }

public virtual int StopLossPips { get; set; }

public virtual bool TrailingStopsEnabled { get; set; }

public virtual int TrailingStopTriggerPips { get; set; }

public virtual int TrailingStopDistancePips { get; set; }

public virtual bool TimeStopsEnabled { get; set; }

public virtual bool ClosePendingOrdersUsingTimeStops { get; set; }

public virtual int DayStop { get; set; }

public virtual int HourStop { get; set; }

public virtual int MinuteStop { get; set; }

public virtual int SlippagePips { get; set; }

public virtual int Volume { get; set; }

public virtual int IncrementVolume { get; set; }

public virtual int IncrementVolumeOnBalanceIncrease { get; set; }

public virtual int MaxVolume { get; set; }

public virtual bool CompoundedVolumeEnabled { get; set; }

public virtual bool CompoundedIncrementVolumeEnabled { get; set; }

public virtual bool CompoundedMaxVolumeEnabled { get; set; }

public virtual int MaxLongTrades { get; set; }

public virtual int MaxShortTrades { get; set; }

public virtual int TradeWaitPeriod { get; set; }

public virtual double BalanceStopLossRatio { get; set; }

public virtual double EquityStopLossRatio { get; set; }

public virtual bool TradeMondays { get; set; }

public virtual bool TradeTuesdays { get; set; }

public virtual bool TradeWednesdays { get; set; }

public virtual bool TradeThursdays { get; set; }

public virtual bool TradeFridays { get; set; }

public virtual bool TakeProfitDaily { get; set; }

public virtual bool TakeProfitWeekly { get; set; }

public virtual bool TakeProfitMonthly { get; set; }

public virtual bool RestorePreviousState { get; set; }

public virtual bool SynchronizationEnabled { get; set; }

====================================================================================

It is currently running on 26 currencies in 1 cAlgo instance.

MEMORY FOOTPRINT WHEN STARTED:

 

MEMORY FOOTPRINT AFTER RUNNING 3 DAYS:

As you can see there is cle3arly something very wrong with your memory handling. I know from experience that in WPF it is very easy to cause Memory Leaks if you don't unsubscribe your events from your models etc. Please, please investigate and find the issue - it will be much appreciated!

 

Thanks for an awesome platform!!

 

From another Software Engineer with over 10 years of experience in windows software development.

 


@jobenb

jobenb
11 Jun 2014, 17:13

I don't want to come across as prescribing or anything, but I know cAlgo is done using WPF and from experience if you do not unsubscribe when you have subscribed then references are kept, very easy to happen with following MVVM, so if you += an event you must make sure that you also -= the event. You can easily see if something is destructed by adding a destructor to the objects with a breakpoint in it to try and find the cause or object not being released due to something having a reference to it... Very important. Something that might not be unsubscribed that constantly changing could be the 3 buttons to the right of each row in the Positions grid or maybe the row in the grid itself... Since my robots open constant orders that continues to grow etc. etc. Maybe also all the charts that continue to paint in the background of all the 26 currencies that are open, maybe something there. Maybe it is not releasing the data that come up in the MarketSeries that are stored. 19GB of used memory from 1 application within 3 days are really a lot of bytes.

 

You guys will know best, so I have full confidence that you will find this issue and deal with it. :-)


@jobenb

Spotware
16 Jun 2014, 14:43

Unfortunately we still cannot reproduce this issue. If you send code of your cBot to engage@spotware.com it will simplify our search. We will use your cBots for debugging purposes only.


@Spotware

cjdduarte
16 Jan 2015, 18:33

Your issue resolved? Is going through something like that.


@cjdduarte

davidvandewalle
11 Feb 2016, 20:42

Same for me.


@davidvandewalle

jhtrader
17 Feb 2016, 04:13

code to reproduce issue.

I recently implemented the zigZag indicator (from the website) and when accessing it from cAlgo found that my computer would freeze due to the memory consumed by cAlgo.

NOTE the program runs perfectly fine until I go into the ZigZag indicator so something in this code is causing the issue... please investigate so you can figure it out..

 

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


namespace cAlgo.Indicators
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class ZigZag : Indicator
    {
        [Parameter(DefaultValue = "EURUSD")]
        public string TradePair { get; set; }

        [Parameter(DefaultValue = 12)]
        public int Depth { get; set; }

        [Parameter(DefaultValue = 5)]
        public int Deviation { get; set; }

        [Parameter(DefaultValue = 3)]
        public int BackStep { get; set; }

        [Output("ZigZag", Color = Colors.OrangeRed)]
        public IndicatorDataSeries Result { get; set; }

        #region Private fields

        private double _lastLow;
        private double _lastHigh;
        private double _low;
        private double _high;
        private int _lastHighIndex;
        private int _lastLowIndex;
        private int _type;
        private double _point;
        private double _currentLow;
        private double _currentHigh;

        private IndicatorDataSeries _highZigZags;
        private IndicatorDataSeries _lowZigZags;
        private MarketSeries mSeries;


        #endregion

        protected override void Initialize()
        {


            _highZigZags = CreateDataSeries();
            _lowZigZags = CreateDataSeries();

            _point = Symbol.TickSize;
            mSeries = MarketData.GetSeries(TradePair, TimeFrame.Hour);

        }

        public override void Calculate(int index)
        {

            if (index < Depth)
            {
                Result[index] = 0;
                _highZigZags[index] = 0;
                _lowZigZags[index] = 0;
                return;
            }

            _currentLow = Functions.Minimum(mSeries.Close, Depth);


            if (Math.Abs(_currentLow - _lastLow) < double.Epsilon)
                _currentLow = 0.0;

            else
            {
                _lastLow = _currentLow;

                //Check if Current Close is Greater than the currentLow if True then ignore
                if ((mSeries.Close[index] - _currentLow) > (Deviation * _point))
                    _currentLow = 0.0;

                else
                {
                    for (int i = 1; i <= BackStep; i++)
                    {
                        if (Math.Abs(_lowZigZags[index - i]) > double.Epsilon && _lowZigZags[index - i] > _currentLow)
                            _lowZigZags[index - i] = 0.0;
                    }
                }
            }

            //Check if Current Low = Current Close if true then add to _lowZigZags otherwise put a 0

            if (Math.Abs(mSeries.Close[index] - _currentLow) < double.Epsilon)
                _lowZigZags[index] = _currentLow;
            else

                _lowZigZags[index] = 0.0;


            //TEST
            for (int i = 0; i < index; i++)
            {
                Print("indx Val at {0} = {1}", i, _lowZigZags[i]);
            }


            _currentHigh = mSeries.Close.Maximum(Depth);

            if (Math.Abs(_currentHigh - _lastHigh) < double.Epsilon)
                _currentHigh = 0.0;
            else
            {
                _lastHigh = _currentHigh;

                if ((_currentHigh - mSeries.Close[index]) > (Deviation * _point))
                    _currentHigh = 0.0;
                else
                {
                    for (int i = 1; i <= BackStep; i++)
                    {
                        if (Math.Abs(_highZigZags[index - i]) > double.Epsilon && _highZigZags[index - i] < _currentHigh)
                            _highZigZags[index - i] = 0.0;
                    }
                }
            }

            if (Math.Abs(mSeries.Close[index] - _currentHigh) < double.Epsilon)
                _highZigZags[index] = _currentHigh;
            else
                _highZigZags[index] = 0.0;


            switch (_type)
            {
                case 0:
                    if (Math.Abs(_low - 0) < double.Epsilon && Math.Abs(_high - 0) < double.Epsilon)
                    {
                        if (Math.Abs(_highZigZags[index]) > double.Epsilon)
                        {
                            _high = mSeries.Close[index];
                            _lastHighIndex = index;
                            _type = -1;
                            Result[index] = _high;
                        }
                        if (Math.Abs(_lowZigZags[index]) > double.Epsilon)
                        {
                            _low = mSeries.Close[index];
                            _lastLowIndex = index;
                            _type = 1;
                            Result[index] = _low;
                        }
                    }
                    break;
                case 1:
                    if (Math.Abs(_lowZigZags[index]) > double.Epsilon && _lowZigZags[index] < _low && Math.Abs(_highZigZags[index] - 0.0) < double.Epsilon)
                    {
                        Result[_lastLowIndex] = double.NaN;
                        _lastLowIndex = index;
                        _low = _lowZigZags[index];
                        Result[index] = _low;
                    }
                    if (Math.Abs(_highZigZags[index] - 0.0) > double.Epsilon && Math.Abs(_lowZigZags[index] - 0.0) < double.Epsilon)
                    {
                        _high = _highZigZags[index];
                        _lastHighIndex = index;
                        Result[index] = _high;
                        _type = -1;
                    }
                    break;
                case -1:
                    if (Math.Abs(_highZigZags[index]) > double.Epsilon && _highZigZags[index] > _high && Math.Abs(_lowZigZags[index] - 0.0) < double.Epsilon)
                    {
                        Result[_lastHighIndex] = double.NaN;
                        _lastHighIndex = index;
                        _high = _highZigZags[index];
                        Result[index] = _high;
                    }
                    if (Math.Abs(_lowZigZags[index]) > double.Epsilon && Math.Abs(_highZigZags[index]) <= double.Epsilon)
                    {
                        _low = _lowZigZags[index];
                        _lastLowIndex = index;
                        Result[index] = _low;
                        _type = 1;
                    }
                    break;
                default:
                    return;
            }

        }
    }
}

 

 


Spotware
17 Feb 2016, 14:47

Dear Trader,

From a quick look through your code, we see that you loop from 0 to the index and you print on the log. This code snippet consumes a lot of memory, and CPU usage according to the frequency the Calculate method is called. We kindly ask you to check your code again.

We also would like to inform you that we do not provide coding assistance services. We more than glad to assist you with specific questions about cAlgo.API. You can contact one of our Partners or post a job in Development Jobs section for further coding assistance.


@Spotware

jhtrader
17 Feb 2016, 17:57

RE: memory leak issue SOLVED

jhtrader said:

I had removed that line already and the problem persists!  Please stop reminding me you dont provide assistance! I get it I am trying to figure out why your platform is hanging I am trying to allow you to replicate the issue nothing more ... I have a lot invested in this platform and I want to see it function well.. so please don't be obstinate and obtuse and lets get on with fixing the issue!

I tried to reinstall the software it still consumes memory.. I deleted all instances from the indicators and removed the indiators from the bots.  This fixed the issue!

So the memory usage of the builtin indicators and each instance attached to either a robot or indicator can lead to a significant drain on RAM.  Is this the same for cTrader or is the memory only used when the chart is selected (if possible that would be good if that was the case in cAlgo so that the overall memory is not chewed up by instances or indicators not being used.  

 

 

 

 

 

I recently implemented the zigZag indicator (from the website) and when accessing it from cAlgo found that my computer would freeze due to the memory consumed by cAlgo.

NOTE the program runs perfectly fine until I go into the ZigZag indicator so something in this code is causing the issue... please investigate so you can figure it out..

 

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


namespace cAlgo.Indicators
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class ZigZag : Indicator
    {
        [Parameter(DefaultValue = "EURUSD")]
        public string TradePair { get; set; }

        [Parameter(DefaultValue = 12)]
        public int Depth { get; set; }

        [Parameter(DefaultValue = 5)]
        public int Deviation { get; set; }

        [Parameter(DefaultValue = 3)]
        public int BackStep { get; set; }

        [Output("ZigZag", Color = Colors.OrangeRed)]
        public IndicatorDataSeries Result { get; set; }

        #region Private fields

        private double _lastLow;
        private double _lastHigh;
        private double _low;
        private double _high;
        private int _lastHighIndex;
        private int _lastLowIndex;
        private int _type;
        private double _point;
        private double _currentLow;
        private double _currentHigh;

        private IndicatorDataSeries _highZigZags;
        private IndicatorDataSeries _lowZigZags;
        private MarketSeries mSeries;


        #endregion

        protected override void Initialize()
        {


            _highZigZags = CreateDataSeries();
            _lowZigZags = CreateDataSeries();

            _point = Symbol.TickSize;
            mSeries = MarketData.GetSeries(TradePair, TimeFrame.Hour);

        }

        public override void Calculate(int index)
        {

            if (index < Depth)
            {
                Result[index] = 0;
                _highZigZags[index] = 0;
                _lowZigZags[index] = 0;
                return;
            }

            _currentLow = Functions.Minimum(mSeries.Close, Depth);


            if (Math.Abs(_currentLow - _lastLow) < double.Epsilon)
                _currentLow = 0.0;

            else
            {
                _lastLow = _currentLow;

                //Check if Current Close is Greater than the currentLow if True then ignore
                if ((mSeries.Close[index] - _currentLow) > (Deviation * _point))
                    _currentLow = 0.0;

                else
                {
                    for (int i = 1; i <= BackStep; i++)
                    {
                        if (Math.Abs(_lowZigZags[index - i]) > double.Epsilon && _lowZigZags[index - i] > _currentLow)
                            _lowZigZags[index - i] = 0.0;
                    }
                }
            }

            //Check if Current Low = Current Close if true then add to _lowZigZags otherwise put a 0

            if (Math.Abs(mSeries.Close[index] - _currentLow) < double.Epsilon)
                _lowZigZags[index] = _currentLow;
            else

                _lowZigZags[index] = 0.0;


            //TEST
            for (int i = 0; i < index; i++)
            {
                Print("indx Val at {0} = {1}", i, _lowZigZags[i]);
            }


            _currentHigh = mSeries.Close.Maximum(Depth);

            if (Math.Abs(_currentHigh - _lastHigh) < double.Epsilon)
                _currentHigh = 0.0;
            else
            {
                _lastHigh = _currentHigh;

                if ((_currentHigh - mSeries.Close[index]) > (Deviation * _point))
                    _currentHigh = 0.0;
                else
                {
                    for (int i = 1; i <= BackStep; i++)
                    {
                        if (Math.Abs(_highZigZags[index - i]) > double.Epsilon && _highZigZags[index - i] < _currentHigh)
                            _highZigZags[index - i] = 0.0;
                    }
                }
            }

            if (Math.Abs(mSeries.Close[index] - _currentHigh) < double.Epsilon)
                _highZigZags[index] = _currentHigh;
            else
                _highZigZags[index] = 0.0;


            switch (_type)
            {
                case 0:
                    if (Math.Abs(_low - 0) < double.Epsilon && Math.Abs(_high - 0) < double.Epsilon)
                    {
                        if (Math.Abs(_highZigZags[index]) > double.Epsilon)
                        {
                            _high = mSeries.Close[index];
                            _lastHighIndex = index;
                            _type = -1;
                            Result[index] = _high;
                        }
                        if (Math.Abs(_lowZigZags[index]) > double.Epsilon)
                        {
                            _low = mSeries.Close[index];
                            _lastLowIndex = index;
                            _type = 1;
                            Result[index] = _low;
                        }
                    }
                    break;
                case 1:
                    if (Math.Abs(_lowZigZags[index]) > double.Epsilon && _lowZigZags[index] < _low && Math.Abs(_highZigZags[index] - 0.0) < double.Epsilon)
                    {
                        Result[_lastLowIndex] = double.NaN;
                        _lastLowIndex = index;
                        _low = _lowZigZags[index];
                        Result[index] = _low;
                    }
                    if (Math.Abs(_highZigZags[index] - 0.0) > double.Epsilon && Math.Abs(_lowZigZags[index] - 0.0) < double.Epsilon)
                    {
                        _high = _highZigZags[index];
                        _lastHighIndex = index;
                        Result[index] = _high;
                        _type = -1;
                    }
                    break;
                case -1:
                    if (Math.Abs(_highZigZags[index]) > double.Epsilon && _highZigZags[index] > _high && Math.Abs(_lowZigZags[index] - 0.0) < double.Epsilon)
                    {
                        Result[_lastHighIndex] = double.NaN;
                        _lastHighIndex = index;
                        _high = _highZigZags[index];
                        Result[index] = _high;
                    }
                    if (Math.Abs(_lowZigZags[index]) > double.Epsilon && Math.Abs(_highZigZags[index]) <= double.Epsilon)
                    {
                        _low = _lowZigZags[index];
                        _lastLowIndex = index;
                        Result[index] = _low;
                        _type = 1;
                    }
                    break;
                default:
                    return;
            }

        }
    }
}

 

 

 


Spotware
24 Feb 2016, 14:20

Dear Trader,

As said, we see that you loop from 0 to the index and you print on the log. This code snippet consumes a lot of memory, and CPU usage according to the frequency the Calculate method is called. We kindly ask you to check your code again. 

We kindly ask you to be careful when using loops in the Calculate() Method. This method is called for each historic bar starting from the beginning of the series up to the current bar and then on each incoming tick. 


@Spotware