cAlgo default methods: An execution sequence issue ? - Control variabes uneffective

Created at 14 Apr 2022, 22:11
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!
NC

ncel01

Joined 19.03.2020

cAlgo default methods: An execution sequence issue ? - Control variabes uneffective
14 Apr 2022, 22:11


Hello, 

I found that, unlike user-defined methods, cAlgo methods don't seem to follow a logical sequence, where every code line is fully executed prior to the execution of the next line.

The code below illustrates this. It returns the following output while, in fact, I was expecting a sequential ascending order here.

Behaving like this, it is really hard/impossible to predict a cBot behavior, whenever any control variables are required to be defined/modified inside and/or after calling a method.

Am I missing something here?

How to make this effective? Is there any solution for this?

Thank you!

 

using cAlgo.API;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewcBot : Robot
    {

        protected override void OnStart()
        {

            Positions.Closed += Positions_Closed;

            //Print("Stage #1");
            SetTrade();

            Print("Stage #2");

            foreach (var position in Positions)
            {
                //Print("Stage #3");
                ClosePosition(position);
            }

            //Print("Stage #4");
            Stop();

            Print("Stage #5");
        }

        private void SetTrade()
        {
            Print("Stage #1");
            ExecuteMarketOrder(TradeType.Buy, SymbolName, 1000);
        }

        private void Positions_Closed(PositionClosedEventArgs obj)
        {
            Print("Stage #3");
        }

        protected override void OnStop()
        {
            Print("Stage #4");
        }

    }
}

 


@ncel01
Replies

amusleh
15 Apr 2022, 08:57

Hi,

cTrader cBots/Indicators run on a single thread and their code indeed are executed sequentially.

Regarding your code, this is the result I got:

15/04/2022 13:10:42.947 | CBot instance [New cBot, EURUSD, h1] started.
15/04/2022 13:10:43.650 | Stage #1
15/04/2022 13:10:44.134 | Stage #2
15/04/2022 13:10:44.556 | Stage #5
15/04/2022 13:10:44.556 | Stage #4
15/04/2022 13:10:44.588 | CBot instance [New cBot, EURUSD, h1] stopped.

The Stage #1 gets printed because it's the first line to be executed inside SetTrade method, all good for now.

The Stage #2 is printed as it's the next line after Stack execution pointer returns from SetMethod.

Next is the loop for closing positions, it iterates over Positions collection and then sends a Close request for each of the positions, then why "Stage #3" is not printed?

Because either the Positions collection is not updated yet (in my case), it gets updated after the thread is released from the execution of an event (OnStart. OnBar, OnTick, etc...) or even if it's updated (based on your output) the close position request can't suspend the current execution and jump to executing the event handlers (here Positions_Closed).

It waits for thread to become free and then it executes the event handler of Positions.Closed event, that's what happened on your case.

Same thing is happening for Stop call, when you call the Stop method it can't suspend the execution of OnStart method and jump to execution of OnStop, instead it first finish the OnStart method and then it executes the OnStop and Positions closed event handler.

As I said each cBot/Indicator runs on a single thread, the thread can only execute one event per time, if you are inside OnTick it can't execute OnBar code or if you are inside OnStart it can't execute the code inside OnStop even if you call it from OnStart, it first finish the current event call and then the next one.

cTrader Automate uses event loop, and it calls each event sequentially when they arrive, only a single event is executed at a time.


@amusleh

ncel01
15 Apr 2022, 14:39 ( Updated at: 21 Dec 2023, 09:22 )

RE:

amusleh said:

Hi,

cTrader cBots/Indicators run on a single thread and their code indeed are executed sequentially.

Regarding your code, this is the result I got:

15/04/2022 13:10:42.947 | CBot instance [New cBot, EURUSD, h1] started.
15/04/2022 13:10:43.650 | Stage #1
15/04/2022 13:10:44.134 | Stage #2
15/04/2022 13:10:44.556 | Stage #5
15/04/2022 13:10:44.556 | Stage #4
15/04/2022 13:10:44.588 | CBot instance [New cBot, EURUSD, h1] stopped.

