StopLoss Calculations/ Terminal freeze volatile market conditions/System Interrupts

Created at 12 Feb 2022, 09:46
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!
M4

m4trader4

Joined 19.09.2021

StopLoss Calculations/ Terminal freeze volatile market conditions/System Interrupts
12 Feb 2022, 09:46


Hi

I run CBot in vps with 6 threads/16 GB RAM which has ample resources, normally the cpu utilization is about 30-40% and ram utilization is 30%. This CBot runs on 20-30 symbols on Range Bars, whenever there is high volatility CTrader freezes and in task manager "SystemInterrupts" cpu utilization goes up 80-90%.

When there is high volatility/Event CBot of different symbol opens trade. Cumulatively ~ 10 -20 positions with stoploss are present and at every bar based on logic new positions(orders) are opened or StopLoss is moved or Positions are scaled (new orders)

In the CBot logs errors 

Failed to get symbol 'XAUUSD': symbol has no quotes.
Crashed in BarOpened with NullReferenceException: Object reference not set to an instance of an object.

The symbols are random and CBot stops.

In the attached code, I could point out to StopLoss calculation function.

If there is no high volatality/Event CBot works without any issue.

Please let me know what might be causing the issue. 

Appreciate your insights

Regards

Ahmed

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class ForumCTraderSL : Robot
    {
        [Parameter(DefaultValue = 0.0)]
        public double Parameter { get; set; }

        double GlobalTotalSl;

        public double CheckSLPositions()
        {

            //Print(Symbol.Name + "CheckSlPositions Executed");
            var positionsCBS = Positions.FindAll("");
            double TotalSl = 0;

            //var positionsCBS = Positions.FindAll("");
            if (positionsCBS.Length != 0)
            {
                foreach (var psnCBS in positionsCBS)
                {
                    // psnCBS.StopLoss doesnt return 0 if there is no StopLoss for open position, so have to convert to string

                    if (psnCBS.StopLoss.ToString() != "")
                    {

                        var GetSymbolName = psnCBS.SymbolName;
                        var GetSymbolNameLotSize = Symbols.GetSymbol(GetSymbolName).LotSize;
                        var GetSymbolPipValueSize = Symbols.GetSymbol(GetSymbolName).PipValue / Symbols.GetSymbol(GetSymbolName).PipSize;
                        var GetSymbolNameQty = psnCBS.Quantity;

                        switch (psnCBS.TradeType)
                        {

                            case TradeType.Buy:
                                var Bpips = (double)(psnCBS.StopLoss - psnCBS.EntryPrice);
                                TotalSl = Bpips * GetSymbolNameLotSize * GetSymbolPipValueSize * GetSymbolNameQty;
                                break;

                            case TradeType.Sell:
                                var Spips = (double)(psnCBS.EntryPrice - psnCBS.StopLoss);
                                TotalSl = Spips * GetSymbolNameLotSize * GetSymbolPipValueSize * GetSymbolNameQty;
                                break;


                        }


                    }


                }
                Print("CheckSlPositions TotalStopLossPips:  " + TotalSl.ToString("F6"));

            }

            return TotalSl;
        }

        private void Bars_BarOpened_CheckSLPositions(BarOpenedEventArgs obj)
        {
            GlobalTotalSl = 0;

            GlobalTotalSl = CheckSLPositions();


        }


        private void Bars_BarOpened_StopLossMove(BarOpenedEventArgs obj)
        {
           
            //Logic to move stop loss
        }

        private void Bars_BarOpened_AutoOrder(BarOpenedEventArgs obj)
        {

            //Logic place order there are some calculations used 
            //When the condition GlobalTotalSl is executed, due to computations of above statements,  sync of GlobalTotalSl should happen
            //Condition Check GlobalTotalSl should be within limit
        }

        private void Bars_BarOpened_AutoScale(BarOpenedEventArgs obj)
        {

            //Logic scale up orders
        }



        protected override void OnStart()
        {
            GlobalTotalSl = 0;


            Bars.BarOpened += Bars_BarOpened_CheckSLPositions;
            Bars.BarOpened += Bars_BarOpened_StopLossMove;
            Bars.BarOpened += Bars_BarOpened_AutoOrder;
            Bars.BarOpened += Bars_BarOpened_AutoScale;

            // Put your initialization logic here
        }

        protected override void OnTick()
        {
            // Put your core logic here
        }

        protected override void OnStop()
        {
            // Put your deinitialization logic here
        }
    }
}

 

 


@m4trader4
Replies

cAIgoBuddy
12 Feb 2022, 10:52

RE:

m4trader4 said:

Hi

I run CBot in vps with 6 threads/16 GB RAM which has ample resources, normally the cpu utilization is about 30-40% and ram utilization is 30%. This CBot runs on 20-30 symbols on Range Bars, whenever there is high volatility CTrader freezes and in task manager "SystemInterrupts" cpu utilization goes up 80-90%.

