I’ve been having issues with NinjaTrader filling a Stop order. For reference, I have included scree shots.
Red: Original Stop Loss
Greens: Each Profit Target
Yellow: Modified Stop, Break Even (when Profit Target 1 hits)
Black: Reduced Profit (When Profit Target 2 hits).
In live mode, the above works perfectly. Each stop is modified and filled without a problem. However, when backtesting, it will not move the stop. I have looked everywhere for an error, but the code is fine. So, this makes testing and optimizing impossible as I cannot trust the results. I also cannot see anything on TraceOrders and it is set to true.
The important code is below:
private void SetStopProfit(double entryPrice)
{
double _stop = 0; ;
if (_currentPosition == CurrentPos.Long)
{
_stop = RoundToTickSize(entryPrice - _atr[0] * StopLossMultipler);
_profit = RoundToTickSize(entryPrice + (_atr[0] * ProfitTargetOne));
_profit2 = RoundToTickSize(entryPrice + (_atr[0] * ProfitTargetTwo));
_profit3 = RoundToTickSize(entryPrice + (_atr[0] * ProfitTargetThree));
if (UseMultipleContracts)
{
_profitOrder1 = ExitLongLimit(0, true, (int)((double)ContractsShares * (double)(TP1Percentage / 100.0)), _profit, ProfitLong1, LongOrder);
_profitOrder2 = ExitLongLimit(0, true, (int)((double)ContractsShares * (double)(TP2Percentage / 100.0)), _profit2, ProfitLong2, LongOrder);
_profitOrder3 = ExitLongLimit(0, true, (int)((double)ContractsShares * (double)(TP3Percentage / 100.0)), _profit3, ProfitLong3, LongOrder);
_stopOrder = ExitLongStopMarket(0, true, ContractsShares, _stop, StopLong, LongOrder);
}
else
{
_profitOrder1 = ExitLongLimit(0, true, ContractsShares, _profit, ProfitLong1, LongOrder);
_stopOrder = ExitLongStopMarket(0, true, ContractsShares, _stop, StopLong, LongOrder);
}
}
else if (_currentPosition == CurrentPos.Short)
{
_stop = RoundToTickSize((entryPrice + _atr[0] * StopLossMultipler));
_profit = RoundToTickSize(entryPrice - (_atr[0] * ProfitTargetOne));
_profit2 = RoundToTickSize(entryPrice - (_atr[0] * ProfitTargetTwo));
_profit3 = RoundToTickSize(entryPrice - (_atr[0] * ProfitTargetThree));
if (UseMultipleContracts)
{
_profitOrder1 = ExitShortLimit(0, true, (int)((double)ContractsShares * (double)(TP1Percentage / 100.0)), _profit, ProfitShort1, ShortOrder);
_profitOrder2 = ExitShortLimit(0, true, (int)((double)ContractsShares * (double)(TP2Percentage / 100.0)), _profit2, ProfitShort2, ShortOrder);
_profitOrder3 = ExitShortLimit(0, true, (int)((double)ContractsShares * (double)(TP3Percentage / 100.0)), _profit3, ProfitShort3, ShortOrder);
_stopOrder = ExitShortStopMarket(0, true, ContractsShares, _stop, StopShort, ShortOrder);
}
else
{
_profitOrder1 = ExitShortLimit(0, true, ContractsShares, _profit, ProfitShort1, ShortOrder);
_stopOrder = ExitShortStopMarket(0, true, ContractsShares, _stop, StopShort, ShortOrder);
}
}
if (UseMultipleContracts)
{
Draw.Line(this, CurrentBar + "Profit 3", true, 1, _profit3, 0, _profit3, Brushes.Green, DashStyleHelper.Solid, 2);
Draw.Line(this, CurrentBar + "Profit 2", true, 1, _profit2, 0, _profit2, Brushes.Green, DashStyleHelper.Solid, 2);
}
Draw.Line(this, CurrentBar + "Profit 1", true, 1, _profit, 0, _profit, Brushes.Green, DashStyleHelper.Solid, 2);
Draw.Line(this, CurrentBar + "Stop", true, 1, _stop, 0, _stop, Brushes.Red, DashStyleHelper.Solid, 2);
}
private void BreakEven(Execution execution)
{
CancelOrder(_stopOrder);
int sharesToClose = 0;
if (execution.Order.Name == ProfitLong1)
{
sharesToClose = (int)((double)ContractsShares * (double)(TP2Percentage / 100.0)) + (int)((double)ContractsShares * (double)(TP3Percentage / 100.0));
_stopOrder = ExitLongStopMarket(0, true, sharesToClose, RoundToTickSize(Position.AveragePrice), BreakEvenLong, LongOrder);
Print("Break Even Long1 Set! " + sharesToClose);
}
if (execution.Order.Name == ProfitShort1)
{
sharesToClose = (int)((double)ContractsShares * (double)(TP2Percentage / 100.0)) + (int)((double)ContractsShares * (double)(TP3Percentage / 100.0));
_stopOrder = ExitShortStopMarket(0, true, sharesToClose, RoundToTickSize(Position.AveragePrice), BreakEvenShort, ShortOrder);
Print("Break Even Short1 Set! " + sharesToClose);
}
Draw.Line(this, CurrentBar + "BE 2", true, 1, RoundToTickSize(Position.AveragePrice), 0, Position.AveragePrice, Brushes.Yellow, DashStyleHelper.Solid, 2);
Draw.Text(this, CurrentBar + "Text", sharesToClose.ToString(), 0, RoundToTickSize(Position.AveragePrice), Brushes.Black);
}
private void MoveBEtoTP1(Execution execution)
{
double newStop = 0;
int sharesToClose = 0;
CancelOrder(_stopOrder);
if (execution.Order.Name == ProfitLong2)
{
newStop = _profit;
sharesToClose = (int)((double)ContractsShares * (double)(TP3Percentage / 100.0));
_stopOrder = ExitLongStopMarket(0, true, sharesToClose, newStop, ReducedProfitLong, LongOrder);
Print("Half Profit Long Set!");
}
if (execution.Order.Name == ProfitShort2)
{
newStop = _profit;
sharesToClose = (int)((double)ContractsShares * (double)(TP3Percentage / 100.0));
_stopOrder = ExitShortStopMarket(0, true, sharesToClose, newStop, ReducedProfitShort, ShortOrder);
Print("Half Profit Short Set!");
}
Draw.Line(this, CurrentBar + "Half Profit", true, 1, newStop, 0, newStop, Brushes.Black, DashStyleHelper.Solid, 2);
Draw.Text(this, CurrentBar + "Text", sharesToClose.ToString(), 0, RoundToTickSize(Position.AveragePrice), Brushes.Black);
}
private void DefineExit()
{
if (ExitType == MyExitType.StopProfit)
{
}
if (ExitType == MyExitType.Trail)
{
ResetTrail();
}
if (ExitType == MyExitType.StopReverse)
{
if (Position.MarketPosition == MarketPosition.Long && _enterShort)
{
ExitLong("Time Long");
}
if (Position.MarketPosition == MarketPosition.Short && _enterLong)
{
ExitShort("Time Short");
}
}
}
private void DefineEntry()
{
try
{
//These will hold custom conditions that need to be fulfilled
bool BullCondition = false;
bool BearCondition = false; ;
//Create buy and sell conditions that are options set by the user
var buyConditions = new List<Func<bool>>();
var sellConditions = new List<Func<bool>>();
//Market Hours
buyConditions.Add(() => CheckTime());
sellConditions.Add(() => CheckTime());
buyConditions.Add(() => GreenBar());
sellConditions.Add(() => RedBar());
if (BollingerCrossUpper())
{
BullCondition = true;
BearCondition = false;
}
if (BollingerCrossLower())
{
BullCondition = false;
BearCondition = true;
}
_enterLong = buyConditions.All(x => x()) && BullCondition;
_enterShort = sellConditions.All(x => x()) && BearCondition;
}
catch (Exception ex)
{
Print(ex.Message);
}
}
private void EnterMarket()
{
if (Position.MarketPosition == MarketPosition.Flat)
{
_breakEvenSet = false;
if (_enterLong)
EnterLong(ContractsShares, LongOrder);
else if (_enterShort)
EnterShort(ContractsShares, ShortOrder);
}
else if (Position.MarketPosition != MarketPosition.Flat)
{
//BreakEven();
}
}
#endregion
#region Handle Orders
private bool IsEntryOrderFilled(Execution exec)
{
return exec.Order.OrderState == OrderState.Filled && IsEntryOrder(exec.Order.Name);
}
private bool IsEntryOrder(string name)
{
return name == LongOrder || name == ShortOrder;
}
private void IdentifyDirection(Execution execution)
{
if (execution.Order.Name == LongOrder)
_currentPosition = CurrentPos.Long;
if (execution.Order.Name == ShortOrder)
_currentPosition = CurrentPos.Short;
}
/// <summary>
/// Check time to ensure it is trading during the startegy's trading hours
/// </summary>
/// <returns>true/false</returns>
private bool CheckTime()
{
if (UseTimeFilter == false)
return true;
else
{
//Uses Computer's Local Time
if ((ToTime(Time[0]) >= 94500 && ToTime(Time[0]) <= 154500))
{
return true;
}
else
return false;
}
}
private bool IsProfitTargetOneFilled(Execution execution)
{
return execution.Order.OrderState == OrderState.Filled && IsProTargetOneOrder(execution.Order.Name);
}
private bool IsProfitTargetTwoFilled(Execution execution)
{
return execution.Order.OrderState == OrderState.Filled && IsProTargetTwoOrder(execution.Order.Name);
}
private bool IsProTargetOneOrder(string orderName)
{
return orderName == ProfitLong1 || orderName == ProfitShort1;
}
private bool IsProTargetTwoOrder(string orderName)
{
return orderName == ProfitLong2 || orderName == ProfitShort2;
}
protected override void OnBarUpdate()
{
if (CurrentBar < 2)
return;
DefineEntry();
if (Position.MarketPosition == MarketPosition.Flat)
EnterMarket();
if (Position.MarketPosition != MarketPosition.Flat)
{
DefineExit();
}
}
protected override void OnExecutionUpdate(Execution execution, string executionId, double price, int quantity, MarketPosition marketPosition,
string orderId, DateTime time)
{
if (IsEntryOrderFilled(execution))
{
profitOneHa**** = false;
IdentifyDirection(execution);
if (ExitType == MyExitType.StopProfit)
{
SetStopProfit(execution.Order.AverageFillPrice);
}
if (ExitType == MyExitType.PreviousSwing)
{
SetStopProfitSwing(execution.Order.AverageFillPric e);
}
if (ExitType == MyExitType.PreviousCandle)
{
SetStopProfitCandle(execution.Order.AverageFillPri ce);
}
if (ExitType == MyExitType.Trail)
{
InitializeTrail(execution.Order.AverageFillPrice);
}
}
if (IsProfitTargetOneFilled(execution))
{
BreakEven(execution);
}
if (IsProfitTargetTwoFilled(execution))
{
profitOneHa**** = true;
MoveBEtoTP1(execution);
}
}
protected override void OnOrderTrace(DateTime timestamp, string message)
{
//var messageLower = message.ToLower();
//var ignored = "ignored";
//if (messageLower.Contains(ignored))
PrintToSecondaryOutput(String.Format("{0} {1}", message, timestamp));
}
#endregion
#region Helpers
private double RoundToTickSize(double value)
{
return Instrument.MasterInstrument.RoundToTickSize(value) ;
}
private void PrintToSecondaryOutput(string info)
{
Output.Process(info, PrintTo.OutputTab2);
}
#endregion