Here's the code:
{ public class AdoptAccountPositionAndSubmitProtectiveSLPTOrders : Strategy { private bool DoOnceLong = false; private bool DoOnceShort = false; private Order ptLongOrder = null; private Order slLongOrder = null; private Order ptShortOrder = null; private Order slShortOrder = null; /// <summary> /// This strategy will adapt the current account position and then submit a PT limit order and SL Stop order. /// Upon either the PT or SL or even a manual order which closes the account position, working SL and PT orders /// will be canceled. /// /// You can manually cancel the orders on chart, and it won't disable strategy. /// /// Written By Alan Palmer. /// </summary> protected override void OnStateChange() { if (State == State.SetDefaults) { Description = @"Enter the description for your new custom Strategy here."; Name = "AdoptAccountPositionAndSubmitProtectiveSLPTOrders "; Calculate = Calculate.OnBarClose; EntriesPerDirection = 9; EntryHandling = EntryHandling.UniqueEntries; IsExitOnSessionCloseStrategy = false; ExitOnSessionCloseSeconds = 30; IsFillLimitOnTouch = false; MaximumBarsLookBack = MaximumBarsLookBack.TwoHundredFiftySix; OrderFillResolution = OrderFillResolution.Standard; Slippage = 0; StartBehavior = StartBehavior.AdoptAccountPosition; TimeInForce = TimeInForce.Gtc; TraceOrders = false; RealtimeErrorHandling = RealtimeErrorHandling.IgnoreAllErrors; StopTargetHandling = StopTargetHandling.PerEntryExecution; BarsRequiredToTrade = 0; // Disable this property for performance gains in Strategy Analyzer optimizations // See the Help Guide for additional information IsInstantiatedOnEachOptimizationIteration = true; IsAdoptAccountPositionAware = true; Period = 5; Multi = 3.5; } else if (State == State.Configure) { } } protected override void OnBarUpdate() { if(State == State.Historical) return; Print(State.ToString()+PositionsAccount[0].Quantity.ToString()); Print(PositionsAccount[0].MarketPosition.ToString()); ///If account position is long upon starting strategy, submit a PT and SL order for the open position. if(PositionsAccount[0].MarketPosition == MarketPosition.Long && DoOnceLong == false) { double trail; double loss = ATR(Input, Period)[0] * Multi; if (Close[0] > Value[1] && Close[1] > Value[1]) trail = Math.Max(Value[1], Close[0] - loss); else if (Close[0] < Value[1] && Close[1] < Value[1]) trail = Math.Min(Value[1], Close[0] + loss); else if (Close[0] > Value[1]) { trail = Close[0] - loss; } else { trail = Close[0] + loss; } Value[0] = trail; Print("Position is long"); ExitLongLimit(0, true, PositionsAccount[0].Quantity, Close[0]*1.01,"LongLimitPT", ""); ExitLongStopMarket(0, true, PositionsAccount[0].Quantity, Close[0]*.99, "StopForLong", ""); DoOnceLong = true; if(Close[0] < trail) { ExitLong(0, PositionsAccount[0].Quantity, "TrailStopForLong", ""); } } ///If account position is short upon starting strategy, submit a PT and SL order for the open position. if(PositionsAccount[0].MarketPosition == MarketPosition.Short && DoOnceShort ==false) { Print("Position is short"); ExitShortLimit(0, true, PositionsAccount[0].Quantity, Close[0]*.99,"ShortLimitPT", ""); //Submit PT Limit order for open position ExitShortStopMarket(0, true, PositionsAccount[0].Quantity, Close[0]*1.01, "StopForShort", ""); //Submit SL order for open position DoOnceShort =true; } ///Should 1 SL or PT or manual order close the position, then need to cancel orders. if(PositionsAccount[0].MarketPosition == MarketPosition.Flat) { Print("Cancel all orders"); if(ptLongOrder != null); //Checking that order object is not null before canceling orders. { CancelOrder(ptLongOrder); //Cancel ptOrder since we are now flat. ptLongOrder=null; //Setting order objects back to null. } if(slLongOrder != null); { CancelOrder(slLongOrder); slLongOrder=null; } if(ptShortOrder != null); { CancelOrder(ptShortOrder); ptShortOrder=null; } if(slShortOrder != null); { CancelOrder(slShortOrder); slShortOrder=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) { //Assiging order objects to SL and PT for the purpose of canceling orders if the position becomes flat. if (order.Name == "LongLimitPT" && orderState != OrderState.Working) ptLongOrder = order; if (order.Name == "StopForLong" && orderState != OrderState.Accepted ) slLongOrder = order; if (order.Name == "ShortLimitPT" && orderState != OrderState.Working) ptShortOrder = order; if (order.Name == "StopForShort" && orderState != OrderState.Accepted) slShortOrder = order; } #region Properties [NinjaScriptProperty] [Range(1, int.MaxValue)] [Display(Name="Period", Description="ATR period", Order=1, GroupName="Parameters")] public int Period { get; set; } [NinjaScriptProperty] [Range(1, double.MaxValue)] [Display(Name="Multi", Description="ATR multiplication", Order=2, GroupName="Parameters")] public double Multi { get; set; } [Browsable(false)] [XmlIgnore] public Series<double> TrailingStop { get { return Values[0]; } } #endregion } }
Comment