API für Bot-Entwicklung

Nutze die Kaizen-Indikatoren aus deinen NinjaScript-Strategien über eine öffentliche API: Deine Strategie hostet den Indikator und liest seine Werte, ohne die DLL.

Aktualisiert: 10. September 2026

Die Kaizen-Indikatoren stellen eine öffentliche API für die Nutzung aus deinen eigenen NinjaScript-Strategien bereit. Du musst die DLL weder öffnen noch dekompilieren — deine Strategie hostet den Indikator und liest seine Daten direkt.

using NinjaTrader.NinjaScript.Indicators.Kaizen;

Fehlt dieses using, bekommst du den Fehler CS0246.

Sechs Regeln, die darüber entscheiden, ob es funktioniert

Verletzt du eine davon, liefert die API leere Daten — ohne Fehlermeldung. Genau diese Stille macht sie teuer: Die Strategie läuft, das Log bleibt sauber, und jeder Wert ist null.

  1. Immer die Helper-Methode, nie new. new KaizenFootprint() durchläuft NinjaTraders Cache- und Lifecycle-Verdrahtung nicht; der Indikator hängt dauerhaft in (Calculating…), und jeder Lesezugriff liefert 0 oder null. Nutze KaizenFootprint(...) mit allen Parametern. Es gibt keine parameterlosen Überladungen — die Helper-Methode nimmt jede Property entgegen, von 3 Parametern (SuperTrend) bis 37 (Footprint).

  2. Erzeuge ihn in State.DataLoaded, nicht in State.Configure. Ein AddChartIndicator(...) gehört, falls du es nutzt, ebenfalls dorthin.

  3. Rufe Update() bei Indikatoren ohne Plots auf. NinjaTrader treibt gehostete Indikatoren nur bei Bedarf an. Bei einem Indikator mit Plots löst schon der Zugriff auf Values[0][0] die Update-Kette aus; bei einem Indikator ohne Plots gibt es nichts abzugreifen, sein OnBarUpdate läuft dann nur, wenn Tick Replay ihn zufällig mit antreibt. 11 der 17 Indikatoren haben keine Plots — siehe Tabelle unten. Ohne Update() bekommt ihre Engine keine einzige Bar.

  4. Filtere gegen Lookahead, wenn du Zonen- oder Level-Listen liest. Diese Listen enthalten den aktuellen Zustand aller Zonen — auch solcher, die es an der ausgewerteten Bar noch gar nicht gab; und IsActive beschreibt heute, nicht jene Bar. Im Backtest wird daraus still ein Lookahead. Filtere über den Zeitstempel oder den Ursprungs-Bar-Index; beide Beispiele unten zeigen das Muster.

  5. Multi-Timeframe: Der Host muss die Serie vorladen. Setzt du useMTF: true, muss deine Strategie dieselbe Serie in ihrem State.Configure laden, z. B. AddDataSeries(BarsPeriodType.Minute, 30). Ein gehostetes NinjaScript darf keine eigenen Daten laden. Lässt du das weg, deaktiviert NinjaTrader die Strategie vor der ersten Bar — du bekommst 0 Trades, leere Ausgabedateien, und der Fehler steht ausschliesslich im NinjaTrader-Log, nie auf dem Bildschirm.

  6. Eine ungültige Lizenz liefert leere Daten, keinen Fehler. Schlägt die Lizenzprüfung fehl, geben alle APIs 0, null oder eine leere Liste zurück. Prüfe zuerst, ob der Indikator auf einem Chart funktioniert.

Beispiel: Supply-/Demand-Zonen kombiniert mit VWAP

Beide Beispiele setzen den Standard-using-Block voraus, den NinjaTrader beim Anlegen einer neuen Strategie einfügt (er enthält bereits System.Windows.Media für Brushes und NinjaTrader.Gui für DashStyleHelper) — dazu den oben gezeigten Kaizen-Namespace.

public class MeinSupplyDemandBot : Strategy
{
    private KaizenSupplyDemand _sd;
    private KaizenVWAP         _vwap;

    protected override void OnStateChange()
    {
        if (State == State.SetDefaults)
        {
            Name                = "MeinSupplyDemandBot";
            Calculate           = Calculate.OnBarClose;
            BarsRequiredToTrade = 25;
        }
        else if (State == State.DataLoaded)
        {
            _sd = KaizenSupplyDemand(
                false,                        // useMTF
                BarsPeriodType.Minute, 30,    // mtfBarType, mtfBarPeriod (ohne Wirkung bei useMTF = false)
                Brushes.DodgerBlue,           // demandColor
                Brushes.OrangeRed,            // supplyColor
                0.40f, 0.15f, 0.10f, 0.05f,   // Deckkraft: Linie/Flaeche aktiv, Linie/Flaeche gebrochen
                1,                            // zoneLineWidth
                false,                        // extendZones
                false, true,                  // hideActiveZones, hideBrokenZones
                200);                         // maxZoneCount

            _vwap = KaizenVWAP(
                KVWAPStyle.Directional,       // vWAPStyle
                1.28, 2.01, 2.51,             // Multiplikatoren Band 1 / 2 / 3
                5,                            // bandOpacity
                DashStyleHelper.Dash);        // bandLineStyle
        }
    }

