Code:
region Using declarations
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.NinjaScript;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript.Strategies;
#endregion
namespace NinjaTrader.NinjaScript.Strategies
{
public class BasicShortTrailingStop : Strategy
{
region User Defined Variables
[NinjaScriptProperty]
[Range(1, int.MaxValue)]
[Display(Name = "Trailing Bars Back", Order = 1, GroupName = "Parameters")]
public int TrailingBarsBack { get; set; }
[NinjaScriptProperty]
[Range(1, int.MaxValue)]
[Display(Name = "Initial Stop Ticks", Order = 2, GroupName = "Parameters")]
public int InitialStopTicks { get; set; }
#endregion
private Order stopOrder = null;
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
Name = "BasicShortTrailingStop";
Calculate = Calculate.OnBarClose;
EntriesPerDirection = 1;
EntryHandling = EntryHandling.AllEntries;
IsExitOnSessionCloseStrategy = true;
BarsRequiredToTrade = 20;
TrailingBarsBack = 1;
InitialStopTicks = 20;
Description = "Enters a short trade on a down bar close and applies a trailing stop.";
}
}
protected override void OnBarUpdate()
{
if (CurrentBar < TrailingBarsBack + 2)
return;
if (Position.MarketPosition == MarketPosition.Flat)
{
if (Close[0] < Open[0])
{
EnterShort("ShortEntry");
Print($"DEBUG: Entering short trade at {Close[0]} on bar {CurrentBar}");
}
}
else if (Position.MarketPosition == MarketPosition.Short)
{
if (stopOrder == null || stopOrder.OrderState == OrderState.Cancelled || stopOrder.OrderState == OrderState.Rejected)
{
double initialStopPrice = Position.AveragePrice + (InitialStopTicks * TickSize);
ExitShortStopMarket(Position.Quantity, initialStopPrice, "StopLoss", "ShortEntry");
Print($"DEBUG: Placed initial stop loss at {initialStopPrice}");
}
else
{
if (Close[TrailingBarsBack] < Open[TrailingBarsBack])
{
double newStopPrice = High[TrailingBarsBack] + TickSize;
if (stopOrder.OrderState == OrderState.Working && newStopPrice < stopOrder.StopPrice)
{
ChangeOrder(stopOrder, stopOrder.Quantity, newStopPrice, 0);
Print($"DEBUG: Updated trailing stop to {newStopPrice} on bar {CurrentBar}");
}
}
}
}
}
protected override void OnExecutionUpdate(Execution execution, string executionId, double price, int quantity,
MarketPosition marketPosition, string orderId, DateTime time)
{
if (execution.Order.Name == "ShortEntry" && execution.Order.OrderState == OrderState.Filled)
{
Print($"DEBUG: Short entry filled at {price} on bar {CurrentBar}");
}
if (stopOrder != null && execution.Order == stopOrder && execution.Order.OrderState == OrderState.Filled)
{
stopOrder = null;
Print($"DEBUG: Stop loss hit at {price} on bar {CurrentBar}");
}
}
protected override void OnOrderUpdate(Order order, double limitPrice, double stopPrice, int quantity,
int filled, double averageFillPrice, OrderState orderState, string orderId, DateTime time)
{
if (order.Name == "StopLoss")
{
stopOrder = order;
}
}
}
}
Comment