An Enter() method to submit an entry order has been ignored. Please search on the term 'Internal Order Handling Rules that Reduce Unwanted Positions' in the Help Guide for detailed explanation

Hello all, I am not familiar with ninjatrading or coding but I am straggling to let NT allow me to have pending buy/sell orders at the same time. I just need to have floating pending orders at the same time but the buy will go through and the sell will get rejected.

I have tried:

  • start behavior > immediately submit;
  • entries per direction > 2
  • stop and target submission > by strategy position;
  • tools > settings > automated trading interference > submit > submit as is;

I just want the strategy to have both orders at the same time, I don’t know why they make it so complicated. Can anyone please help me figure it out?

Code:

#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

namespace NinjaTrader.NinjaScript.Strategies
{
public class NewsStraddleStrategy : Strategy
{
private bool isLocked = false;
private Order entryOrderLong = null;
private Order entryOrderShort = null;

    protected override void OnStateChange()
    {
        if (State == State.SetDefaults)
        {
            Description = @"Strategy that places Stop orders that trail price and freeze before news.";
            Name = "NewsStraddleStrategy";
            Calculate = Calculate.OnEachTick;
            EntriesPerDirection = 1;
            EntryHandling = EntryHandling.AllEntries;
            IsExitOnSessionCloseStrategy = true;
            ExitOnSessionCloseSeconds = 30;

            // Defaults
            OffsetTicks = 40;
            // Set default time (Date is ignored by logic)
            NewsTime = DateTime.Now.Date.AddHours(8).AddMinutes(30); 
            SecondsBeforeLock = 3;
            Quantity = 1;
            
            // Profit Target defaults
            UseProfitTarget = false;
            ProfitTargetAmount = 100;
        }
    }

    protected override void OnBarUpdate()
    {
        if (CurrentBar < 1 || State != State.Realtime) return;

        // Check for Profit Target exit if enabled and we have a position
        if (UseProfitTarget && Position.MarketPosition != MarketPosition.Flat)
        {
            double unrealizedPnL = Position.GetUnrealizedProfitLoss(PerformanceUnit.Currency, Close[0]);
            
            if (unrealizedPnL >= ProfitTargetAmount)
            {
                if (Position.MarketPosition == MarketPosition.Long)
                {
                    ExitLong("ProfitTarget", "NewsBuy");
                    Print("Profit Target Hit! Exiting Long at $" + unrealizedPnL.ToString("F2") + " profit");
                }
                else if (Position.MarketPosition == MarketPosition.Short)
                {
                    ExitShort("ProfitTarget", "NewsSell");
                    Print("Profit Target Hit! Exiting Short at $" + unrealizedPnL.ToString("F2") + " profit");
                }
                return; // Exit the method after closing position
            }
        }

        // 1. Time Logic - FIXED TO USE CHART TIME
        DateTime chartTime = Time[0]; // Use the timestamp of the current bar
        DateTime targetNewsTime = new DateTime(chartTime.Year, chartTime.Month, chartTime.Day, NewsTime.Hour, NewsTime.Minute, NewsTime.Second);
        TimeSpan timeDiff = targetNewsTime - chartTime;

        // 2. Determine if we are in the "Floating" phase or "Locked" phase
        if (timeDiff.TotalSeconds > SecondsBeforeLock)
        {
            // --- FLOATING PHASE (Update Orders) ---
            isLocked = false;

            double newBuyPrice = Close[0] + (OffsetTicks * TickSize);
            double newSellPrice = Close[0] - (OffsetTicks * TickSize);

            // Manage Long Order
            if (entryOrderLong == null)
            {
                // Create initial order if it doesn't exist
                entryOrderLong = EnterLongStopMarket(0, true, Quantity, newBuyPrice, "NewsBuy");
                Print(chartTime + " - Creating Long Stop Order at: " + newBuyPrice);
            }
            else
            {
                // Update existing order to new price
                ChangeOrder(entryOrderLong, entryOrderLong.Quantity, 0, newBuyPrice);
            }

            // Manage Short Order
            if (entryOrderShort == null)
            {
                // Create initial order if it doesn't exist
                entryOrderShort = EnterShortStopMarket(0, true, Quantity, newSellPrice, "NewsSell");
                Print(chartTime + " - Creating Short Stop Order at: " + newSellPrice);
            }
            else
            {
                // Update existing order to new price
                ChangeOrder(entryOrderShort, entryOrderShort.Quantity, 0, newSellPrice);
            }
            
            // Optional: Draw lines just so you can see them clearly
            Draw.HorizontalLine(this, "BuyLine", newBuyPrice, Brushes.DodgerBlue);
            Draw.HorizontalLine(this, "SellLine", newSellPrice, Brushes.Red);
        }
        else
        {
            // --- LOCKED PHASE (Stop Updating) ---
            if (!isLocked)
            {
                isLocked = true;
                Print("NEWS LOCK: Orders frozen at " + chartTime.ToString());
                
                // We simply stop calling ChangeOrder. 
                // The orders remain active at the last calculated price.
            }
        }
    }

