[POST] SuperFlattenSafetyNet

Strategy acting as protection Against Rejected OCO/Bracket Orders in Ninjatrader
 avatar
TrendIsYourFriend
markdown
4 months ago
8.1 kB
57
No Index

[Release] SuperFlattenSafetyNet – Protection Against Rejected OCO/Bracket Orders

Introduction

We have all experienced the "nightmare scenario" during high-volatility events (FOMC, CPI, etc.): you enter a trade, but your Stop Loss or Profit Target is rejected by the broker because the price moved too fast or "gapped" your trigger. You are left with a "naked" position that NinjaTrader might not even realize is still open—the dreaded Ghost Position.

I am sharing the SuperFlattenSafetyNet strategy. This is not a trading strategy; it is a background risk-management utility designed to act as a fail-safe. It bridges the gap between Managed strategies and Manual (Chart Trader) trades by monitoring the Account level directly.


How It Works

The script operates on three layers of defense to ensure you aren't "annihilated" by an unprotected trade:

  1. Account-Level Event Hook: Unlike standard strategies that only see their own orders, this script hooks into the Account.OrderUpdate event. It monitors every order on the instrument, whether placed by a strategy, an ATM, or manually via Chart Trader.
  2. Order-Type Intelligence: Instead of relying on order names, it monitors OrderType. If a StopMarket, StopLimit, Limit, or MIT order is rejected, the emergency sequence triggers.
  3. Persistent Flattening (The Retry Loop): In fast markets, a single "Close" command might be rejected. This script enters an "Emergency Mode" that continuously attempts to Flatten the instrument until the Account.Positions collection confirms the position is officially Flat.

Key Features

  • IsAdoptAccountPositionAware: Allows the strategy to "adopt" and protect manual trades.
  • RealtimeErrorHandling.StopCancelCloseIgnoreRejects: Overrides NinjaTrader's default behavior of shutting down the strategy when an error occurs, keeping the safety logic alive.
  • Asynchronous Detection: Catches rejections the millisecond they happen via the Account event handler.

Critical Limitations & Risks

  • Platform Connection: If your internet disconnects or NinjaTrader crashes, the script cannot run.
  • The "Last-Mile" Rejection: If the broker rejects the Flatten command itself (e.g., margin violation), the script will keep trying, but cannot override broker-side restrictions.
  • Slippage: This script sends Market Orders to ensure an exit. In extreme volatility, slippage is expected, but it is usually preferable to an unmanaged "runaway" loss.
  • One Chart per Instrument: Apply this to one chart for each instrument you trade (e.g., one for NQ, one for ES).

Installation & Setup Guide

1. Importing the Script

  1. Open NinjaTrader 8.
  2. Go to Control CenterToolsEditor.
  3. Right-click on StrategiesNew Strategy. Name it SuperFlattenSafetyNet.
  4. Delete the default code and paste the provided script below.
  5. Press F5 to compile.

2. Applying to a Chart

  1. Open a chart for your instrument (e.g., NQ).
  2. Right-click → Strategies → Select SuperFlattenSafetyNet.
  3. Settings:
    • Calculate: On each tick (Required).
    • Strategy Tag: Name it (e.g., "NQ_Safety").
    • Enabled: Check this box.
  4. Click OK.

The 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.Gui.SuperDom; using NinjaTrader.Data; using NinjaTrader.NinjaScript; using NinjaTrader.Core.FloatingPoint; using NinjaTrader.NinjaScript.Indicators; using NinjaTrader.NinjaScript.DrawingTools; #endregion namespace NinjaTrader.NinjaScript.Strategies { /// <summary> /// SuperFlattenSafetyNet: A fail-safe utility designed to prevent "Naked" positions. /// It monitors the Account-level OrderUpdate event for any rejected protection orders /// (Stops/Targets) and forces a Market Flatten for the specific instrument. /// </summary> public class SuperFlattenSafetyNet : Strategy { private Account myAccount = null; private string myInstrument = String.Empty; private bool emergencyModeActive = false; [NinjaScriptProperty] [Display(Name = "Strategy Tag", Description = "Label for identification in the Control Center.", Order = 0)] public string tag { get; set; } protected override void OnStateChange() { if (State == State.SetDefaults) { Description = "Fail-safe: Flattens instrument if OCO/Bracket orders are rejected."; Name = "SuperFlattenSafetyNet"; Calculate = Calculate.OnEachTick; // CRITICAL: Prevent the strategy from disabling itself if an error occurs. RealtimeErrorHandling = RealtimeErrorHandling.StopCancelCloseIgnoreRejects; // Allow the strategy to see positions opened manually or by other scripts. IsAdoptAccountPositionAware = true; tag = "Safety_Module_V1"; } else if (State == State.Transition) { emergencyModeActive = false; myInstrument = Instrument.FullName; lock (Account.All) { myAccount = Account.All.FirstOrDefault(a => a.Name == Account.Name); } if (myAccount != null) myAccount.OrderUpdate += OnOrderUpdate; else SetState(State.Terminated); } else if (State == State.Terminated) { if (myAccount != null) myAccount.OrderUpdate -= OnOrderUpdate; } } protected override void OnBarUpdate() { if (State != State.Realtime) return; // PERSISTENT FLATTEN LOGIC: if (emergencyModeActive) { Position accPosition = myAccount.Positions.FirstOrDefault(p => p.Instrument.FullName == myInstrument); if (accPosition != null && accPosition.MarketPosition != MarketPosition.Flat) { Print(Time[0] + " | [" + tag + "] EMERGENCY: Rejection detected. Attempting Flatten for " + myInstrument); myAccount.Flatten(new[] { Instrument.GetInstrument(myInstrument) }); } else { Print(Time[0] + " | [" + tag + "] SUCCESS: Instrument is now Flat."); emergencyModeActive = false; } } } private void OnOrderUpdate(object sender, OrderEventArgs e) { if (e.OrderState == OrderState.Rejected && e.Order.Instrument.FullName == myInstrument) { // Monitor Stop, Limit, and MIT types bool isProtectionOrder = e.Order.OrderType == OrderType.StopMarket || e.Order.OrderType == OrderType.StopLimit || e.Order.OrderType == OrderType.Limit || e.Order.OrderType == OrderType.MIT; if (isProtectionOrder) { Print(Time[0] + " | [" + tag + "] ALERT: " + e.Order.Name + " REJECTED! Reason: " + e.NativeError); emergencyModeActive = true; } } } } }