Multiple sequential Async instructions: Suspending execution

Created at 24 Apr 2022, 23:43
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

Multiple sequential Async instructions: Suspending execution
24 Apr 2022, 23:43


Hello,

I would like to be aware of what can be the best approach when it comes to suspending execution, waiting for several Async instructions to be completed.

My strategy is made of several orders, which I would like to open/close/cancel in Asynchronous mode, while suspending the execution until the last instruction is completed/executed.
This way, I want to avoid a large (cumulative) time delay in execution, which will happen by calling Sync methods only.

Please note that these Async calls will mainly happen outside OnTick() event.

Is there a time delay, to simulate the server time response, considered in backtesting?

Below is an example of what I thought to be a solution, however it doesn't seem to work (at least when backtesting - "Backtesting was terminated due to timeout").

Could any of you provide some highlights on how to get this to work properly?

Thank you!

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

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

        protected override void OnStart()
        {
            SetTradesAsync();
            CancelAllPendingOrdersAsync();

            Stop();
        }

        private void SetTradesAsync()
        {

            var amountOfOrders = 20;
            var tradeOperations = new TradeOperation[amountOfOrders];

            for (int i = 0; i < amountOfOrders; i++)
                tradeOperations[i] = PlaceLimitOrderAsync(TradeType.Buy, SymbolName, Symbol.QuantityToVolumeInUnits(0.1), Symbol.Ask * 1.05, "Trade_" + i);

            while (tradeOperations.Any(result => result.IsExecuting))
            {
                Thread.Sleep(10);
                RefreshData();
            }

            Print("All orders have been created");
        }

        private void CancelAllPendingOrdersAsync()
        {
            var myPendingOrders = PendingOrders.Where(o => o.Label.Contains("Trade_")).ToArray();
            var tradeOperations = new TradeOperation[myPendingOrders.Length];

            for (int i = 0; i < myPendingOrders.Length; i++)
                tradeOperations[i] = CancelPendingOrderAsync(myPendingOrders[i]);

            while (tradeOperations.Any(result => result.IsExecuting))
            {
                Thread.Sleep(10);
                RefreshData();
            }

            Print("All orders have been cancelled");
        }

        protected override void OnStop()
        {
        }

    }
}

@ncel01
Replies

amusleh
26 Apr 2022, 09:41 ( Updated at: 27 Apr 2022, 10:00 )

Hi,

When using Async calls the main idea is to avoid blocking or suspending the thread, so you call the order place/cancel method and instead of waiting for response you can continue using the thread until the response come back for your requests, so you shouldn't block the thread at all.

Regarding your issue, there are several solutions, when it comes to async programming you can use callbacks like this:

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class Sample : Robot
    {
        private int _numberOfPendingPlaceOrderOperations;
        private int _numberOfPendingCancelOrderOperations;

        protected override void OnStart()
        {
            SetTradesAsync();
        }

        private void SetTradesAsync()
        {
            var amountOfOrders = 20;

            for (int i = 0; i < amountOfOrders; i++)
            {
                Interlocked.Increment(ref _numberOfPendingPlaceOrderOperations);

                PlaceLimitOrderAsync(TradeType.Buy, SymbolName, Symbol.VolumeInUnitsMin, Symbol.Ask - (Symbol.PipSize * 50), "Trade_" + i, OnOrderPlaced);
            }
        }

        private void OnOrderPlaced(TradeResult result)
        {
            if (Interlocked.Decrement(ref _numberOfPendingPlaceOrderOperations) == 0)
            {
                Print("All orders have been created");

                CancelAllPendingOrdersAsync();
            }
        }

        private void CancelAllPendingOrdersAsync()
        {
            var myPendingOrders = PendingOrders.Where(o => o.Label.Contains("Trade_")).ToArray();

            foreach (var order in myPendingOrders)
            {
                Interlocked.Increment(ref _numberOfPendingCancelOrderOperations);

                CancelPendingOrderAsync(order, OnOrderCancel);
            }
        }

        private void OnOrderCancel(TradeResult result)
        {
            if (Interlocked.Decrement(ref _numberOfPendingCancelOrderOperations) == 0)
            {
                Print("All orders have been canceled");

                Stop();
            }
        }
    }
}

The better approach would be to use .NET async/await from Task parallel library but unfortunately cTrader automate API is not supporting them for now so you have to use the old callbacks pattern.


@amusleh

ncel01
26 Apr 2022, 14:46

RE:

amusleh said:

Hi,

When using Async calls the main idea is to avoid blocking or suspending the thread, so you call the order place/cancel method and instead of waiting for response you can continue using the thread until the response come back for your requests, so you shouldn't block the thread at all.

Regarding your issue, there are several solutions, when it comes to async programming you can use callbacks like this:

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class Sample : Robot
    {
        private int _numberOfPendingPlaceOrderOperations;
        private int _numberOfPendingCancelOrderOperations;

        protected override void OnStart()
        {
            SetTradesAsync();
        }

        private void SetTradesAsync()
        {
            var amountOfOrders = 20;

            for (int i = 0; i < amountOfOrders; i++)
            {
                Interlocked.Increment(ref _numberOfPendingPlaceOrderOperations);

                PlaceLimitOrderAsync(TradeType.Buy, SymbolName, Symbol.VolumeInUnitsMin, Symbol.Ask - (Symbol.PipSize * 50), "Trade_" + i, OnOrderPlaced);
            }
        }

        private void OnOrderPlaced(TradeResult result)
        {
            Interlocked.Decrement(ref _numberOfPendingPlaceOrderOperations);

            if (Interlocked.CompareExchange(ref _numberOfPendingPlaceOrderOperations, 0, 0) == 0)
            {
                Print("All orders have been created");

                CancelAllPendingOrdersAsync();
            }
        }

        private void CancelAllPendingOrdersAsync()
        {
            var myPendingOrders = PendingOrders.Where(o => o.Label.Contains("Trade_")).ToArray();

            foreach (var order in myPendingOrders)
            {
                Interlocked.Increment(ref _numberOfPendingCancelOrderOperations);

                CancelPendingOrderAsync(order, OnOrderCancel);
            }
        }

        private void OnOrderCancel(TradeResult result)
        {
            Interlocked.Decrement(ref _numberOfPendingCancelOrderOperations);

            if (Interlocked.CompareExchange(ref _numberOfPendingCancelOrderOperations, 0, 0) == 0)
            {
                Print("All orders have been canceled");

                Stop();
            }
        }
    }
}

The better approach would be to use .NET async/await from Task parallel library but unfortunately cTrader automate API is not supporting them for now so you have to use the old callbacks pattern.

Hi amusleh,

Thanks for your reply. 

I want to suspend the thread only to control the execution. However, rather than executing multiple Sync instructions (waiting for all to be processed, one by one), my goal is to execute Async methods and only wait for the latest instruction to be executed, so that execution time can be made as short as possible, since it won't be depending on the amount of instructions (orders created/cancelled). 

Is this the code behavior, when using the OnOrderPlaced() and OnOrderCancel() methods as arguments in the Async methods, as shown above?

Is there a time delay, used to simulate the server time response, considered in backtesting?

Thank you once again!

 

 


@ncel01

amusleh
27 Apr 2022, 08:24 ( Updated at: 28 Apr 2022, 09:15 )

Hi,

The code I posted does the same thing but without suspending the thread or causing any delay, that's the fastest possible solution.

Regarding time delay, no there is no such function in API and I don't think there is a need for something like that.


@amusleh

ncel01
27 Apr 2022, 13:40

RE:

amusleh said:

Hi,

The code I posted does the same thing but without suspending the thread of causing any delay, that's the fastest possible solution.

Regarding time delay, no there no such function in API and I don't think there is a need for something like that.

Hi amusleh,

It sounds good. Many thanks!

Regarding the time delay, I asked to be aware if this was considered when backtesting.

If that's not the case, any possible issues due to Async execution can only be noticed when running cBot in real time I am afraid.


@ncel01