    protected override void OnOrderUpdate(Order order, double limitPrice, double stopPrice, int quantity, int filled, double averageFillPrice, OrderState orderState, DateTime time, ErrorCode error, string nativeError)
    {
        // Print debug info for order updates
        Print(string.Format("Order Update - Signal: {0}, State: {1}, Quantity: {2}", 
            order.Name, orderState, quantity));
        
        // Reset order objects if they are filled, cancelled, or rejected so we don't try to change them
        if (orderState == OrderState.Filled || orderState == OrderState.Cancelled || orderState == OrderState.Rejected)
        {
            if (entryOrderLong != null && entryOrderLong == order) 
            {
                Print("Long order " + orderState.ToString());
                entryOrderLong = null;
            }
            if (entryOrderShort != null && entryOrderShort == order) 
            {
                Print("Short order " + orderState.ToString());
                entryOrderShort = null;
            }
        }
    }

    #region Properties
    [NinjaScriptProperty]
    [Range(1, int.MaxValue)]
    [Display(Name="Offset Ticks", Order=1, GroupName="Parameters")]
    public int OffsetTicks { get; set; }

    [NinjaScriptProperty]
    [PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
    [Display(Name="News Time (HH:MM:SS)", Description="Set the time of the event.", Order=2, GroupName="Parameters")]
    public DateTime NewsTime { get; set; }

    [NinjaScriptProperty]
    [Range(1, 60)]
    [Display(Name="Seconds Before Lock", Order=3, GroupName="Parameters")]
    public int SecondsBeforeLock { get; set; }
    
    [NinjaScriptProperty]
    [Range(1, int.MaxValue)]
    [Display(Name="Quantity", Order=4, GroupName="Parameters")]
    public int Quantity { get; set; }
    
    [NinjaScriptProperty]
    [Display(Name="Use Profit Target", Description="Enable automatic profit target exit", Order=5, GroupName="Profit Target")]
    public bool UseProfitTarget { get; set; }
    
    [NinjaScriptProperty]
    [Range(1, double.MaxValue)]
    [Display(Name="Profit Target ($)", Description="Dollar amount of profit to exit at", Order=6, GroupName="Profit Target")]
    public double ProfitTargetAmount { get; set; }
    #endregion
}

}

Many thanks

I have not used OCO, but maybe that will help you.

1 Like

From the managed order docs:

Methods that generate orders to enter a position will be ignored if:

•A position is open and an order submitted by a non market order exit method (ExitLongLimit() for example) is active and the order is used to open a position in the opposite direction
•A position is open and an order submitted by a set method (SetStopLoss() for example) is active and the order is used to open a position in the opposite direction
•A position is open and two or more Entry methods to reverse the position are entered together. In this case the second Entry order will be ignored.
•The strategy position is flat and an order submitted by an enter method (EnterLongLimit() for example) is active and the order is used to open a position in the opposite direction
•The entry signal name is not unique

Sounds like you’re running into the 4th one when the position is flat.

You’ll probably need to take the unmanaged order approach rather than the managed one.

order methods
advanced order handling

2 Likes