CTrader Crash/Memory Deficit on this Source Code

Created at 15 Dec 2024, 19:53
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!
AL

algobeginner

Joined 15.12.2024

CTrader Crash/Memory Deficit on this Source Code
15 Dec 2024, 19:53


The CTrader on Mac having difficulties with this code , It first does only one day backtest on 1timeframe 15m, and then after stuck I have pressed stop button and memory consumption was over 200GB. 

Sample of crash - https://www.file.io/FRe2/download/wv5wFzFm5kxO

Code is included below 

// -------------------------------------------------------------------------------------------------
//
//    This code is a cAlgo API sample.
//
//    This cBot is intended to be used as a sample and does not guarantee any particular outcome or
//    profit of any kind. Use it at your own risk
//
//    The "Sample Martingale cBot" creates a random Sell or Buy order. If the Stop loss is hit, a new 
//    order of the same type (Buy / Sell) is created with double the Initial Volume amount. The cBot will 
//    continue to double the volume amount for  all orders created until one of them hits the take Profit. 
//    After a Take Profit is hit, a new random Buy or Sell order is created with the Initial Volume amount.
//
// -------------------------------------------------------------------------------------------------

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

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class HedgingMartingale : Robot
    {
        [Parameter("Initial Quantity (Lots)", DefaultValue = 0.01, MinValue = 0.01, Step = 0.01)]
        public double InitialQuantity { get; set; }

        [Parameter("Restart Initial Quantity (Lots)", DefaultValue = 0.01, MinValue = 0.01, Step = 0.01)]
        public double RestartInitialQuantity { get; set; }

        [Parameter("Take Profit / StopLoss", DefaultValue = 35)]
        public int TakeProfitStopLoss { get; set; }

        [Parameter("Max Loss In Row", DefaultValue = 11)]
        public int MaxLossInRow { get; set; }

        // Timer-based check to ensure positions are only opened during the desired time range
        private const int StartHour = 12; // 12:00 UTC
        private const int EndHour = 15;   // 15:00 UTC

        private Random random = new Random();
        private int LossInRowLong = 0;
        private int LossInRowShort = 0;

        protected override void OnTick()
        {
            // Get the current UTC time
            var currentTime = Server.Time;

            // Check if it's within the allowed time range for opening positions (12:00 to 15:00)
            if (currentTime.Hour >= StartHour && currentTime.Hour < EndHour)

            { Positions.Closed += OnPositionsClosed;

            var position = Positions.Find("HedgingMartingale");

            ExecuteOrder(RestartInitialQuantity, TradeType.Buy);
            ExecuteOrder(RestartInitialQuantity, TradeType.Sell);
            }
        }

        private void ExecuteOrder(double quantity, TradeType tradeType)
        {
            Print("The Spread of the symbol is: {0}", Symbol.Spread);
            var volumeInUnits = Symbol.QuantityToVolume(quantity);
            var result = ExecuteMarketOrder(tradeType, Symbol, volumeInUnits, "HedgingMartingale", TakeProfitStopLoss, TakeProfitStopLoss);

            if (result.Error == ErrorCode.NoMoney)
                Stop();
        }

        private void OnPositionsClosed(PositionClosedEventArgs args)
        {
            Print("Closed");
            var position = args.Position;

            if (position.Label != "HedgingMartingale" || position.SymbolCode != Symbol.Code)
                return;

            if (position.GrossProfit > 0)
            {
                if (position.TradeType == TradeType.Buy)
                {
                    LossInRowLong = 0;
                }

                else if (position.TradeType == TradeType.Sell)
                {
                    LossInRowShort = 0;
                }

                ExecuteOrder(InitialQuantity, position.TradeType);
            }
            else
            {
                if (position.TradeType == TradeType.Buy)
                {
                    LossInRowLong = LossInRowLong + 1;
                }

                else if (position.TradeType == TradeType.Sell)
                {
                    LossInRowShort = LossInRowShort + 1;
                }

                if (LossInRowLong > MaxLossInRow || LossInRowShort > MaxLossInRow)
                {
                    ExecuteOrder(InitialQuantity, position.TradeType);
                }
                else
                {
                    ExecuteOrder(position.Quantity * 2, position.TradeType);
                }
            }
        }

        private TradeType GetRandomTradeType()
        {
            return random.Next(2) == 0 ? TradeType.Buy : TradeType.Sell;
        }
    }
}

