Multiple Close Single Action

Created at 30 May 2019, 13:56
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!
GDPR-83_694920's avatar

GDPR-83_694920

Joined 27.02.2019 Blocked

Multiple Close Single Action
30 May 2019, 13:56


Have been trying to figure this out for (quite!) some time but just can't get it...

I want to perform a single action (open a new trade) once a bunch of trades for example all with the same take profit close

Using the Positions.Closed += OnPositionsClosed means that every time a position closes this method loops through and from what I have experienced from months of experimenting with different cBots this seems to happen irrespective of whether a tick has occured which as I understand it is the only time the main code will run

This seems to me to be multithreading but have read this is not happening/available in cAlgo but I am 99% convinced both the Positions.Closed/Open += methods run in parrallel with the main code when they are triggered

So how can I get a new position to only open one time when 10 trades close at exactly the same time?

I have tried many many different approaches to solving this but the latest/most succesful so far has been using a counter (++counter;) --- then ---- if (counter==1) {executemarketorder(...)} in the OnPositionsClosed method whilst having counter=0; in the main OnTick code

The idea is that if it is true as it would seem to be the case that the OnPositionsClosed is running in parrallel regardless of ticks (and using Print commands to see how each action is playing out this has been confirmed a few times) then trade 1 closes -> counter=1 -> trade executes -> trades 2,3,4,5...10 close as counter increases 2,3,4,5...10 so counter does not equal 1 therefore no further trades are placed

This seems to work most of the time but not every time it would seem - what I think is happening is that occassionaly a tick occurs whilst the 10 trades are closing and so counter is reset to 0 and another trade is therefore executed in the OnPositionsClosed method

Hope this makes sense... can anyone help/point me in the right direction please?

Many thanks

Max


Replies

PanagiotisCharalampous
31 May 2019, 09:41

Hi Max,

This is not multithreading but event criven programming. Both OnPositionsClosed and OnTick are event which do not depend on each other. My approach would be to trigger the order only when all the positions of the group have closed. However without the cBot code we cannot provide specific guidance as we can only make assumptions about it.

Best Regards,

Panagiotis


@PanagiotisCharalampous

GDPR-83_694920
31 May 2019, 10:28

Hi Panagiotis

Ok many thanks for confimring about the event driven programming and that they run independantly/it is not multithreading

Yes that is exactly what I am trying to achieve - trigger the new order only once the last of the group of closing trades has completed through the OnPositionsClosed method

Here is an example code I quickly put together - slightly different from the original question in that I am actually using a CloseAllPositions method to trigger the closing of a group of trades and also obviously this code is not complete but hopefully is enough to give you an idea

        protected override void OnStart()
        {
            Positions.Closed += OnPositionsClosed;
        }
        protected override void OnTick()
        {
            Counter=0;
            if (x=y)
               CloseAllPostions();
        }
        private void CloseAllPositions()
        {
            foreach (Position p in Positions.Where(p => p.Label == BotLabel).ToArray())
                ClosePosition(p);
        }
        private void OnPositionsClosed(PositionClosedEventArgs args)
        {
            Position pos = args.Position;
            if (pos.Label == BotLabel)
            {
                ++Counter;
                if (Counter == 1)
                    ExecuteMarketOrder(TradeType.Buy, Symbol, Volume, BotLabel, null, null);
            }
        }

Obviously this will trigger the new trade when the first of the group of closing trades loops through the OPC method and yes as you say I would much rather do this only when the last of the group of trades has looped through the OPC so another way I tried was to count the number of open positions in the CloseAllPositions method before they were closed and trigger the new order in the OPC method only when the number of orders are zero

        private void CloseAllPositions()
        {
         OpenPositionsCount = Positions.Where(p => p.Label == BotLabel).Count();
         foreach (Position p in Positions.Where(p => p.Label == BotLabel).ToArray())
                ClosePosition(p);
        }
        private void OnPositionsClosed(PositionClosedEventArgs args)
        {
            Position p = args.Position;
            if (p.Label == BotLabel)
            {
             if (OpenPositionsCount==0)
                    ExecuteMarketOrder(TradeType.Buy, Symbol, Volume, BotLabel, null, 5);
            }
        }

It was very quickly clear that this doesn't work though (it was an early attempt at figuring this out but wanted to put it in as one of the alternative ideas) as the number of orders are already zero by the time the first loop of the OPC occurs as they have all been closed already and it is only the event driven programming that is processing these closures through the OPC so 10 new orders are triggered as they loop through the OPC

There are quite a few other ways I tried but all had their own problems and as I say the ++Counter approach seems to work the best but gets messed up if a tick occurs in the time that the group of closing orders are being processed through the OPC

Hope that is what you are after in terms of a better explanation - basically I guess the question is "how is it possible to properly 'detect' that event driven programming processes have properly completed?"

(Although I think that is not really a correct/impossible to answer question but hopefully it makes some sense!)

Many thanks

Max


PanagiotisCharalampous
31 May 2019, 10:47

Hi Max,

I thing I am still missing something since if this was the code you are using then the solution would be as simple as this

private void CloseAllPositions()
{
    foreach (Position p in Positions.Where(p => p.Label == BotLabel).ToArray())
        ClosePosition(p);
    ExecuteMarketOrder(TradeType.Buy, Symbol, Volume, BotLabel, null, 5);
}

However I am sure this is not the case :) and this is just an exampe. From what I understand, the positions are closed by TP so you are not sure when did all the positions close and if there are other Closed events coming. So my suggestion is to keep each position you open in a collection (list, dictionary etc) and remove it from the collection as soon as you receive the Closed event for that position. As soon as the collection is empty (meaning all positions closed successfully) you can proceed with sending the new order.

Let me know if this gives you a direction.

Best Regards,

Panagiotis


@PanagiotisCharalampous

GDPR-83_694920
31 May 2019, 11:05

Haha :) yes I knew something like that would happen - there are much easier ways to achieve the same result as I have presented it!

But of course this is not the full code/strategy although I think you have got it there/on the right track with the collection idea

The basic idea behind the strategy is to open two opposing positions each with a TP - when a TP is hit again two opposing positions are to be opened with their own TP's

The TP's are modified as time progresses in a manner that means in some situations multiple Buy positions (for example) would all have the same TP (for example 6 out of the 10 exisiting Buy positions now have the same TP) which will all close at the same time when their TP is hit

When this happens I want to only open one more pair of Buy/Sell order (not 6 pairs!)

So yes I think this could be achieved with the collections idea as you suggest but hmmmmm.... looking at it again/quickly thinking it through perhaps not as it would only be 6 of the 10 orders (in this example) that are closing...

Maybe this further explanation will help you come up with another approach or even if not it would be great if you could give an example of how what you've already said could be achieved - I have no problem creating the collection but how/where would I receive the Closed event and process it properly...?