    protected override void OnBarUpdate()
    {
        if (CurrentBar < 25) return;

        _sd.Update();                         // Pflicht: Supply/Demand hat keine Plots

        double vwap   = _vwap.Values[0][0];
        double lower1 = _vwap.Values[2][0];   // unteres Band bei 1,28 SD
        if (vwap <= 0) return;

        IReadOnlyList<KaizenSupplyDemandZoneInfo> zones = _sd.Zones;
        if (zones == null) return;

        for (int i = 0; i < zones.Count; i++)
        {
            KaizenSupplyDemandZoneInfo z = zones[i];

            // Anti-Lookahead: Die Zone muss an der ausgewerteten Bar bereits
            // existiert haben und darf dort noch nicht gebrochen gewesen sein
            if (z.Date > Time[0]) continue;
            if (!z.IsActive && z.DateInactive.HasValue && z.DateInactive.Value <= Time[0])
                continue;

            if (z.Type == KaizenSupplyDemandZoneType.Demand
                && Close[0] <= z.High && Close[0] >= z.Low
                && Close[0] < lower1)
            {
                EnterLong(1, "LongNachfrageUnterVWAP");
            }
        }
    }
}

Beispiel: Stacked-Imbalance-Zonen

Beachte die Parameterliste — die Helper-Methode hat keine Kurzform. Die Werte unten sind die Standardwerte des Indikators.

public class MeinStackedImbalanceBot : Strategy
{
    private KaizenStackedImbalance _si;

    protected override void OnStateChange()
    {
        if (State == State.SetDefaults)
        {
            Name                = "MeinStackedImbalanceBot";
            Calculate           = Calculate.OnBarClose;
            BarsRequiredToTrade = 20;
        }
        else if (State == State.DataLoaded)
        {
            _si = KaizenStackedImbalance(
                300,                          // imbalanceRatio (%)
                3,                            // minStackSize
                10,                           // volumeFilter
                false,                        // ignoreZeroValues
                true, 6, 2,                   // showTickMarks, tickMarkWidthPx, tickMarkThickness
                true, 20,                     // showZones, zoneOpacity
                KSIZoneEndCondition.Touch,    // zoneEndCondition
                true, 2, 10,                  // showAbsorption, absorptionDepth, absorptionMinVolume
                KBTMarkerShape.Diamond, 10,   // absorptionMarkerShape, absorptionMarkerSize
                500);                         // maxStoredBars
        }
    }

    protected override void OnBarUpdate()
    {
        if (_si == null || CurrentBar < 20) return;

        _si.Update();                         // Pflicht: keine Plots

        IReadOnlyList<KaizenStackedImbalance.ImbalanceZone> zones = _si.ActiveZones;
        if (zones == null) return;

        for (int i = 0; i < zones.Count; i++)
        {
            KaizenStackedImbalance.ImbalanceZone z = zones[i];

            // Anti-Lookahead
            if (z.OriginBarIndex > CurrentBar) continue;
            if (z.MitigationBarIndex >= 0 && z.MitigationBarIndex <= CurrentBar) continue;

            if (Close[0] >= z.PriceLow && Close[0] <= z.PriceHigh)
            {
                Print("Preis in " + (z.IsBullish ? "bullischer" : "baerischer") + " Zone "
                      + z.PriceLow + " - " + z.PriceHigh);
            }
        }
    }
}

Welcher Indikator braucht was

Update() ist immer dann Pflicht, wenn der Indikator keine Plots hat. Tick Replay muss für die Orderflow-Indikatoren auf dem Chart aktiviert sein.

IndikatorPlotsTick ReplayUpdate() nötigHelper-Parameter
KaizenBigTradesjaja15
KaizenCVD3janein9
KaizenClusterSearchjaja12
KaizenDeltaCandle2janein8
KaizenFootprintjaja37
KaizenNakedLevelsneinja11
KaizenOrderInfoneinja5
KaizenReversalIndicatorjaja25
KaizenSpeedOfTape2janein7
KaizenStackedImbalancejaja16
KaizenStatGrid2janein25
KaizenStatsProfileneinja18
KaizenSuperTrend2neinnein3
KaizenSupplyDemandneinja14
KaizenTPOneinja34
KaizenVWAP8neinnein6
KaizenVolumeProfilejaja23

