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