Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Orders not setting and filling on the right bar

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Orders not setting and filling on the right bar

    Hi, I've been working on a strategy that I am trying to backtest with tick replay. My orders are not being executed properly. I'm kind of a beginner so I don't know if its my code or I am running TickReplay incorrectly. Probably both. It should be pretty simple, I want to calculate the first 10s place above and below the vwap at any given time and if a 5 minute candle opens above the upper 10s place, place a short limit order on that 10s place and if a 5 minute candle opens below the lower 10s place then place a long limit order on that 10s place. Other conditions are that I want it to run only between 9:30 am and 3:40 and if price for the day has touched the vwap and a trade has been taken don't place any more trades for the day.

    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.Gui.SuperDom;
    using NinjaTrader.Gui.Tools;
    using NinjaTrader.Data;
    using NinjaTrader.NinjaScript;
    using NinjaTrader.Core.FloatingPoint;
    using NinjaTrader.NinjaScript.Indicators;
    using NinjaTrader.NinjaScript.DrawingTools;
    #endregion

    //This namespace holds Strategies in this folder and is required. Do not change it.
    namespace NinjaTrader.NinjaScript.Strategies
    {
    public class TensThroughVWAP : Strategy
    {
    private OrderFlowVWAP vwap;
    private Order shortLimitOrder;
    private Order longLimitOrder;
    private bool vwapTouchedToday;
    private bool tradeCompletedToday;
    private bool isFirstTickProcessed = false; // Flag to control execution on the first tick of the bar

    private double upperTensPlace; // Class level variable
    private double lowerTensPlace; // Class level variable

    private bool ordersCanceledPost340 = false; // Flag to control cancellation post 3:40 PM


    protected override void OnStateChange()
    {
    if (State == State.SetDefaults)
    {
    Description = @"Cross of the first 10s place above or below the VWAP";
    Name = "TensThroughVWAP";
    Calculate = Calculate.OnEachTick;
    EntriesPerDirection = 1;
    EntryHandling = EntryHandling.AllEntries;
    IsExitOnSessionCloseStrategy = true;
    ExitOnSessionCloseSeconds = 30;
    IsFillLimitOnTouch = false;
    MaximumBarsLookBack = MaximumBarsLookBack.TwoHundredFiftySix;
    OrderFillResolution = OrderFillResolution.Standard;
    Slippage = 0;
    StartBehavior = StartBehavior.WaitUntilFlat;
    TimeInForce = TimeInForce.Gtc;
    TraceOrders = false;
    RealtimeErrorHandling = RealtimeErrorHandling.StopCancelClose;
    StopTargetHandling = StopTargetHandling.PerEntryExecution;
    BarsRequiredToTrade = 20;
    // Disable this property for performance gains in Strategy Analyzer optimizations
    // See the Help Guide for additional information
    IsInstantiatedOnEachOptimizationIteration = true;

    Print("Strategy is being set to default settings.");

    }
    else if (State == State.Configure)
    {
    // Adding the tick series for "MES 06-24" with Tick Replay enabled
    AddDataSeries("MES 06-24", BarsPeriodType.Tick, 1, MarketDataType.Last);
    vwap = OrderFlowVWAP(VWAPResolution.Standard, TradingHours.Get("CME US Index Futures ETH"), VWAPStandardDeviations.One, 0, 0, 0);
    AddChartIndicator(vwap);
    Print("VWAP indicator has been configured.");
    }
    else if (State == State.Historical)
    {
    vwapTouchedToday = false;
    tradeCompletedToday = false;
    isFirstTickProcessed = false;
    Print("Resetting flags for the historical data processing.");
    }
    }

    protected override void OnBarUpdate()
    {
    // Reset flags at the start of each trading session
    if (Bars.IsFirstBarOfSession)
    {
    isFirstTickProcessed = false;
    ordersCanceledPost340 = false;
    vwapTouchedToday = false;
    tradeCompletedToday = false;
    Print($"{Time[0]} - Session start: Reset all flags.");
    }

    if (BarsInProgress == 0 && IsFirstTickOfBar)
    {
    isFirstTickProcessed = true;
    double vwapValue = vwap.VWAP[0];
    upperTensPlace = Math.Ceiling(vwapValue / 10) * 10;
    lowerTensPlace = Math.Floor(vwapValue / 10) * 10;
    Print($"{Time[0]} - New 5-min bar: Open={Open[0]}, VWAP={vwapValue}, UpperTP={upperTensPlace}, LowerTP={lowerTensPlace}, Orders: Short={shortLimitOrder}, Long={longLimitOrder}");

    if (!IsTradingHour() || (tradeCompletedToday && vwapTouchedToday))
    {
    Print($"{Time[0]} - Trading halted: Outside trading hours or conditions met.");
    return;
    }
    }

    if (BarsInProgress == 1)
    {
    ExecuteTradesOnTick();
    }
    }

    private void ExecuteTradesOnTick()
    {
    if (!IsTradingHour() || (tradeCompletedToday && vwapTouchedToday))
    return;

    // Check conditions for the new 5-minute bar, not for every tick unless it's the first tick of a new bar
    if (isFirstTickProcessed)
    {
    if (Open[0] > upperTensPlace && (shortLimitOrder == null || shortLimitOrder.LimitPrice != upperTensPlace))
    {
    CancelAndPlaceOrder(ref shortLimitOrder, upperTensPlace, "ShortVWAPEntry", MarketPosition.Short);
    }
    else if (Open[0] < lowerTensPlace && (longLimitOrder == null || longLimitOrder.LimitPrice != lowerTensPlace))
    {
    CancelAndPlaceOrder(ref longLimitOrder, lowerTensPlace, "LongVWAPEntry", MarketPosition.Long);
    }
    }
    }


    private void CancelAndPlaceOrder(ref Order order, double price, string signalName, MarketPosition position)
    {
    try
    {
    if (order != null && order.OrderState == OrderState.Working)
    {
    CancelOrder(order);
    }
    order = position == MarketPosition.Short ?
    EnterShortLimit(1, true, 1, price, signalName) :
    EnterLongLimit(1, true, 1, price, signalName);
    SetProfitTarget(signalName, CalculationMode.Ticks, ProfitTicks);
    SetStopLoss(signalName, CalculationMode.Ticks, StopLossTicks, false);
    Print($"Order placed at {price} for {signalName}.");
    }
    catch (Exception ex)
    {
    Print("Error in CancelAndPlaceOrder: " + ex.Message);
    }
    }


    private bool IsTradingHour()
    {
    int currentTime = ToTime(Time[0]);
    return currentTime >= 93000 && currentTime < 160000; // 9:30 AM to 3:40 PM
    }

    private void CancelAllOrders()
    {
    if (shortLimitOrder != null && shortLimitOrder.OrderState == OrderState.Working)
    {
    CancelOrder(shortLimitOrder);
    Print("Canceled short limit order.");
    }
    if (longLimitOrder != null && longLimitOrder.OrderState == OrderState.Working)
    {
    CancelOrder(longLimitOrder);
    Print("Canceled long limit order.");
    }
    }

    protected override void OnExecutionUpdate(Cbi.Execution execution, string executionId, double price, int quantity, Cbi.MarketPosition marketPosition, string orderId, DateTime time)
    {
    if (execution.Order != null && execution.Order.OrderState == OrderState.Filled)
    {
    Print($"Order filled. Price: {price}, Quantity: {quantity}, Position: {marketPosition}");
    if (Math.Abs(execution.Price - vwap.VWAP[0]) < TickSize)
    {
    vwapTouchedToday = true;
    Print("VWAP touched by execution.");
    }
    tradeCompletedToday = true;
    Print("Trade completed today, setting flag.");
    }
    }


    region
    [Range(1, 100)]
    [NinjaScriptProperty]
    public int ProfitTicks { get; set; } = 40;

    [Range(1, 100)]
    [NinjaScriptProperty]
    public int StopLossTicks { get; set; } = 40;
    #endregion
    }
    }
    ​​
    It is properly calculating the open price, vwap, and upper and lower 10s places but it will place limit orders when the price doesn't open above/below one of the 10s places. It also takes more than one trade a day even if my touchedvwap and tradecompletedtoday flags have been set to true. Sometimes it doesn't set the limite orders when a 5 minute candle has opened above/below the 10s places. Any help is appreciated, thanks.
    Last edited by JGriff5646; 05-20-2024, 07:57 PM. Reason: Fixed the code to my more recent version still with the same problems.

    #2
    Hi Brandon,

    Here are some example outputs

    4/29/2024 9:35:00 AM - New 5-min bar: Open=5147.25, VWAP=5142.15694349719, UpperTP=5150, LowerTP=5140, Orders: Short=, Long=
    Order placed at 5150 for ShortVWAPEntry.
    Order filled. Price: 5150, Quantity: 1, Position: Short
    Trade completed today, setting flag.
    4/29/2024 9:40:00 AM - New 5-min bar: Open=5153.75, VWAP=5143.55941966598, UpperTP=5150, LowerTP=5140, Orders: Short=orderId='NT-00000-392' account='Backtest' name='ShortVWAPEntry' orderState=Filled instrument='MES 06-24' orderAction=SellShort orderType='Limit' limitPrice=5150 stopPrice=0 quantity=1 tif=Gtc oco='' filled=1 averageFillPrice=5150 onBehalfOf='' id=-1 time='2024-04-29 09:31:17' gtd='2099-12-01' statementDate='2024-05-20', Long=

    It detects the open price at 5147.25 and the VWAP at 5142. It correctly creates the UpperTP at 5150 and the LowerTP at 5140. However it places a short order at 5150 even though the bar opened at 5147.25 which is below 5150. It should set that order at the next 5 minute candle which opens at 5153.75 which is above the UpperTP of 5150. I believe I have the code set for the primary data series to run onBarUpdate just on the 5 minute because all I need is the open price of that candle. Then the 1 data series handles the orders.

    Here is another one:

    4/30/2024 11:50:00 AM - New 5-min bar: Open=5107, VWAP=5129.95424097709, UpperTP=5130, LowerTP=5120, Orders: Short=orderId='NT-00009-392' account='Backtest' name='ShortVWAPEntry' orderState=Filled instrument='MES 06-24' orderAction=SellShort orderType='Limit' limitPrice=5140 stopPrice=0 quantity=1 tif=Gtc oco='' filled=1 averageFillPrice=5140 onBehalfOf='' id=-1 time='2024-04-30 09:44:20' gtd='2099-12-01' statementDate='2024-05-20', Long=orderId='NT-00006-392' account='Backtest' name='LongVWAPEntry' orderState=Filled instrument='MES 06-24' orderAction=Buy orderType='Limit' limitPrice=5130 stopPrice=0 quantity=1 tif=Gtc oco='' filled=1 averageFillPrice=5130 onBehalfOf='' id=-1 time='2024-04-30 09:30:00' gtd='2099-12-01' statementDate='2024-05-20'
    Order placed at 5120 for LongVWAPEntry.
    Order filled. Price: 5107, Quantity: 1, Position: Long

    In this one, the VWAP is 5129.95 and the LowerTP is 5120. The order is placed at 5120 but why is it filled at 5107. The high of this candle was 109.50​

    Comment


      #3
      Hello JGriff5646,

      I see you are calling a short entry and long entry at the same time.

      EnterShortLimit(1, true, 1, price, signalName) :
      EnterLongLimit(1, true, 1, price, signalName);​

      Unfortunately, this will not be possible using the managed approach as this would violate the internal order handling rules.

      From the help guide:
      "Methods that generate orders to enter a position will be ignored if:
      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"
      Help guide: NinjaScript > Language Reference > Strategy > Order Methods > Managed Approach​ > Internal Order Handling Rules that Reduce Unwanted Positions

      It would be necessary to use the unmanaged approach to send these orders at the same time.



      Regarding the order that are submitted unexpectedly, your print does not appear to match the condition that submits the order.
      if (isFirstTickProcessed)
      {
      if (Open[0] > upperTensPlace && (shortLimitOrder == null || shortLimitOrder.LimitPrice != upperTensPlace))​
      {
      CancelAndPlaceOrder(ref shortLimitOrder, upperTensPlace, "ShortVWAPEntry", MarketPosition.Short);

      The print should print the time of the the bar and the exact values being compared in the condition.
      This print should be placed one line above the conditions that lead to the entry to show the values at the time of the entry submission, not from OnExecutionUpdate() at the time the order filled, which is later.

      Print(string.Format("{0} | isFirstTickProcessed: {1}, Open[0]: {2} > upperTensPlace: {3} && (shortLimitOrder: {4} == null || shortLimitOrder.LimitPrice: {5} != upperTensPlace: {3}", Time[0], isFirstTickProcessed, Open[0], upperTensPlace, (shortLimitOrder == null ? "null" : "not null"), (shortLimitOrder != null ? shortLimitOrder.LimitPrice : 0)));
      Chelsea B.NinjaTrader Customer Service

      Comment

      Latest Posts

      Collapse

      Topics Statistics Last Post
      Started by Chuso, 01-14-2025, 03:41 AM
      4 responses
      22 views
      0 likes
      Last Post Chuso
      by Chuso
       
      Started by steinberg123, 01-09-2025, 05:48 AM
      3 responses
      39 views
      0 likes
      Last Post steinberg123  
      Started by Mindset, 01-14-2025, 05:33 AM
      2 responses
      12 views
      0 likes
      Last Post Mindset
      by Mindset
       
      Started by steinberg123, Today, 02:43 AM
      0 responses
      6 views
      0 likes
      Last Post steinberg123  
      Started by r68cervera, Today, 02:22 AM
      0 responses
      7 views
      0 likes
      Last Post r68cervera  
      Working...
      X