The Stage #1 gets printed because it's the first line to be executed inside SetTrade method, all good for now.

The Stage #2 is printed as it's the next line after Stack execution pointer returns from SetMethod.

Next is the loop for closing positions, it iterates over Positions collection and then sends a Close request for each of the positions, then why "Stage #3" is not printed?

Because either the Positions collection is not updated yet (in my case), it gets updated after the thread is released from the execution of an event (OnStart. OnBar, OnTick, etc...) or even if it's updated (based on your output) the close position request can't suspend the current execution and jump to executing the event handlers (here Positions_Closed).

It waits for thread to become free and then it executes the event handler of Positions.Closed event, that's what happened on your case.

Same thing is happening for Stop call, when you call the Stop method it can't suspend the execution of OnStart method and jump to execution of OnStop, instead it first finish the OnStart method and then it executes the OnStop and Positions closed event handler.

As I said each cBot/Indicator runs on a single thread, the thread can only execute one event per time, if you are inside OnTick it can't execute OnBar code or if you are inside OnStart it can't execute the code inside OnStop even if you call it from OnStart, it first finish the current event call and then the next one.

cTrader Automate uses event loop, and it calls each event sequentially when they arrive, only a single event is executed at a time.

Hello amusleh,

Thank you for your reply!

I think that's clear, however, I believe it makes things much more difficult when it comes to controlling execution.

Example:

In the code below, I want to confirm if all the orders have been closed, by using the control variable allPositionsClosed, however, this will never work since allPositionsClosed = true will always proceed Positions_Closed event execution, as you have already explained.

My question is, what can be done so that it is indeed possible to make use of control variables effectively in such cases?

Defining allPositionsClosed = true inside Positions_Closed event could be, maybe, an alternative, however, this will happen once the first position is closed and not the last one. And, in my case, I only want to pass a new value to the control variable after the last event is executed.
Should I create an array, where each index is assigned a value based on the respective closed position, and then assign a value to the main variable based on this data?
I think this can be a solution, however, maybe there is a better/easier way to get this done and I would really like to be aware of it.

Thank you once again!

 

using cAlgo.API;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewcBot : Robot
    {

        private bool allPositionsClosed = false;

        protected override void OnStart()
        {

            Positions.Closed += Positions_Closed;

            SetTrade();

            Print("All positions closed: ", allPositionsClosed);

            foreach (var position in Positions)
            {
                ClosePosition(position);
                position.Close();
            }

            allPositionsClosed = true;
            Print("All positions closed: ", allPositionsClosed);

            Stop();
        }

        private void SetTrade()
        {
            ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(0.01), "order_1");
            ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(0.01), "order_2");
            ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(0.01), "order_3");
        }

        private void Positions_Closed(PositionClosedEventArgs obj)
        {
            Print("{0} has been closed", obj.Position.Label);
        }

        protected override void OnStop()
        {
        }

    }
}

 


@ncel01

amusleh
18 Apr 2022, 10:39

Hi,

Try this:

using cAlgo.API;
using System.Linq;
using System.Threading;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewcBot : Robot
    {
        private bool allPositionsClosed = false;

        protected override void OnStart()
        {
            var tradeResults = SetTrade();

            Print("Closing Positions");

            foreach (var tradeResult in tradeResults)
            {
                ClosePosition(tradeResult.Position);
            }

            allPositionsClosed = true;

            Print("All positions closed: ", allPositionsClosed);

            Stop();
        }

        private TradeResult[] SetTrade()
        {
            var tradeResults = new TradeResult[3];

            tradeResults[0] = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(0.01), "order_1");
            tradeResults[1] = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(0.01), "order_2");
            tradeResults[2] = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(0.01), "order_3");

            while (tradeResults.Any(result => result.Position is null))
            {
                Thread.Sleep(100);

                RefreshData();
            }

            return tradeResults;
        }

        protected override void OnStop()
        {
        }
    }
}

 


