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