KaizenAlertLine und KaizenDeltaProfile haben keine Bot-API. Sie stellen ausschliesslich Konfigurations-Properties bereit.

Verfügbare öffentliche APIs

IndikatorMemberLiefert
KaizenSupplyDemand.ZonesIReadOnlyList<KaizenSupplyDemandZoneInfo> — alle Zonen, aktive und gebrochene
.ActiveSupplyCount / .ActiveDemandCountint
KaizenVWAPValues[0][0]Values[7][0]VWAP, 3 Bandpaare, VWAP der Vorsession — siehe unten
.CurrentVWAP / .CurrentStdDev / .PriorSessionVWAPdouble — nur aktuelle Bar
KaizenStackedImbalance.ActiveZonesIReadOnlyList<ImbalanceZone>alle Zonen, aktive und mitigierte
.HistoricalZonesIReadOnlyList<ImbalanceZone> — nur mitigierte Zonen
.RecentAbsorptionsIReadOnlyList<KaizenAbsorptionInfo>
.LastImbalanceBarIndexint-1, wenn noch keine
KaizenFootprint.GetBarDelta(barIndex)long — vorzeichenbehaftetes Delta der Bar
.GetBarPOCPrice(barIndex)double
.GetBullishImbalancePrices(barIndex) / .GetBearishImbalancePrices(barIndex)List<double>
.GetBullishAbsorptionPrices(barIndex) / .GetBearishAbsorptionPrices(barIndex)List<double>
.GetFootprintForBar(barIndex)KaizenFootprintBarInfo — siehe Einschränkung unten
.RecentAbsorptionsIReadOnlyList<KaizenAbsorptionInfo>
.UnfinishedLevelsIReadOnlyList<KaizenFootprintUnfinishedLevelInfo>
KaizenVolumeProfile.CurrentPOC / .CurrentVAH / .CurrentVALdouble
.CurrentPriceVolumeSortedDictionary<double, long> — Preis → Volumen
.AllProfilesIReadOnlyList<KaizenVolumeProfileInfo>
.NakedLevelsReadOnlyCollection<KaizenVolumeProfileNakedLevelInfo>
KaizenTPO.SinglePrintsIReadOnlyList<KaizenSinglePrintInfo>
.AllProfilesIReadOnlyList<KaizenTpoProfileInfo>
.CurrentPOC / .CurrentVAH / .CurrentVALdouble
.CurrentIBHigh / .CurrentIBLowdouble — Initial Balance
KaizenCVD.GetCvd(barsAgo) / .GetCvdAt(barIndex)double — ebenso Open-/High-/Low-Varianten
.SessionCvddouble
.CvdCandleOpen / High / Low / Closedouble
KaizenDeltaCandle.GetDeltaClose(barsAgo) / .GetDeltaCloseAt(barIndex)double — ebenso Open-/High-/Low-Varianten
.CurrentBarDeltalong
.RecentAbsorptionsIReadOnlyList<KaizenAbsorptionInfo>
KaizenBigTrades.GetTradesForBar(barIndex)IReadOnlyList<KaizenBigTradeInfo>
KaizenClusterSearch.GetClustersForBar(barIndex)IReadOnlyList<KaizenClusterHitInfo>
KaizenNakedLevels.NakedLevelsIReadOnlyList<KaizenNakedLevelInfo>
.CurrentSessionHigh / Low, .CurrentDailyHigh / Low, .CurrentWeeklyHigh / Lowdouble
KaizenStatsProfile.GetTodayTouchProbability(levelKey)double?
.GetTodaySampleSize(levelKey) / .GetLevelPrice(levelKey)int? / double?
.IsLevelTouchedToday(levelKey)bool
.TodayAmtClass / .StatsInstrumentstring
.StatsLoaded / .StatsSessionCountbool / int
KaizenSuperTrend.TrendDirectionint+1 aufwärts, -1 abwärts, 0 vor der ersten Berechnung
.CurrentValue / .UpperBand / .LowerBanddouble
.FlippedToUpThisBar / .FlippedToDownThisBarbool
KaizenReversalIndicator.GetSignal(barIndex)KaizenReversalSignal
.IsBuySignal(barIndex) / .IsSellSignal(barIndex)bool
.CurrentATR / .CurrentEffectiveFilterdouble
KaizenSpeedOfTape.GetSpeed(barsAgo) / .GetSpeedAt(barIndex)double
.GetIsHighlight(barsAgo) / .GetIsHighlightAt(barIndex)bool
.CurrentSpeedSum / .CurrentFilterValue / .CurrentIsBullishdouble / double / bool
KaizenStatGrid.GetStatsForBar(barIndex)KaizenStatGridBarInfo — Delta, Volumen, Buy-/Sell-Aufteilung, Dauer
KaizenOrderInfo.GetRenderedOrders()IReadOnlyDictionary<double, KaizenOrderLevelInfo>

KaizenVWAP — Plot-Indizes: 0 VWAP · 1/2 Band 1 oben/unten · 3/4 Band 2 · 5/6 Band 3 · 7 VWAP der Vorsession.

Datenstrukturen

// KaizenSupplyDemand.Zones
public sealed class KaizenSupplyDemandZoneInfo
{
    public double    High, Low;
    public int       BarIndex, EndBarIndex;
    public KaizenSupplyDemandZoneType   Type;      // Supply, Demand
    public KaizenSupplyDemandZoneOrigin Origin;    // Regular, Continuation
    public bool      IsActive;
    public DateTime  Date;                         // wann die Zone entstand
    public DateTime? DateInactive;                 // wann sie brach; null, wenn noch aktiv
}

// KaizenStackedImbalance.ActiveZones / .HistoricalZones
public sealed class ImbalanceZone
{
    public int    OriginBarIndex;
    public int    MitigationBarIndex;   // -1, solange noch aktiv
    public double PriceHigh, PriceLow;
    public bool   IsBullish;
    public bool   IsActive;
}

// KaizenBigTrades.GetTradesForBar(...)
public sealed class KaizenBigTradeInfo
{
    public int    BarIndex;
    public double Price;
    public long   Volume, TickPrice, Timestamp;
    public int    Side;                 // +1 Käufer-Aggressor, -1 Verkäufer-Aggressor
    public bool   IsBuyAggressor, IsSellAggressor;
}

// KaizenTPO.SinglePrints
public sealed class KaizenSinglePrintInfo
{
    public double Price;
    public int    OriginBarIndex, MitigationBarIndex, OwnerProfileStartBar;
    public bool   IsActive;
}

Wenn still nichts zurückkommt

SymptomUrsache
Eine Liste ist immer leer, nirgends ein FehlerUpdate() fehlt (Regel 3), oder die Lizenz deckt diesen Indikator nicht ab
Indikator hängt in (Calculating…), alle Werte 0new statt der Helper-Methode (Regel 1)
Strategie läuft, macht aber 0 Trades, Ausgabedateien nur mit KopfzeileMTF-Serie vom Host nicht vorgeladen (Regel 5); der Fehler steht im NinjaTrader-Log
Backtest sieht hervorragend aus, live nichtLookahead durch ungefilterte Zonenlisten (Regel 4)
CS0246 auf den Indikatornamenusing NinjaTrader.NinjaScript.Indicators.Kaizen; fehlt

Wichtige Hinweise

  • Tick Replay muss auf dem Chart für die Orderflow-Indikatoren aktiviert sein (siehe Tabelle oben).
  • Namespace: immer NinjaTrader.NinjaScript.Indicators.Kaizen, nie .Custom.
  • Kompilieren: NinjaScript Editor → New → Strategy → Code einfügen → F5.
  • Lizenz: Dein Schlüssel muss jeden Kaizen-Indikator abdecken, den du referenzierst.
  • Bar-Index unter OnBarClose-Hosts (in v2.3 korrigiert): Wird ein Kaizen-Indikator in einer Strategie mit Calculate = OnBarClose gehostet, lieferten die Bot-APIs die Balkendaten um einen Index versetzt — „dieser Balken” gab die Werte des nächsten zurück. Wenn du Regeln auf diesen Werten gebaut und vor v2.3 gebacktestet hast, prüfe die Ergebnisse: Der Versatz wirkte wie ein Lookahead.
  • Bekannte Einschränkung — Footprint-Summenwerte: CurrentBarDelta, CurrentBarTotalVolume, CurrentBarPOC und die Summenfelder aus GetFootprintForBar(...) bleiben in einer Strategie 0. Die Engine berechnet sie in OnRender, und ein Strategie-Host löst OnRender nicht zuverlässig aus. Nutze stattdessen RecentAbsorptions — das wird in OnBarUpdate gefüllt. Die Methoden auf Ebene einzelner Preislevel (GetBarDelta, GetBarPOCPrice, die Imbalance- und Absorptionslisten) sind davon nicht betroffen.
  • Mindestversion: v2.3. Frühere Versionen hatten abweichende Helper-Signaturen und den oben beschriebenen Bar-Index-Versatz.