@amusleh

ncel01
19 Apr 2022, 00:02

RE:

amusleh said:

Hi,

Try this:

using cAlgo.API;
using System.Linq;
using System.Threading;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewcBot : Robot
    {
        private bool allPositionsClosed = false;

        protected override void OnStart()
        {
            var tradeResults = SetTrade();

            Print("Closing Positions");

            foreach (var tradeResult in tradeResults)
            {
                ClosePosition(tradeResult.Position);
            }

            allPositionsClosed = true;

            Print("All positions closed: ", allPositionsClosed);

            Stop();
        }

        private TradeResult[] SetTrade()
        {
            var tradeResults = new TradeResult[3];

            tradeResults[0] = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(0.01), "order_1");
            tradeResults[1] = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(0.01), "order_2");
            tradeResults[2] = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(0.01), "order_3");

            while (tradeResults.Any(result => result.Position is null))
            {
                Thread.Sleep(100);

                RefreshData();
            }

            return tradeResults;
        }

        protected override void OnStop()
        {
        }
    }
}

 

Hi amusleh,

I am afraid that creating time delays will not solve the issue as there are dozens/hundreds of orders involved and this wouldn't be an efficient/effective solution at all, I believe.

Because either the Positions collection is not updated yet (in my case), it gets updated after the thread is released from the execution of an event (OnStart. OnBar, OnTick, etc...) or even if it's updated (based on your output) the close position request can't suspend the current execution and jump to executing the event handlers (here Positions_Closed).

What can be a reason for such limitation? Wouldn't be possible that these follow the code sequence, as it happens for user-defined methods?

I am sure this would be much more intuitive and, as result, the outcome a lot more effective. Looks to me that managing a high amount of orders/positions seems to be quite hard (if not impossible) considering that internal (API) methods/functions execute asynchronously with respect to the code sequence.

Is there available any diagram (or similar) illustrating how execution is processed through cTrader API functions/methods? I believe this particularity is not really a detail when it comes to creating any "reliable" (behaving as expected) cBot/strategy. Maybe I can get to a solution if I am fully aware of how this really works. So far, it looks like I've been on a loop trying to get this solved.

Does this characteristic/limitation only apply to the events or, to any method? Only to methods?

Another question:  PendingOrders_Created() and PlaceStopOrderAsync(). Do these methods always get triggered simultaneously (as a pair) or, can be that some code is still executed in between?

On my last attempt, I've added PendingOrders_Created() event. The goal was only to modify the value of a variable inside the event. However, soon I noticed that, unlike for a single order, the amount of orders keeps increasing whenever the "real" order is placed. A "clone" order is created, which does not happen if only a single order is initially defined. I also don't know why this is happening nor I do know how to solve this.

My strategy has 2000+ code lines and it is almost finished (I would say). So far, I've been able to solve every issue I noticed but not this one. The only issue, still remaining, is in fact, related to the loop ( pending order placed --> pending order filled --> position closed --> pending order placed ... ), which is still not working as expected, after many tries.

Thank you once again!


@ncel01

amusleh
19 Apr 2022, 09:48

RE: RE:

ncel01 said:

amusleh said:

Hi,

Try this:

using cAlgo.API;
using System.Linq;
using System.Threading;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewcBot : Robot
    {
        private bool allPositionsClosed = false;

        protected override void OnStart()
        {
            var tradeResults = SetTrade();

            Print("Closing Positions");

            foreach (var tradeResult in tradeResults)
            {
                ClosePosition(tradeResult.Position);
            }

            allPositionsClosed = true;

            Print("All positions closed: ", allPositionsClosed);

            Stop();
        }

        private TradeResult[] SetTrade()
        {
            var tradeResults = new TradeResult[3];

            tradeResults[0] = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(0.01), "order_1");
            tradeResults[1] = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(0.01), "order_2");
            tradeResults[2] = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(0.01), "order_3");

            while (tradeResults.Any(result => result.Position is null))
            {
                Thread.Sleep(100);

                RefreshData();
            }

            return tradeResults;
        }

        protected override void OnStop()
        {
        }
    }
}

 

