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. ![]() |
To post a message in this thread, you need to log in with your Sierra Chart account: