A typical sequence of events might be as follows:
NAME STATE
----- -----
Entry PendingSubmit
Entry Accepted
Entry Working
Entry Filled
Just to place an order. Then stop and target orders may follow suit depending on strategy.
To avoid multiple entry scenario, a custom Strategy must check if current position is flat first, before entering.
HOWEVER, if the check is done too soon, one falls into the trap/bug of reseting the strategyId before giving it a chance to be filled.
Therefore, I have found it prudent to perform this check on the next newbar generated on the chart. In otherwords, code snipet:
//Check for next bar
If (NewBar != CurrentBar)
{
NewBar = CurrentBar;
//Check for a pending entry order, DEBUG code
if (orderId.Length > 0)
{
statusx = GetAtmStrategyEntryOrderStatus(orderId);
// If the status call can't find the order specified, the return array length will be zero otherwise it will hold elements
if (statusx.GetLength(0) > 0)
{
// Print out some information about the order to the output window
Print("xThe entry order average fill price is: " + statusx[0]);
Print("xThe entry order filled amount is: " + statusx[1]);
Print("xThe entry order order state is: " + statusx[2]);
// If the order state is terminal, reset the order id value
if (statusx[2] == "Filled" || statusx[2] == "Cancelled" || statusx[2] == "Rejected")
{
Print("status:"+statusx[2]);
orderId = string.Empty;
}
}
}
else {};
// If was in a position and now flat, reset startegyId
if (atmStrategyId.Length > 0)
{
// DEBUG code
Print("The current ATM Strategy market position is: " + GetAtmStrategyMarketPosition(atmStrategyId));
if (GetAtmStrategyMarketPosition(atmStrategyId) == MarketPosition.Flat)
{
atmStrategyId = string.Empty;
// DEBUG code
Print("Position is flat so zero out atmStrategyId:"+atmStrategyId.Length);
}
}
}
{
// some more code for your strategy to generate signal events tradeSignalEvent, etc
}
// If event generated to enter a position, first check if currently flat.......
if ((orderId.Length == 0) && (atmStrategyId.Length == 0) && (tradeSignalEvent))
{
atmStrategyId = GetAtmStrategyUniqueId();
orderId = GetAtmStrategyUniqueId();
bool atmStatus = false;
// Use close of previous bar plus minus offset for stop order entry
atmStatus = AtmStrategyCreate(OrderAction.Sell, OrderType.Stop, 0, (Close[1] - 0.25), TimeInForce.Day, orderId, "2 Target Strategy", atmStrategyId);
//DEBUG code
Print("AtmStrategyCreate: "+atmStatus);
statusx = GetAtmStrategyEntryOrderStatus(orderId);
Print("orderId length:"+statusx.GetLength(0));
if (statusx.GetLength(0) > 0)
{
Print("The entry order average fill price is: " + statusx[0]);
Print("The entry order filled amount is: " + statusx[1]);
Print("The entry order order state is: " + statusx[2]);
}
Print("atmStrategy length:"+atmStrategyId.Length);
Print("The current ATM Strategy market position is: " + GetAtmStrategyMarketPosition(atmStrategyId));
Print("The current ATM Strategy position quantity is: " + GetAtmStrategyPositionQuantity(atmStrategyId));
Print("The current ATM Strategy average price is: " + GetAtmStrategyPositionAveragePrice(atmStrategyId)) ;
Print("The current ATM Strategy Unrealized PnL is: " + GetAtmStrategyUnrealizedProfitLoss(atmStrategyId)) ;
}
Hopefully, this illustrates what I am trying to explain. Curiously, I never fell into a race condition using Market Replay, only on a live feed.

Comment