Hi amusleh,

I am afraid that creating time delays will not solve the issue as there are dozens/hundreds of orders involved and this wouldn't be an efficient/effective solution at all, I believe.

Because either the Positions collection is not updated yet (in my case), it gets updated after the thread is released from the execution of an event (OnStart. OnBar, OnTick, etc...) or even if it's updated (based on your output) the close position request can't suspend the current execution and jump to executing the event handlers (here Positions_Closed).

What can be a reason for such limitation? Wouldn't be possible that these follow the code sequence, as it happens for user-defined methods?

I am sure this would be much more intuitive and, as result, the outcome a lot more effective. Looks to me that managing a high amount of orders/positions seems to be quite hard (if not impossible) considering that internal (API) methods/functions execute asynchronously with respect to the code sequence.

Is there available any diagram (or similar) illustrating how execution is processed through cTrader API functions/methods? I believe this particularity is not really a detail when it comes to creating any "reliable" (behaving as expected) cBot/strategy. Maybe I can get to a solution if I am fully aware of how this really works. So far, it looks like I've been on a loop trying to get this solved.

Does this characteristic/limitation only apply to the events or, to any method? Only to methods?

Another question:  PendingOrders_Created() and PlaceStopOrderAsync(). Do these methods always get triggered simultaneously (as a pair) or, can be that some code is still executed in between?

On my last attempt, I've added PendingOrders_Created() event. The goal was only to modify the value of a variable inside the event. However, soon I noticed that, unlike for a single order, the amount of orders keeps increasing whenever the "real" order is placed. A "clone" order is created, which does not happen if only a single order is initially defined. I also don't know why this is happening nor I do know how to solve this.

My strategy has 2000+ code lines and it is almost finished (I would say). So far, I've been able to solve every issue I noticed but not this one. The only issue, still remaining, is in fact, related to the loop ( pending order placed --> pending order filled --> position closed --> pending order placed ... ), which is still not working as expected, after many tries.

Thank you once again!

Hi,

There is no way to prevent waiting, Automate API is an abstraction over sending and receiving messages to cTrader server, if you have done any kind of network programming you know that when you send something to server/client you have to wait to get back a response, when you send a request from Automate API you have to wait to get back the response from server, there we use the Thread.Sleep method to wait until we receive response for all of our order requests from server.

Regarding your other points, all operations on a cBot is executed by a single thread, and a single thread can execute a single line of code at the time.

If you understand how a single thread environment works you will be able to understand how cTrader automate executes your code.

cTrader automate executes your cBot overloaded methods and event handlers one by one, if the thread is inside OnTick method and a position is closed it can't suspend OnTick method execution and jump to your Position closed event handler, first it finish the execution of OnTick method then it executes your position closed event handler, the same is true for all other methods, event handlers, and collections (Positions and PendingOrders).

When you send something to server you have to wait to get back the response, you can't expect the response to be available instantly, if you sent a market order request you can't expect Positions collections to have your market order position immediately.

A better approach for you to control the sequence of execution will be used the Async calls with callbacks, the async method callbacks will be called when a response is received from server, and while waiting for server response you can execute some other code instead of suspending the thread and waiting for a server response.


@amusleh

ncel01
19 Apr 2022, 14:42

RE: RE: RE:

amusleh said:

ncel01 said:

amusleh said:

Hi,

Try this:

