Support Board
Date/Time: Wed, 27 Nov 2024 08:34:54 +0000
[Programming Help] - ASCIL Different OrderIDs for Same Order
View Count: 426
[2023-08-19 20:10:28] |
Gradient - Posts: 89 |
Hi, I'm doing a replay based backtest of a ASCIL strategy. I've written logic to check for resting orders and to cancel them if after some time threshold. (See Below). if (LongOrderId !=0){ sc.AddMessageToLog("LongOrderID Cancellation Check Beginning",1); //get the status of order s_SCTradeOrder LongTradeOrder; sc.GetOrderByOrderID(LongOrderId, LongTradeOrder); //find order if(LongTradeOrder.InternalOrderID==LongOrderId){ sc.AddMessageToLog("Looking Up Long Order for Cancellation",1); IsOrderFilled = LongTradeOrder.OrderStatusCode == SCT_OSC_FILLED; SCDateTime LongExecutionTime; LongExecutionTime=LongTradeOrder.LastActivityTime; int LongExecutionMinute=LongExecutionTime.GetMinute(); //if not filled send cancel if(IsOrderFilled==0 && (CurrentMinute - LongExecutionMinute)>1){ sc.SetAlert(1,"Trigger to Cancel Stale Order"); sc.AddMessageToLog("Stale Order Cancellation Triggered",1); int LongCancellation=sc.CancelOrder(LongOrderId); } } } if(ShortOrderId !=0) { sc.AddMessageToLog("ShortOrderID Cancellation Check Beginning",1); //get the status of the order s_SCTradeOrder ShortTradeOrder; sc.GetOrderByOrderID(ShortOrderId,ShortTradeOrder); //find order if (ShortTradeOrder.InternalOrderID == ShortOrderId){ sc.AddMessageToLog("Looking Up Short Order for Cancellation",1); SCDateTime ShortExecutionTime; IsOrderFilled=ShortTradeOrder.OrderStatusCode==SCT_OSC_FILLED; ShortExecutionTime=ShortTradeOrder.LastActivityTime; int ShortExecutionMinute=ShortExecutionTime.GetMinute(); //if not filled send cancel if (IsOrderFilled==0 && (CurrentMinute-ShortExecutionMinute)>1){ sc.SetAlert(1,"Trigger to Cancel Stale Order"); sc.AddMessageToLog("Stale Order Cancellation Triggered",1); int ShortCancellation=sc.CancelOrder(ShortOrderId); } } } //end of cancel stale orders I've noticed that, for example, the ShortOrderId is changing to a random number even though no new orders have been sent. In this case, the ShortOrderId is only set when a new sell order is created. See Attached From the Price Chart image, you can see that a buy order was stopped out. Thus there should be a LongOrderId which there is. A sell order was then sent after being stopped out of the long but wasn't filled. Looking at the Changing Error image, you can see that I'm logging the LongOrderId and ShortId, as well as the Bar Time and Execution Time when an order is submitted. You can also see that even though there are no new orders submitted (see Price Chart image) both the LongOrderId and the ShortOrderId both change. Referring back to the cancel order logic above, I log when checking if the OrderId matches the InternalOrderId of the retrieved order. This log is displayed correctly for a couple iterations but then stops because the ShortOrderId changes even though no new order has been sent, thus preventing the stale order from being canceled. How and why is this happening? Please Advise. Thanks. Date Time Of Last Edit: 2023-08-19 20:11:24
|
ShortOrderId Changing Price Chart.png / V - Attached On 2023-08-19 20:02:25 UTC - Size: 35.41 KB - 72 views ShortOrderId Changing Error.png / V - Attached On 2023-08-19 20:02:33 UTC - Size: 128.61 KB - 71 views |
[2023-08-19 21:37:39] |
Gradient - Posts: 89 |
After further analysis, Long and Short Order IDs are being set to the same value which programmatically isn't possible because these values are initialized once buy or sell signals are created. IDs shouldn't be the same and shouldn't be negative values. See Attached (Long and Short IDs Identical Error)
|
Long Short IDs Identical Error.png / V - Attached On 2023-08-19 21:28:20 UTC - Size: 40.91 KB - 68 views |
[2023-08-21 01:21:01] |
Gradient - Posts: 89 |
Those lines wouldn't cause the issue with the InternalOrderID of the TradeOrder. IsOrderFilled has no side effect on setting LongOrderId and ShortOrderId as this parameter is only set after the order ids have already been set. IsOrderFilled is a bool variable. See TradeSystem.cpp in ACS Source Folder. The variable is initialized identically to the way it is in that file. It is checking to see if the status is filled and returning a boolean value. The order ids are declared as int and only being set when there is a new trade initiated. Order Ids should only be generated when a new trade is initiated. I've shown that this is not the case. Also order ids should be discrete and non negative. |
[2023-08-21 08:31:34] |
User431178 - Posts: 543 |
The order ids are declared as int and only being set when there is a new trade initiated.
Where and how are LongOrderId and ShortOrderId being declared and set? Please post the relevant section of code. Order Ids should only be generated when a new trade is initiated. I've shown that this is not the case. Also order ids should be discrete and non negative.
This suggests a problem with your code.
|
[2023-08-21 13:06:14] |
Gradient - Posts: 89 |
Looking at the code block below, you can see that it's not possible to create a long order or short order id without the following conditions being true 1)drawdown not met, 2) policy (i.e. a buy or sell signal) and 3) and response from sending the order that's greater than zero. In the screenshots provided I showed the timestamp, of which was within the same minute of the most recent sell order, in which a new ShortOrderId was being created and from the code block below as well as the fact that no new sell signals appeared on the chart, that this was not due to a logic error. It also wouldn't explain why those numbers are negative. If you see an error in the logic below that would cause several new order ids to be created despite the default constraints of only taking one position at a time, no trade reversals still being in place, max position allowed=1, please point them out. //only trade if drawdown not met if(drawdown_met ==0){ if (policy==1){ //create new order s_SCNewOrder LongParentOrder; LongParentOrder.OrderQuantity=1; LongParentOrder.OrderType=SCT_ORDERTYPE_LIMIT_TOUCH_CHASE; LongParentOrder.TimeInForce=SCT_TIF_IMMEDIATE_OR_CANCEL; LongParentOrder.Price1=sc.Open[sc.Index]; LongParentOrder.MaximumChaseAsPrice=1; //send order int response=static_cast<int>(sc.BuyEntry(LongParentOrder)); if(response >0){ //store order id LongOrderId=LongParentOrder.InternalOrderID; //plot arrow at low of entry bar Subgraph_BuyEntry[sc.Index]=sc.Low[sc.Index]; if(LongOrderId !=0){ //lookup working properly per alert debug below sc.SetAlert(1,"Long Order Lookup Alert"); //get the order by order id s_SCTradeOrder TradeOrder; sc.GetOrderByOrderID(LongOrderId, TradeOrder); //sc.AddMessageToLog("Current Bar Time %d, Long Bar Entry Time %d".SCString::Format(CurrentBarTime,LongBarEntryTime),0); //find order if (TradeOrder.InternalOrderID == LongOrderId) { ExecutionTime=TradeOrder.LastActivityTime; double FillPrice = TradeOrder.LastFillPrice; //DEBUG: alert executiontime sc.SetAlert(1,"Capturing Long Order Execution Time"); //Note, Execution time is as of time of the signal; order is transmitted at close of bar; thus actual actual execution time is t+1 SCString Message; SCString ExecutionTimeString; SCString TimeDelta; SCString MinuteDelta; Message.Format("Current Bar Date-Time: %s", sc.FormatDateTime(sc.BaseDateTimeIn[sc.Index]).GetChars()); ExecutionTimeString.Format("Current Execution Date-Time: %s", sc.FormatDateTime(ExecutionTime).GetChars()); TimeDelta.Format("Current Time Delta %s",sc.FormatDateTime((ExecutionTime.GetTimeAsSCDateTime()-sc.BaseDateTimeIn.TimeAt(sc.Index))).GetChars()); sc.AddMessageToLog(Message,1); sc.AddMessageToLog(ExecutionTimeString,1); sc.AddMessageToLog(TimeDelta,1); ExecutionMinute = ExecutionTime.GetMinute(); //SCString ExecutionMinuteString; ExecutionMinuteString.Format("Current Execution Minute %d",ExecutionMinute); sc.AddMessageToLog(ExecutionMinuteString,1); }//end of long order id lookup }//end of long order id }//end of positive response for long entry }//end of policy 1 if (policy == -1){ //execute short //create new order s_SCNewOrder ShortParentOrder; ShortParentOrder.OrderQuantity=1; ShortParentOrder.OrderType=SCT_ORDERTYPE_LIMIT_TOUCH_CHASE; ShortParentOrder.TimeInForce=SCT_TIF_IMMEDIATE_OR_CANCEL; ShortParentOrder.Price1=sc.Open[sc.Index]; ShortParentOrder.MaximumChaseAsPrice= 1; //send order int response=static_cast<int>(sc.SellEntry(ShortParentOrder)); if(response > 0){ //store order id ShortOrderId=ShortParentOrder.InternalOrderID; //plot arrow at high of entry bar Subgraph_SellEntry[sc.Index]=sc.High[sc.Index]; //if elapsed time met and order not filled cancel order if(ShortOrderId !=0){ //get the order by order id s_SCTradeOrder TradeOrder; sc.GetOrderByOrderID(ShortOrderId, TradeOrder); // Order has been found. if (TradeOrder.InternalOrderID == ShortOrderId) { sc.SetAlert(1,"Short order lookup alert"); ExecutionTime=TradeOrder.LastActivityTime;//.EntryDateTime; //DEBUG: alert executiontime sc.SetAlert(1,"Capturing Short Order Execution Time"); SCString Message; SCString ExecutionTimeString; SCString TimeDelta; SCString MinuteDelta; Message.Format("Current Bar Date-Time: %s", sc.FormatDateTime(sc.BaseDateTimeIn[sc.Index]).GetChars()); ExecutionTimeString.Format("Current Execution Date-Time: %s", sc.FormatDateTime(ExecutionTime).GetChars()); TimeDelta.Format("Current Time Delta %s",sc.FormatDateTime((ExecutionTime.GetTimeAsSCDateTime()-sc.BaseDateTimeIn.TimeAt(sc.Index))).GetChars()); sc.AddMessageToLog(Message,1); sc.AddMessageToLog(ExecutionTimeString,1); sc.AddMessageToLog(TimeDelta,1); ExecutionMinute = ExecutionTime.GetMinute(); ExecutionMinuteString.Format("Current Execution Minute %d",ExecutionMinute); sc.AddMessageToLog(ExecutionMinuteString,1); } //end of short order lookup } //end of short order id positive }//end of if short policy positive response }//end of short policy |
[2023-08-21 13:13:06] |
User431178 - Posts: 543 |
That is essentially the same code you posted before, still need answer to question below. Where and how are LongOrderId and ShortOrderId being declared and set? Date Time Of Last Edit: 2023-08-21 13:36:29
|
[2023-08-21 13:20:28] |
Gradient - Posts: 89 |
This is a completely different code block than before. The prior code block was logic to cancel stale orders. The aforementioned block initiates those orders when a trade has taken place. The block below shows that these order ids (i.e. LongOrderId and ShortOrderId) are declared but not initialized until the prior mentioned conditions are met. As shown and stated in the prior reply, Order IDs are not being set until those three conditions are met. If no trade has taken place with a response > 0 there will be no LongOrderId or ShortOrderId. Order Ids being declared below: //trading policy int policy=GetTradingPolicy(sc); bool drawdown_met=GetDrawdown(sc); sc.AllowOnlyOneTradePerBar=true; //variables to track elapsed time of sent orders int ExecutionMinute; int CurrentMinute = sc.BaseDateTimeIn[sc.Index].GetMinute(); SCString CurrentMinuteString; SCString ExecutionMinuteString; CurrentMinuteString.Format("Current Minute %d",CurrentMinute); sc.AddMessageToLog(CurrentMinuteString,1); //display entries and exits on main graph instead of subgraph sc.GraphRegion=0; //current time SCDateTime CurrentTime=sc.CurrentSystemDateTime; SCDateTime ReplayTime=sc.CurrentDateTimeForReplay; SCDateTime CurrentBarTime=sc.BaseDateTimeIn.TimeAt(sc.Index); SCDateTime ExecutionTime; //variables to store order ids int LongOrderId; int ShortOrderId; bool IsOrderFilled; SCString LongOrderIdString; SCString ShortOrderIdString; LongOrderIdString.Format("Long Order Id: %d",LongOrderId); ShortOrderIdString.Format("Short Order Id: %d",ShortOrderId); sc.AddMessageToLog(LongOrderIdString,1); sc.AddMessageToLog(ShortOrderIdString,1); |
[2023-08-21 13:26:32] |
Gradient - Posts: 89 |
The issue is that the ShortOrderId for example was set properly when the sell order was taken. I printed the sell order id, though there were no new sell orders as can be seen on the price chart and the logs, the sell order id changed. If the logic is correct and the setting of the ShortOrderId can only happen when a new sell order has been sent, how can the ShortOrderId change in the same bar of the original sell order. |
[2023-08-21 13:29:25] |
Gradient - Posts: 89 |
Ultimately, the intent of capturing the LongOrderId and ShortOrderId is to track the elapsed time of the order and if at some threshold and not filled to cancel. Any suggestions for doing so in a robust manner are welcome. Thanks. |
[2023-08-21 13:33:39] |
ondafringe - Posts: 286 |
Misread your code, so deleted my earlier comments. Use the VS debugger to step through your code. Makes it much easier to track down problems. |
[2023-08-21 13:34:13] |
User431178 - Posts: 543 |
If the logic is correct and the setting of the ShortOrderId can only happen when a new sell order has been sent, how can the ShortOrderId change in the same bar of the original sell order.
It's not changing, on the next call into the study function you are reading the value of an uninitialized variable. This is undefined behavior and the value could essentially be anything. If you want the values to be available between function calls, then you need to use persistent variables. Persistent Variable Functions Ultimately, the intent of capturing the LongOrderId and ShortOrderId is to track the elapsed time of the order and if at some threshold and not filled to cancel.
See link above.For further information about the scope / lifetime of variables, please see - https://en.cppreference.com/w/cpp/language/scope Date Time Of Last Edit: 2023-08-21 13:37:37
|
[2023-08-21 13:38:14] |
Gradient - Posts: 89 |
Thanks. Will take a look now. |
[2023-08-28 21:07:40] |
ForgivingComputers.com - Posts: 960 |
You want your study to remember the OrderIDs from previous passes through the study function. OrderIDs should not be declared as int, but as Persistent Variables. int& LongOrderID = sc.GetPersistentInt(0);
int& ShortOrderID = sc.GetPersistentInt(1); |
To post a message in this thread, you need to log in with your Sierra Chart account: