Help required to work around the Position.Modified event missing in cAlgo API

Created at 14 May 2016, 13:08
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!
30

3082492

Joined 23.01.2015

Help required to work around the Position.Modified event missing in cAlgo API
14 May 2016, 13:08


Dear all, 

I need some advice on how to tackle the following problem:

My cBot creates a pending order based on some logic. When this pending order turns into an open position, the Position.Opened event registered in OnStart triggers DoSomething which reads the stop-loss and take-profit price of the opened position. In cAlgo, stop-loss and take-profit protection is assigned asynchronously to new positions. As the cAlgo API does not feature a Position.Modified event, I need to make the Position.Opened event wait until stop-loss and take-profit have been assigned.

Below please find the stripped and simplified code. The idea of the work-around is that DoSomething waits until the asynchronous process of setting stop-loss and take-profit has completed. For some reason, it never makes its way out of the while-loop, and hence the cBot hangs. Any idea about what I am doing wrong or about alternative solutions would be highly appreciated.

Thank you for your help!

John

protected override void OnStart()
{
    Positions.Opened += DoSomething;
}

protected override void OnTick()
{
// Some logic to create a pending order
}

private void DoSomething(PositionOpenedEventArgs args)
{
    Position pos = args.Position;
    while (!pos.StopLoss.HasValue || !pos.TakeProfit.HasValue)
    {
        Print("Waiting for SL and TP to be assigned to pos {0}...", pos.Id);
        Thread.Sleep(1000);
        pos = Positions.Where(p => p.Id == args.Position.Id).First<Position>();
    }

    Print("Stoploss price of position is {0}", pos.StopLoss.Value);
}

 


@3082492
Replies

solark
14 May 2016, 19:07

The while loop is stalling the main thread. You're gonna want to kick the check off to another thread then get back to the main thread when the condition is met. Try

 

        private void DoSomething(PositionOpenedEventArgs args)
        {
            Position pos = args.Position;

            var task = new System.Threading.Tasks.Task(() =>
            {
                while (!pos.StopLoss.HasValue || !pos.TakeProfit.HasValue)
                {
                    Print("Waiting for SL and TP to be assigned to pos {0}...", pos.Id);
                    Thread.Sleep(1000);
                    this.BeginInvokeOnMainThread(() => pos = Positions.Where(p => p.Id == args.Position.Id).First<Position>());
                }
            });
            task.Start();
            Print("Stoploss price of position is {0}", pos.StopLoss.Value);
        }

 

 

So you put the check into a Task, run the task. Once the stop loss and take profit are set then use BeginInvokeOnMainThread to get back to the main cbot thread. Untested and could obviously be cleaned up a bit.


@solark

3082492
14 May 2016, 20:04

RE:

Hi Solark, 

Thanks a ton for your reply and code example. Multi-threading is beyond my coding skills, so your example really is a great help!

Best regards,

John


@3082492

3082492
25 May 2016, 23:30

Hi Solark, 

I am facing another threading-related challenge. Maybe you are willing help if you read this:

I am running multiple instances of the same cBot in parallel, e.g. one on EURUSD and a second one on USDJPY. I want to limit the number of open positions to exactly one across all instances at any point in time. The following piece of code does not seem to do the trick. I also tried to wrap mutex around the if-statement to make both instances wait for the other to finish creating a position; however, two parallel cBot instances each opened a position. Could you provide some advise?

protected override void OnTick()
{
   if (Positions.Count(p => p.Comment.Contains(Name)) == 0) // Allow a single position at a time.
   {
      // do stuff
   }
}

Best regards,

John


@3082492

3082492
26 May 2016, 18:24

RE:

Hi, 

I seem to have found a solution that, while it might not be the perfect solution, works for me. I am sharing it so that others who face the same challenge can save some time. Please forgive me in case I do not use the correct technical words; multi-threading and concurrent processes really is way beyond my understanding. 

The problem: The following piece of code DOES NOT prevent parallel instances of the same cBot, e.g. one running on EURUSD and another one on GBPUSD, from opening more than one position. I believe this is because concurrent processes (the parallel cBot instances) execute this piece of code at the same time so that both get zero as a return value from Positions.Count().

protected override void OnTick()
{
    if(Positions.Count() == 0) // Prevent concurrent processes (same cBot running in parallel multiple times). DOES NOT WORK.
    {
       // Open new position.
    }
}

 

While all my attempts to use a lock or mutex to solve the problem failed, the following piece of code did the trick for me: 

using System.Threading;

...

private static int tradeOperationIsExecuting = 0; // Indicates whether a tradeOperation is in progress.

...

protected override void OnTick()
{
    if(Interlocked.Exchange(ref tradeOperationIsExecuting, 1) == 0) // Lock the following section for concurrent processes.
    {
        if (Positions.Count(p => p.Comment.Contains(Name)) == 0) // Allow a single position at a time.
        {
           // Business logic to open a new position.
        }
        Interlocked.Exchange(ref tradeOperationIsExecuting, 0); // Release lock.
    }
}

 

If you know a way how to improve this or do it in a more correct way, please let me know.

 

Regards,

John

 


@3082492