Login Page - Create Account

Support Board


Date/Time: Mon, 21 Apr 2025 04:35:53 +0000



[Programming Help] - ACSIL Custom OCO

View Count: 140

[2025-03-09 23:24:55]
Gradient - Posts: 121
Hi,

I've noticed that some firms don't process orders properly and thus when sending OCOs, etc, the only order that appears on their end is the ParentOrder.

I decided to manually code the logic of an OCO to alleviate this and ensure that Stops and Targets get sent, but noticed when testing in Replay only the ParentOrders appear.

After getting the ParentOrder by OrderId I do the following:

note: exposure is an SCInputRef int value; tradeTarget is an int value
#################################################################################################################################################################
//check to see if in a position and if change from arrival price hits stop or target send order to exit
    if(ParentOrder.OrderStatusCode==SCT_OSC_FILLED){
      
      s_SCPositionData PositionData;
    
      sc.GetTradePosition(PositionData);
      
//Normalizing PnL into Ticks for comparison

      double pnlTicks=((PositionData.OpenProfitLoss)/50)/sc.TickSize;
      
      double TargetPnL=(tradeTarget*12.50)*PositionData.PositionQuantity;
      
      double StopPnL= -(exposure.GetInt()*12.50)*PositionData.PositionQuantity;
      
      double entryPrice=PositionData.AveragePrice;
      
      //Break Even
      if(pnlTicks==exposure.GetInt()){
        
        
        s_SCNewOrder BreakEven;
        
        BreakEven.OrderType=SCT_ORDERTYPE_MARKET_IF_TOUCHED;
        BreakEven.Price1=entryPrice;
        BreakEven.OrderQuantity=PositionData.PositionQuantity;
        
        if(PositionData.PositionQuantity>0){
          float BEResponse=static_cast<int>(sc.SellOrder(BreakEven));
        }
        else if(PositionData.PositionQuantity<0){
          float BEResponse=static_cast<int>(sc.BuyOrder(BreakEven));
        }
        sc.SetAlert(1,"Moved to BE");
        
        
      }//Target
      
      if(pnlTicks>=tradeTarget){
      
        
        s_SCNewOrder Target;
        
        Target.OrderType=SCT_ORDERTYPE_LIMIT;
        
        Target.OrderQuantity=PositionData.PositionQuantity;
        
        if(PositionData.PositionQuantity>0){
          Target.Price1=entryPrice+(tradeTarget*sc.TickSize);
          float TargetResponse=static_cast<int>(sc.SellOrder(Target));
        }
        else if(PositionData.PositionQuantity<0){
          Target.Price1=entryPrice-(tradeTarget*sc.TickSize);
          float TargetResponse=static_cast<int>(sc.BuyOrder(Target));
        }
        sc.SetAlert(1,"Target Sent");
        
        
      }//Stop
      
      if(pnlTicks<= -exposure.GetInt()){
        
        
        s_SCNewOrder Stop;
        
        Stop.OrderType=SCT_ORDERTYPE_MARKET;
        
        Stop.OrderQuantity=PositionData.PositionQuantity;
        
        if(PositionData.PositionQuantity>0){
          Stop.Price1=entryPrice-(tradeTarget*sc.TickSize);
          float TargetResponse=static_cast<int>(sc.SellOrder(Stop));
        }
        else if(PositionData.PositionQuantity<0){
          Stop.Price1=entryPrice+(tradeTarget*sc.TickSize);
          float TargetResponse=static_cast<int>(sc.BuyOrder(Stop));
        }
        sc.SetAlert(1,"Stop Sent");
        
        
      }
      
      //Exit Position if Stop or Target Achieved
      if(pnlTicks>=tradeTarget || pnlTicks <= -exposure.GetInt()){
        sc.SetAlert(1,"Flattened Positions");
        sc.FlattenAndCancelAllOrders();
      }
      
    }


#################################################################################################################################################################

Is there any logic within this code block that might explain this behavior?

Thanks
[2025-03-10 02:22:32]
cmet - Posts: 690
If the child orders are never sent, I would look at the way you're normalizing PnL to ticks. I could be wrong, but it seems in Replay mode (live too), those conditions would often be false.

Using the contract tick size alone or distance from entry in ticks + persistence might solve that.
[2025-03-10 04:07:51]
Gradient - Posts: 121
Thanks.

You helped identify an error.

So this normalization is specifically for the ES contract.

Logic was to divide the Open PnL by the contract value (eg. ES is $50 per point) to get the value per point which would still be in dollar terms and then divide that by the tick size to get the amount of ticks moved.

For example, if Open PnL in ES is $500 we would divide this by $50 to get 10 points. We could then divide this 10pts by 0.25 (i.e. ES tick value) to get 40 ticks

The error is that this computation doesn't generalize. It only assumes that we are trading one lots.

The correction is to:

$500 (open pnl) / $50 (point value)= 10 (number of points)

10 (number of points)/ X (the number of lots traded)= Y (points per lot)

Y (points per lot) / 0.25 (tick value) = number of ticks for given lot size.

I will implement this fix and retest, but checking the logs, the system was trying to generate the orders. (see attached)
Attachment Deleted.
imageCustom OCO Troubleshooting.png / V - Attached On 2025-03-10 04:05:54 UTC - Size: 95.18 KB - 22 views

To post a message in this thread, you need to log in with your Sierra Chart account:

Login

Login Page - Create Account