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
namespace NinjaTrader.NinjaScript.Strategies
{
public class MyCustomStrategy : Strategy
{
private OrderFlowCumulativeDelta cumulativeDelta;
[NinjaScriptProperty]
public int MinTickMove { get; set; } = 4;
[NinjaScriptProperty]
public int MinIcebergVolume { get; set; } = 1000;
// Dizionario per tenere traccia degli ordini aperti
private Dictionary<string, Order> activeOrders = new Dictionary<string, Order>();
// Variabile per tenere traccia dell'indice della barra corrente
private int currentBarIndex = -1;
// Variabili di stato per evitare aperture multiple sulla stessa candela
private bool deltaLongOpenedThisBar = false;
private bool deltaShortOpenedThisBar = false;
private bool icebergLongOpenedThisBar = false;
private bool icebergShortOpenedThisBar = false;
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
Description = "Strategia Delta/Iceberg con gestione diretta degli ordini";
Name = "MyCustomStrategy";
EntriesPerDirection = 100; // Aumenta il numero massimo di posizioni
EntryHandling = EntryHandling.AllEntries; // Accetta tutti gli ordini
ExitOnSessionCloseSeconds = 30;
IsExitOnSessionCloseStrategy = true;
IsUnmanaged = true; // Modalità Unmanaged per gestione manuale
TraceOrders = true; // Abilita TraceOrders
}
else if (State == State.Configure)
{
AddDataSeries(Data.BarsPeriodType.Tick, 1);
}
else if (State == State.DataLoaded)
{
cumulativeDelta = OrderFlowCumulativeDelta(CumulativeDeltaType.BidAs k, CumulativeDeltaPeriod.Bar, 0);
}
}
protected override void OnBarUpdate()
{
// Controlla se è una nuova barra
if (currentBarIndex != CurrentBar)
{
// Resetta le variabili di stato all'inizio di ogni nuova candela
deltaLongOpenedThisBar = false;
deltaShortOpenedThisBar = false;
icebergLongOpenedThisBar = false;
icebergShortOpenedThisBar = false;
// Aggiorna l'indice della barra corrente
currentBarIndex = CurrentBar;
// Stampa informazioni sulla nuova barra
Print($"Nuova barra: {Time[0]}");
}
if (State != State.Realtime || CurrentBar < BarsRequiredToTrade || cumulativeDelta?.DeltaClose == null)
return;
try
{
// --- Condizioni Delta ---
if (activeOrders.Count < EntriesPerDirection)
{
// Delta Long: Candela del prezzo verde e venditori maggiori dei compratori
Print(Time[0] + " | DELTA LONG: " +
"deltaLongOpenedThisBar: " + deltaLongOpenedThisBar + " = false & " +
"Close[0]: " + Close[0] + " > Open[0]: " + Open[0] + " & " +
"cumulativeDelta.DeltaClose[0]: " + cumulativeDelta.DeltaClose[0] + " < 0 & " +
"Close[0] - Open[0]: " + (Close[0] - Open[0]) + " >= MinTickMove * TickSize: " + (MinTickMove * TickSize));
if (!deltaLongOpenedThisBar && Close[0] > Open[0] && cumulativeDelta.DeltaClose[0] < 0 && (Close[0] - Open[0]) >= MinTickMove * TickSize)
{
ExecuteTrade("DELTA_LONG", OrderAction.Buy);
deltaLongOpenedThisBar = true;
}
// Delta Short: Candela del prezzo rossa e venditori minori dei compratori
Print(Time[0] + " | DELTA SHORT: " +
"deltaShortOpenedThisBar: " + deltaShortOpenedThisBar + " = false & " +
"Close[0]: " + Close[0] + " < Open[0]: " + Open[0] + " & " +
"cumulativeDelta.DeltaClose[0]: " + cumulativeDelta.DeltaClose[0] + " > 0 & " +
"Open[0] - Close[0]: " + (Open[0] - Close[0]) + " >= MinTickMove * TickSize: " + (MinTickMove * TickSize));
if (!deltaShortOpenedThisBar && Close[0] < Open[0] && cumulativeDelta.DeltaClose[0] > 0 && (Open[0] - Close[0]) >= MinTickMove * TickSize)
{
ExecuteTrade("DELTA_SHORT", OrderAction.SellShort);
deltaShortOpenedThisBar = true;
}
}
// --- Condizioni Iceberg ---
CheckIcebergConditions();
}
catch (Exception ex)
{
Print("Errore: " + ex.Message);
}
}
private void CheckIcebergConditions()
{
if (Position.MarketPosition == MarketPosition.Flat || activeOrders.Count < EntriesPerDirection)
{
// Iceberg Short: Delta positivo consecutivo
Print(Time[0] + " | ICEBERG SHORT: " +
"icebergShortOpenedThisBar: " + icebergShortOpenedThisBar + " = false & " +
"cumulativeDelta.DeltaClose[0]: " + cumulativeDelta.DeltaClose[0] + " > 0 & " +
"IsConsecutiveConditionMet(10, true): " + IsConsecutiveConditionMet(10, true));
if (!icebergShortOpenedThisBar && cumulativeDelta.DeltaClose[0] > 0 && IsConsecutiveConditionMet(10, true))
{
ExecuteTrade("ICEBERG_SHORT", OrderAction.SellShort);
icebergShortOpenedThisBar = true;
}
// Iceberg Long: Delta negativo consecutivo
Print(Time[0] + " | ICEBERG LONG: " +
"icebergLongOpenedThisBar: " + icebergLongOpenedThisBar + " = false & " +
"cumulativeDelta.DeltaClose[0]: " + cumulativeDelta.DeltaClose[0] + " < 0 & " +
"IsConsecutiveConditionMet(10, false): " + IsConsecutiveConditionMet(10, false));
if (!icebergLongOpenedThisBar && cumulativeDelta.DeltaClose[0] < 0 && IsConsecutiveConditionMet(10, false))
{
ExecuteTrade("ICEBERG_LONG", OrderAction.Buy);
icebergLongOpenedThisBar = true;
}
}
}
private void ExecuteTrade(string signalName, OrderAction action)
{
// Crea un nome univoco per l'ordine
string uniqueSignalName = $"{signalName}_{DateTime.Now:yyyyMMddHHmmssfff} ";
// Invia ordine di apertura
Order entryOrder = SubmitOrderUnmanaged(0, action, OrderType.Market, 1, 0, 0, "", uniqueSignalName);
// Imposta stop loss e take profit
if (entryOrder != null)
{
// Stop Loss: 40 tick
double stopLossPrice = action == OrderAction.Buy ?
entryOrder.AverageFillPrice - 40 * TickSize :
entryOrder.AverageFillPrice + 40 * TickSize;
SubmitOrderUnmanaged(0, action == OrderAction.Buy ? OrderAction.Sell : OrderAction.BuyToCover, OrderType.StopMarket, 1, 0, stopLossPrice, uniqueSignalName, $"{uniqueSignalName}_STOP");
// Take Profit: 40 tick
double takeProfitPrice = action == OrderAction.Buy ?
entryOrder.AverageFillPrice + 40 * TickSize :
entryOrder.AverageFillPrice - 40 * TickSize;
SubmitOrderUnmanaged(0, action == OrderAction.Buy ? OrderAction.Sell : OrderAction.BuyToCover, OrderType.Limit, 1, takeProfitPrice, 0, uniqueSignalName, $"{uniqueSignalName}_PROFIT");
// Aggiungi l'ordine al dizionario degli ordini attivi
activeOrders[uniqueSignalName] = entryOrder;
}
}
private bool IsConsecutiveConditionMet(int barsRequired, bool isBuyVolumeGreater)
{
for (int i = 0; i < barsRequired; i++)
{
if (i >= CurrentBar || i >= cumulativeDelta.DeltaClose.Count)
{
Print(Time[0] + " | IsConsecutiveConditionMet: Barra " + i + " non disponibile. Restituisco false.");
return false;
}
if (isBuyVolumeGreater && cumulativeDelta.DeltaClose[i] <= 0)
{
Print(Time[0] + " | IsConsecutiveConditionMet: Barra " + i + ", DeltaClose: " + cumulativeDelta.DeltaClose[i] + " <= 0. Restituisco false.");
return false;
}
if (!isBuyVolumeGreater && cumulativeDelta.DeltaClose[i] >= 0)
{
Print(Time[0] + " | IsConsecutiveConditionMet: Barra " + i + ", DeltaClose: " + cumulativeDelta.DeltaClose[i] + " >= 0. Restituisco false.");
return false;
}
}
Print(Time[0] + " | IsConsecutiveConditionMet: Condizione consecutiva soddisfatta per " + barsRequired + " barre. Restituisco true.");
return true;
}
protected override void OnExecutionUpdate(Execution execution, string executionId, double price, int quantity, MarketPosition marketPosition, string orderId, DateTime time)
{
// Gestione ordini riempiti
if (execution.Order != null && execution.Order.OrderState == OrderState.Filled)
{
Print($"Ordine eseguito: {execution.Order.Name} a {price}");
// Rimuovi l'ordine dal dizionario degli ordini attivi se è stato chiuso
if (activeOrders.ContainsKey(execution.Order.Name))
{
activeOrders.Remove(execution.Order.Name);
}
}
}
protected override void OnOrderUpdate(Order order, double limitPrice, double stopPrice, int quantity, int filled, double averageFillPrice, OrderState orderState, DateTime time, ErrorCode error, string comment)
{
// Gestione aggiornamenti dell'ordine
if (order.OrderState == OrderState.Rejected)
{
Print($"⚠️ Ordine {order.Name} RIFIUTATO: {order}");
// Rimuovi l'ordine dal dizionario degli ordini attivi se è stato rifiutato
if (activeOrders.ContainsKey(order.Name))
{
activeOrders.Remove(order.Name);
}
}
}
}
}
Comment