I need some help. I am using unmanaged order entry, and everything seems to work as expected besides the stop loss order for the long entry.
I cannot see why this fails but it does not work. Proditarhet is 2 points = 8 ticks stoploss is 1 point = 4 ticks.
As can b e seen from the screenshot there are some massive losers here all with Exit on session close, but these should have been exited long before with a loss of 1 point.
The issue seems to be only for the long stop loss order.
namespace NinjaTrader.NinjaScript.Strategies
{
public class Strat : Strategy
{
private Order shortEntry = null;
private Order longEntry = null;
private Order targetLong = null;
private Order targetShort = null;
private Order stopLossShort = null;
private Order stopLossLong = null;
private string oco;
private int ProfitDistance = 8;
private int StopDistance = 4;
private int sumFilledLong = 0;
private int sumFilledShort = 0;
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
Description = @"Enter the description for your new custom Strategy here.";
Name = "Strat";
Calculate = Calculate.OnBarClose;
EntriesPerDirection = 1;
EntryHandling = EntryHandling.AllEntries;
IsExitOnSessionCloseStrategy = true;
ExitOnSessionCloseSeconds = 30;
IsFillLimitOnTouch = false;
MaximumBarsLookBack = MaximumBarsLookBack.TwoHundredFiftySix;
OrderFillResolution = OrderFillResolution.Standard;
Slippage = 0;
StartBehavior = StartBehavior.WaitUntilFlat;
TimeInForce = TimeInForce.Gtc;
TraceOrders = false;
RealtimeErrorHandling = RealtimeErrorHandling.StopCancelClose;
StopTargetHandling = StopTargetHandling.PerEntryExecution;
BarsRequiredToTrade = 2;
IsUnmanaged = true;
IsInstantiatedOnEachOptimizationIteration = true;
}
else if (State == State.Configure)
{
}
else if (State == State.Realtime)
{
var aStrategyPosition = this.Position;
var aRealAccount = PositionAccount;
// convert any old historical order object references
// to the new live order submitted to the real-time account
if (shortEntry != null)
shortEntry = GetRealtimeOrder(shortEntry);
if (longEntry != null)
longEntry = GetRealtimeOrder(longEntry);
if (targetLong != null)
targetLong = GetRealtimeOrder(targetLong);
if (targetShort != null)
targetShort = GetRealtimeOrder(targetShort);
if (stopLossShort != null)
stopLossShort = GetRealtimeOrder(stopLossShort);
if (stopLossLong != null)
stopLossLong = GetRealtimeOrder(stopLossLong);
}
}
protected override void OnBarUpdate()
{
if (CurrentBar < 20)
return;
string scenario = GetScenario();
if (longEntry == null && shortEntry == null && Position.MarketPosition == MarketPosition.Flat)
{
if (State == State.Historical)
oco = DateTime.Now.ToString() + CurrentBar + "entry";
else
oco = GetAtmStrategyUniqueId() + "entry";
if (scenario == "1")
{
longEntry = SubmitOrderUnmanaged(0, OrderAction.Buy, OrderType.StopMarket, 1, 0, High[0] + 1 * TickSize, oco, "Long_IB");
shortEntry = SubmitOrderUnmanaged(0, OrderAction.SellShort, OrderType.StopMarket, 1, 0, Low[0] - 1 * TickSize, oco, "Short_IB");
}
}
}
private string GetScenario()
{
string scenario = "0";
if (High[0] <= High[1] && Low[0] >= Low[1])
{//Inside Bar
scenario = "1";
}
else if (High[0] >= High[1] && Low[0] >= Low[1])
{
scenario = "2u";
}
else if (High[0] <= High[1] && Low[0] <= Low[1])
{
scenario = "2d";
}
else if (High[0] > High[1] && Low[0] < Low[1])
{
scenario = "3";
}
return scenario;
}
protected override void OnExecutionUpdate(Execution execution, string executionId, double price, int quantity, MarketPosition marketPosition, string orderId, DateTime time)
{
if (longEntry != null && longEntry == execution.Order)
{
if (execution.Order.OrderState == OrderState.Filled
|| execution.Order.OrderState == OrderState.PartFilled
|| (execution.Order.OrderState == OrderState.Cancelled && execution.Order.Filled > 0))
{
sumFilledLong += execution.Quantity;
if (State == State.Historical)
oco = DateTime.Now.ToString() + CurrentBar + "LongExits";
else
oco = GetAtmStrategyUniqueId() + "LongExits";
if (stopLossLong == null && targetLong == null)
{
SubmitOrderUnmanaged(0, OrderAction.Sell, OrderType.StopMarket, execution.Order.Filled,0,execution.Order.AverageFi llPrice - StopDistance * TickSize, oco, "StopLossLong");
SubmitOrderUnmanaged(0, OrderAction.Sell, OrderType.Limit, execution.Order.Filled, execution.Order.AverageFillPrice + ProfitDistance * TickSize, 0, oco, "TargetLong");
}
else
{
// Submit exit orders for partial fills
if (execution.Order.OrderState == OrderState.PartFilled)
{
ChangeOrder(stopLossLong, execution.Order.Filled, 0, execution.Order.AverageFillPrice - StopDistance * TickSize);
ChangeOrder(targetLong, execution.Order.Filled, execution.Order.AverageFillPrice + ProfitDistance * TickSize, 0);
}
// Update our exit order quantities once orderstate turns to filled and we have seen execution quantities match order quantities
else if (execution.Order.OrderState == OrderState.Filled && sumFilledLong == execution.Order.Filled)
{
// Stop-Loss order for OrderState.Filled
ChangeOrder(stopLossLong, execution.Order.Filled, 0, execution.Order.AverageFillPrice - StopDistance * TickSize);
ChangeOrder(targetLong, execution.Order.Filled, execution.Order.AverageFillPrice + ProfitDistance * TickSize, 0);
}
}
// Resets the entryOrder object and the sumFilled counter to null / 0 after the order has been filled
if (execution.Order.OrderState != OrderState.PartFilled && sumFilledLong == execution.Order.Filled)
{
longEntry = null;
sumFilledLong = 0;
}
}
}
if (shortEntry != null && shortEntry == execution.Order)
{
if (execution.Order.OrderState == OrderState.Filled
|| execution.Order.OrderState == OrderState.PartFilled
|| (execution.Order.OrderState == OrderState.Cancelled && execution.Order.Filled > 0))
{
// We sum the quantities of each execution making up the entry order
sumFilledShort += execution.Quantity;
if (State == State.Historical)
oco = DateTime.Now.ToString() + CurrentBar + "ShortExits";
else
oco = GetAtmStrategyUniqueId() + "ShortExits";
if (stopLossShort == null && targetShort == null)
{
SubmitOrderUnmanaged(0, OrderAction.BuyToCover, OrderType.StopMarket, execution.Order.Filled, 0, execution.Order.AverageFillPrice + StopDistance * TickSize, oco, "StopLossShort");
SubmitOrderUnmanaged(0, OrderAction.BuyToCover, OrderType.Limit, execution.Order.Filled, execution.Order.AverageFillPrice - ProfitDistance * TickSize, 0, oco, "TargetShort");
}
else
{
// Submit exit orders for partial fills
if (execution.Order.OrderState == OrderState.PartFilled)
{
ChangeOrder(stopLossShort, execution.Order.Filled, 0, execution.Order.AverageFillPrice + StopDistance * TickSize);
ChangeOrder(targetShort, execution.Order.Filled, execution.Order.AverageFillPrice - ProfitDistance * TickSize, 0);
}
// Update our exit order quantities once orderstate turns to filled and we have seen execution quantities match order quantities
else if (execution.Order.OrderState == OrderState.Filled && sumFilledShort == execution.Order.Filled)
{
// Stop-Loss order for OrderState.Filled
ChangeOrder(stopLossShort, execution.Order.Filled, 0, execution.Order.AverageFillPrice + StopDistance * TickSize);
ChangeOrder(targetShort, execution.Order.Filled, execution.Order.AverageFillPrice - ProfitDistance * TickSize, 0);
}
}
// Resets the entryOrder object and the sumFilled counter to null / 0 after the order has been filled
if (execution.Order.OrderState != OrderState.PartFilled && sumFilledShort == execution.Order.Filled)
{
shortEntry = null;
sumFilledShort = 0;
}
}
}
// Reset our stop order and target orders' Order objects after our position is closed.
if ((stopLossLong != null && stopLossLong == execution.Order) || (targetLong != null && targetLong == execution.Order))
{
if (execution.Order.OrderState == OrderState.Filled
|| execution.Order.OrderState == OrderState.PartFilled)
{
stopLossLong = null;
targetLong = null;
}
}
if ((stopLossShort != null && stopLossShort == execution.Order) || (targetShort != null && targetShort == execution.Order))
{
if (execution.Order.OrderState == OrderState.Filled
|| execution.Order.OrderState == OrderState.PartFilled)
{
stopLossShort = null;
targetShort = null;
}
}
}
protected override void OnOrderUpdate(Order order, double limitPrice, double stopPrice, int quantity, int filled, double averageFillPrice, OrderState orderState, DateTime time, ErrorCode error, string nativeError)
{
// Assign Order objects here
// This is more reliable than assigning Order objects in OnBarUpdate, as the assignment is not guaranteed to be complete if it is referenced immediately after submitting
if (order.Name == "Short_IB")
shortEntry = order;
else if (order.Name == "Long_IB")
longEntry = order;
else if (order.Name == "StopLossLong")
stopLossLong = order;
else if (order.Name == "TargetLong")
targetLong = order;
else if (order.Name == "StopLossShort")
stopLossShort = order;
else if (order.Name == "TargetShort")
targetShort = order;
if (longEntry != null && longEntry == order)
{
// Reset the longTop object to null if order was cancelled without any fill
if (order.OrderState == OrderState.Cancelled && order.Filled == 0)
{
longEntry = null;
sumFilledLong = 0;
}
}
if (shortEntry != null && shortEntry == order)
{
// Reset the shortTop object to null if order was cancelled without any fill
if (order.OrderState == OrderState.Cancelled && order.Filled == 0)
{
shortEntry = null;
sumFilledShort = 0;
}
}
//sets all targets and stops to null if one of them is canceled
//PLEASE NOTE: setting IOrders to null ***DOES NOT*** cancel them
if ((targetLong != null && targetLong == order)
|| (stopLossLong != null && stopLossLong == order)
|| (targetShort != null && targetShort == order)
|| (stopLossShort != null && stopLossShort == order)
)
{
if (order.OrderState == OrderState.Cancelled && order.Filled == 0)
{
targetLong = stopLossLong = targetShort = stopLossShort = null;
}
}
}
}
}

Comment