using cAlgo.API;
using System.Linq;
using System.Threading;

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class NewcBot : Robot
    {
        private bool allPositionsClosed = false;

        protected override void OnStart()
        {
            var tradeResults = SetTrade();

            Print("Closing Positions");

            foreach (var tradeResult in tradeResults)
            {
                ClosePosition(tradeResult.Position);
            }

            allPositionsClosed = true;

            Print("All positions closed: ", allPositionsClosed);

            Stop();
        }

        private TradeResult[] SetTrade()
        {
            var tradeResults = new TradeResult[3];

            tradeResults[0] = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(0.01), "order_1");
            tradeResults[1] = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(0.01), "order_2");
            tradeResults[2] = ExecuteMarketOrder(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(0.01), "order_3");

            while (tradeResults.Any(result => result.Position is null))
            {
                Thread.Sleep(100);

                RefreshData();
            }

            return tradeResults;
        }

        protected override void OnStop()
        {
        }
    }
}

 

Hi amusleh,

I am afraid that creating time delays will not solve the issue as there are dozens/hundreds of orders involved and this wouldn't be an efficient/effective solution at all, I believe.

Because either the Positions collection is not updated yet (in my case), it gets updated after the thread is released from the execution of an event (OnStart. OnBar, OnTick, etc...) or even if it's updated (based on your output) the close position request can't suspend the current execution and jump to executing the event handlers (here Positions_Closed).

What can be a reason for such limitation? Wouldn't be possible that these follow the code sequence, as it happens for user-defined methods?

I am sure this would be much more intuitive and, as result, the outcome a lot more effective. Looks to me that managing a high amount of orders/positions seems to be quite hard (if not impossible) considering that internal (API) methods/functions execute asynchronously with respect to the code sequence.

Is there available any diagram (or similar) illustrating how execution is processed through cTrader API functions/methods? I believe this particularity is not really a detail when it comes to creating any "reliable" (behaving as expected) cBot/strategy. Maybe I can get to a solution if I am fully aware of how this really works. So far, it looks like I've been on a loop trying to get this solved.

Does this characteristic/limitation only apply to the events or, to any method? Only to methods?

Another question:  PendingOrders_Created() and PlaceStopOrderAsync(). Do these methods always get triggered simultaneously (as a pair) or, can be that some code is still executed in between?

On my last attempt, I've added PendingOrders_Created() event. The goal was only to modify the value of a variable inside the event. However, soon I noticed that, unlike for a single order, the amount of orders keeps increasing whenever the "real" order is placed. A "clone" order is created, which does not happen if only a single order is initially defined. I also don't know why this is happening nor I do know how to solve this.

My strategy has 2000+ code lines and it is almost finished (I would say). So far, I've been able to solve every issue I noticed but not this one. The only issue, still remaining, is in fact, related to the loop ( pending order placed --> pending order filled --> position closed --> pending order placed ... ), which is still not working as expected, after many tries.

Thank you once again!

Hi,

There is no way to prevent waiting, Automate API is an abstraction over sending and receiving messages to cTrader server, if you have done any kind of network programming you know that when you send something to server/client you have to wait to get back a response, when you send a request from Automate API you have to wait to get back the response from server, there we use the Thread.Sleep method to wait until we receive response for all of our order requests from server.

Regarding your other points, all operations on a cBot is executed by a single thread, and a single thread can execute a single line of code at the time.

If you understand how a single thread environment works you will be able to understand how cTrader automate executes your code.

cTrader automate executes your cBot overloaded methods and event handlers one by one, if the thread is inside OnTick method and a position is closed it can't suspend OnTick method execution and jump to your Position closed event handler, first it finish the execution of OnTick method then it executes your position closed event handler, the same is true for all other methods, event handlers, and collections (Positions and PendingOrders).

When you send something to server you have to wait to get back the response, you can't expect the response to be available instantly, if you sent a market order request you can't expect Positions collections to have your market order position immediately.

A better approach for you to control the sequence of execution will be used the Async calls with callbacks, the async method callbacks will be called when a response is received from server, and while waiting for server response you can execute some other code instead of suspending the thread and waiting for a server response.