@algobeginner
Replies

algobeginner
16 Dec 2024, 12:04

This seem to do the trick , no memory crash and does tested multiple days
using System;
using cAlgo.API;

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class HedgingMartingale : Robot
    {
        [Parameter("Initial Quantity (Lots)", DefaultValue = 0.01, MinValue = 0.01, Step = 0.01)]
        public double InitialQuantity { get; set; }

        [Parameter("Restart Initial Quantity (Lots)", DefaultValue = 0.01, MinValue = 0.01, Step = 0.01)]
        public double RestartInitialQuantity { get; set; }

        [Parameter("Take Profit / StopLoss", DefaultValue = 35)]
        public int TakeProfitStopLoss { get; set; }

        [Parameter("Max Loss In Row", DefaultValue = 11)]
        public int MaxLossInRow { get; set; }

        private const int StartHour = 12; // 12:00 UTC
        private const int EndHour = 15;   // 15:00 UTC

        private Random random = new Random();
        private int LossInRowLong = 0;
        private int LossInRowShort = 0;

        protected override void OnStart()
        {
            Positions.Closed += OnPositionsClosed;
        }

        protected override void OnTick()
        {
            var currentTime = Server.Time;

            if (currentTime.Hour >= StartHour && currentTime.Hour < EndHour)
            {
                var position = Positions.Find("HedgingMartingale");
                if (position == null)
                {
                    ExecuteOrder(RestartInitialQuantity, GetRandomTradeType());
                }
            }
        }

        private void ExecuteOrder(double quantity, TradeType tradeType)
        {
            Print("The Spread of the symbol is: {0}", Symbol.Spread);
            var volumeInUnits = Symbol.QuantityToVolumeInUnits(quantity);
            var result = ExecuteMarketOrder(tradeType, Symbol.Name, volumeInUnits, "HedgingMartingale", TakeProfitStopLoss, TakeProfitStopLoss);

            if (result.Error == ErrorCode.NoMoney)
            {
                Print("Not enough money to execute order.");
                Stop();
            }
        }

        private void OnPositionsClosed(PositionClosedEventArgs args)
        {
            var position = args.Position;

            if (position.Label != "HedgingMartingale" || position.SymbolName != Symbol.Name)
                return;

            if (position.GrossProfit > 0)
            {
                if (position.TradeType == TradeType.Buy)
                {
                    LossInRowLong = 0;
                }
                else if (position.TradeType == TradeType.Sell)
                {
                    LossInRowShort = 0;
                }

                ExecuteOrder(InitialQuantity, position.TradeType);
            }
            else
            {
                if (position.TradeType == TradeType.Buy)
                {
                    LossInRowLong++;
                }
                else if (position.TradeType == TradeType.Sell)
                {
                    LossInRowShort++;
                }

                if (LossInRowLong > MaxLossInRow || LossInRowShort > MaxLossInRow)
                {
                    Print("Max loss in a row reached. Resetting.");
                    LossInRowLong = 0;
                    LossInRowShort = 0;
                }
                else
                {
                    ExecuteOrder(position.Quantity * 2, position.TradeType);
                }
            }
        }

        private TradeType GetRandomTradeType()
        {
            return random.Next(2) == 0 ? TradeType.Buy : TradeType.Sell;
        }

        protected override void OnStop()
        {
            Positions.Closed -= OnPositionsClosed; // Unsubscribe from the event
        }
    }
}

@algobeginner