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