When there is high volatility/Event CBot of different symbol opens trade. Cumulatively ~ 10 -20 positions with stoploss are present and at every bar based on logic new positions(orders) are opened or StopLoss is moved or Positions are scaled (new orders)

In the CBot logs errors 

Failed to get symbol 'XAUUSD': symbol has no quotes.
Crashed in BarOpened with NullReferenceException: Object reference not set to an instance of an object.

The symbols are random and CBot stops.

In the attached code, I could point out to StopLoss calculation function.

If there is no high volatality/Event CBot works without any issue.

Please let me know what might be causing the issue. 

Appreciate your insights

Regards

Ahmed

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class ForumCTraderSL : Robot
    {
        [Parameter(DefaultValue = 0.0)]
        public double Parameter { get; set; }

        double GlobalTotalSl;

        public double CheckSLPositions()
        {

            //Print(Symbol.Name + "CheckSlPositions Executed");
            var positionsCBS = Positions.FindAll("");
            double TotalSl = 0;

            //var positionsCBS = Positions.FindAll("");
            if (positionsCBS.Length != 0)
            {
                foreach (var psnCBS in positionsCBS)
                {
                    // psnCBS.StopLoss doesnt return 0 if there is no StopLoss for open position, so have to convert to string

                    if (psnCBS.StopLoss.ToString() != "")
                    {

                        var GetSymbolName = psnCBS.SymbolName;
                        var GetSymbolNameLotSize = Symbols.GetSymbol(GetSymbolName).LotSize;
                        var GetSymbolPipValueSize = Symbols.GetSymbol(GetSymbolName).PipValue / Symbols.GetSymbol(GetSymbolName).PipSize;
                        var GetSymbolNameQty = psnCBS.Quantity;

                        switch (psnCBS.TradeType)
                        {

                            case TradeType.Buy:
                                var Bpips = (double)(psnCBS.StopLoss - psnCBS.EntryPrice);
                                TotalSl = Bpips * GetSymbolNameLotSize * GetSymbolPipValueSize * GetSymbolNameQty;
                                break;

                            case TradeType.Sell:
                                var Spips = (double)(psnCBS.EntryPrice - psnCBS.StopLoss);
                                TotalSl = Spips * GetSymbolNameLotSize * GetSymbolPipValueSize * GetSymbolNameQty;
                                break;


                        }


                    }


                }
                Print("CheckSlPositions TotalStopLossPips:  " + TotalSl.ToString("F6"));

            }

            return TotalSl;
        }

        private void Bars_BarOpened_CheckSLPositions(BarOpenedEventArgs obj)
        {
            GlobalTotalSl = 0;

            GlobalTotalSl = CheckSLPositions();


        }


        private void Bars_BarOpened_StopLossMove(BarOpenedEventArgs obj)
        {
           
            //Logic to move stop loss
        }

        private void Bars_BarOpened_AutoOrder(BarOpenedEventArgs obj)
        {

            //Logic place order there are some calculations used 
            //When the condition GlobalTotalSl is executed, due to computations of above statements,  sync of GlobalTotalSl should happen
            //Condition Check GlobalTotalSl should be within limit
        }

        private void Bars_BarOpened_AutoScale(BarOpenedEventArgs obj)
        {

            //Logic scale up orders
        }



        protected override void OnStart()
        {
            GlobalTotalSl = 0;


            Bars.BarOpened += Bars_BarOpened_CheckSLPositions;
            Bars.BarOpened += Bars_BarOpened_StopLossMove;
            Bars.BarOpened += Bars_BarOpened_AutoOrder;
            Bars.BarOpened += Bars_BarOpened_AutoScale;

            // Put your initialization logic here
        }

        protected override void OnTick()
        {
            // Put your core logic here
        }

        protected override void OnStop()
        {
            // Put your deinitialization logic here
        }
    }
}

 

 

Hello,

For starters, change

psnCBS.StopLoss.ToString() != ""

to 

psnCBS.StopLoss.HasValue

Since StopLoss is a nullable double, it can crash when invoking ToString() when it's null.

 


@cAIgoBuddy

firemyst
13 Feb 2022, 05:48

positionsCBS can be null, which is one reason you might be getting the null reference exception.

After all, when you start the bot, there might not be any positions open.

So you need to check if you have any positions:

if (positionsCBS != null && positionsCBS.Length != 0)

 

And if you want to check if a position has a stoploss or not, you need to use p.GetValueOrDefault()

That will return zero if there's no stop loss associated with the position.

So don't do this:

if (psnCBS.StopLoss.ToString() != "")

 

Do this instead:

if (psnCBS.StopLoss.GetValueOrDefault() != 0)

@firemyst

m4trader4
13 Feb 2022, 18:52

RE:

This is the second time i am writing as the first one after posting dint appear

Hi Firemyst

Thanks for pointers, will amend the code.

The issue i think is when there is high volatility CheckSLPositions() is unable to lock the postions list. The CBot running on other symbols is doing the same opening new trades/moving stoploss/checking Stoploss.

Its about the thread safe

Regards

Ahmed


@m4trader4

firemyst
14 Feb 2022, 04:47

RE: RE:

m4trader4 said:

This is the second time i am writing as the first one after posting dint appear

Hi Firemyst

Thanks for pointers, will amend the code.

The issue i think is when there is high volatility CheckSLPositions() is unable to lock the postions list. The CBot running on other symbols is doing the same opening new trades/moving stoploss/checking Stoploss.

Its about the thread safe

Regards

Ahmed

Why would you need to lock the Positions object? All you're doing is reading it; you can't set any values in it. So it's not your problem. :-)

I don't understand why you would want, or have, a cbot running under multiple symbols that would adjust the stoploss for _ALL_ open positions and not just the one the bot is running under?

To resolve the "thread safety", just have this cbot running once under 1 symbol and that's it since it updates every position that's open.

So change this statement to only find the symbol's the bot is running under:

Positions.FindAll("") //change this

change the above to something like:

Positions.Find("", Symbol.Name); //return only the positions under the current symbol the bot instance is running under

 

If you insist or really need multiple instances of this bot to be running and updating all positions across all symbols, then one approach is to create a global lock object and lock that bit of code. KEep in mind the performance implications - like it'll slow down your other bots as they wait to obtain a lock. This isn't the most elegant or possibly best way, but here goes:

public static object myGlobalLockObject = new object();

:

:

lock (myGlobalLockObject)

{

   if (positionsCBS != null and positionsCBS.Length > 0)

   {

      foreach ( ... )

      {

      }

   }

}


@firemyst

m4trader4
14 Feb 2022, 11:19

RE: RE: RE:

cAIgoBuddy, Yesterday i could not find your reply, have ammended code according to Firemyst suggestions, i had to repost my reply second time

@Firemyst, Bars.BarOpened += Bars_BarOpened_StopLossMove; does excatly the same as you said moves the stoploss according to symbol as the parameters are different for each symbol

Positions.Find("", Symbol.Name); //return only the positions under the current symbol the bot instance is running under

Only issue is checking the public double CheckSLPositions() of all the positions before placing new orders, when there is high volatility/Event, as bars print very fast.

As you said lock does not seems to be a good solution, not for it

 

 

 

 

 

 

 


@m4trader4

m4trader4
14 Feb 2022, 11:29

RE: RE: RE: RE:

@Firemyst

if (psnCBS.StopLoss.GetValueOrDefault() != 0) doesnt work, CBot crashes

@ cAlgoBuddy

psnCBS.StopLoss.HasValue is working CBot is not crashing. 

 

Have to check when there is high volatility/Event

 

 

 

 

 


@m4trader4

firemyst
14 Feb 2022, 12:35

RE: RE: RE: RE: RE:

m4trader4 said:

@Firemyst

if (psnCBS.StopLoss.GetValueOrDefault() != 0) doesnt work, CBot crashes

@ cAlgoBuddy

psnCBS.StopLoss.HasValue is working CBot is not crashing. 

 

Have to check when there is high volatility/Event

 

 

 

 

 

Define "doesn't work".

The only way it won't work is if psnCBS is null.

What's the error message thrown when the bot crashes?

 

 


@firemyst

m4trader4
14 Feb 2022, 13:02

RE: RE: RE: RE: RE:

m4trader4 said:

@Firemyst

if (psnCBS.StopLoss.GetValueOrDefault() != 0) doesnt work, CBot crashes

@ cAlgoBuddy

psnCBS.StopLoss.HasValue is working CBot is not crashing. 

 

Have to check when there is high volatility/Event

 

 

 

 

 

cBot crashed: Error #90580554

cBot crashed: Error #65147970


@m4trader4

firemyst
14 Feb 2022, 14:41

RE: RE: RE: RE: RE: RE:

m4trader4 said:

 

cBot crashed: Error #90580554

cBot crashed: Error #65147970

If you check this thread:

according to @amusleh, this happens with high volatility. So again this probably comes back to your code trying to move/check a stop loss when the position could have been closed elsewhere.

This could happen either with ".HasValue" or ".Stoploss.GetValueOrDefault()".

It also says you need a flag in your code to see if the closing event has been fired. If it has, you can't go through, check positions, and modify stop losses because one of the positions in your foreach loop could have been closed between the time you check the length of the positions and go through the foreach loop.

 

 


@firemyst