Hi amusleh,

Yes, I am aware that there's always a time delay when waiting for a response from the server, that's why I provided an example of synchronous execution ClosePosition(), which in fact I thought, would suspend all the executions of the remaining code.

Nevertheless, and as suggested, I'll implement the callbacks and hope these will solve my problem!

On my last attempt, I've added PendingOrders_Created() event. The goal was only to modify the value of a variable inside the event. However, soon I noticed that, unlike for a single order, the amount of orders keeps increasing whenever the "real" order is placed. A "clone" order is created, which does not happen if only a single order is initially defined. I also don't know why this is happening nor I do know how to solve this.

This seems to be related to the event subscription PendingOrders.Created += PendingOrders_Created, however, it won't work, at all, without this.
How can I make this event "code neutral" without affecting any of the cBot outcome? For instance, if I only want to execute a Print() inside the event?

 

Thank you!


@ncel01

prosteel1
19 Apr 2022, 18:27 ( Updated at: 19 Apr 2022, 19:03 )

RE: RE: RE: RE:

I use PendingOrders.Count and haven't seen an issue in use, it does seem to be updated as soon as an order is placed which seems to get around the delay between when an order is placed and when it is filled. Here is a roughly cropped example which you should be able to paste into your bot: If you can break it I'll be interested ;) But I think this was the solution to preventing multiple orders for me.

So regardless of code execution sequence semantics, if the point is to prevent multiple orders I believe this works because PendingOrders.Count gets updated immediately upon the placing of an order ;)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace NewcBot6
{
    [Robot(AccessRights = AccessRights.None)]
    public class NewcBot6 : Robot
    {
        int LongTradeActive = 0;
        int ShortTradeActive = 0;

        protected override void OnStart()
        {
            Print("OnStart");
            Positions.Opened += PositionsOnOpened;
            Positions.Closed += PositionsOnClosed;
        }

        protected override void OnTick()
        {
            // Handle price updates here
            Print("OnTick");
            SetTrade();
        }

        protected override void OnStop()
        {
            // Handle cBot stop here
            Print("OnStop");
        }

        private void SetTrade()
        {
            Print("SetTrade");
            int Longpendingorders = 0;
            int Shortpendingorders = 0;
            var LabelLong = "Long";
            var LabelShort = "Short";

            if (PendingOrders.Count(x => x.Label == LabelLong) > 0)
            {
                foreach (var order in PendingOrders)
                {
                    if (order.SymbolName == SymbolName)
                        Longpendingorders = 1;
                }
            }
            if (PendingOrders.Count(x => x.Label == LabelShort) > 0)
            {
                foreach (var order in PendingOrders)
                {
                    if (order.SymbolName == SymbolName)
                        Shortpendingorders = 1;
                }
            }

            if (LongTradeActive == 0 && Longpendingorders == 0 && Positions.Find(LabelLong, SymbolName) == null && Positions.Find(LabelShort, SymbolName) == null)
            {
                ExecuteMarketOrder(TradeType.Buy, SymbolName, 1000, LabelLong);
            }
            
            if (ShortTradeActive == 0 && Shortpendingorders == 0 && Positions.Find(LabelLong, SymbolName) == null && Positions.Find(LabelShort, SymbolName) == null)
            {
                ExecuteMarketOrder(TradeType.Sell, SymbolName, 1000, LabelShort);
            }

        }

        private void PositionsOnOpened(PositionOpenedEventArgs args)
        {
            Print("PositionsOnOpened");
            var pos = args.Position;
            if (pos.SymbolName == SymbolName)
            {
                if (pos.Label == "Long")
                {
                    LongTradeActive = 1;
                }
                if (pos.Label == "Short")
                {
                    ShortTradeActive = 1;
                }
            }
        }

        private void PositionsOnClosed(PositionClosedEventArgs args)
        {
            Print("PositionsOnClosed");
            var pos = args.Position;
            if (pos.SymbolName == SymbolName)
            {
                if (pos.Label == "Long")
                {
                    LongTradeActive = 0;
                }
                if (pos.Label == "Short")
                {
                    ShortTradeActive = 0;
                }
            }
        }
    }
}

 


@prosteel1

ncel01
24 Apr 2022, 23:17

RE: RE: RE: RE: RE:

prosteel1 said:

I use PendingOrders.Count and haven't seen an issue in use, it does seem to be updated as soon as an order is placed which seems to get around the delay between when an order is placed and when it is filled. Here is a roughly cropped example which you should be able to paste into your bot: If you can break it I'll be interested ;) But I think this was the solution to preventing multiple orders for me.

So regardless of code execution sequence semantics, if the point is to prevent multiple orders I believe this works because PendingOrders.Count gets updated immediately upon the placing of an order ;)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace NewcBot6
{
    [Robot(AccessRights = AccessRights.None)]
    public class NewcBot6 : Robot
    {
        int LongTradeActive = 0;
        int ShortTradeActive = 0;

        protected override void OnStart()
        {
            Print("OnStart");
            Positions.Opened += PositionsOnOpened;
            Positions.Closed += PositionsOnClosed;
        }

        protected override void OnTick()
        {
            // Handle price updates here
            Print("OnTick");
            SetTrade();
        }

        protected override void OnStop()
        {
            // Handle cBot stop here
            Print("OnStop");
        }

        private void SetTrade()
        {
            Print("SetTrade");
            int Longpendingorders = 0;
            int Shortpendingorders = 0;
            var LabelLong = "Long";
            var LabelShort = "Short";

            if (PendingOrders.Count(x => x.Label == LabelLong) > 0)
            {
                foreach (var order in PendingOrders)
                {
                    if (order.SymbolName == SymbolName)
                        Longpendingorders = 1;
                }
            }
            if (PendingOrders.Count(x => x.Label == LabelShort) > 0)
            {
                foreach (var order in PendingOrders)
                {
                    if (order.SymbolName == SymbolName)
                        Shortpendingorders = 1;
                }
            }

            if (LongTradeActive == 0 && Longpendingorders == 0 && Positions.Find(LabelLong, SymbolName) == null && Positions.Find(LabelShort, SymbolName) == null)
            {
                ExecuteMarketOrder(TradeType.Buy, SymbolName, 1000, LabelLong);
            }
            
            if (ShortTradeActive == 0 && Shortpendingorders == 0 && Positions.Find(LabelLong, SymbolName) == null && Positions.Find(LabelShort, SymbolName) == null)
            {
                ExecuteMarketOrder(TradeType.Sell, SymbolName, 1000, LabelShort);
            }

        }

        private void PositionsOnOpened(PositionOpenedEventArgs args)
        {
            Print("PositionsOnOpened");
            var pos = args.Position;
            if (pos.SymbolName == SymbolName)
            {
                if (pos.Label == "Long")
                {
                    LongTradeActive = 1;
                }
                if (pos.Label == "Short")
                {
                    ShortTradeActive = 1;
                }
            }
        }

        private void PositionsOnClosed(PositionClosedEventArgs args)
        {
            Print("PositionsOnClosed");
            var pos = args.Position;
            if (pos.SymbolName == SymbolName)
            {
                if (pos.Label == "Long")
                {
                    LongTradeActive = 0;
                }
                if (pos.Label == "Short")
                {
                    ShortTradeActive = 0;
                }
            }
        }
    }
}

 

Hi prosteel1,

Thanks for your reply but I've already found the issue!
I was changing a variable inside PendingOrders_Created() event, reason why another order was being created.
I am still trying to handle some residual issues associated to Async mode. Since my strategy involves a high amount of orders, using Sync mode won't be efficient at all, however, on the other hand, Async mode is not so intuitive nor it is as easy to manage.


@ncel01