Debugging is one of the most underrated skills when it comes to writing NinjaScript indicators. You can have the cleanest code in the world, but if the logic isn’t behaving how you expect—or worse, it’s silently failing—you’ll find yourself stuck staring at a chart wondering what went wrong.

In NinjaTrader, debugging isn’t quite the same as it is in traditional development environments. You don’t have full access to a real debugger unless you attach Visual Studio, and many developers rely heavily on the Print() statement to track what their scripts are doing behind the scenes. While that works, there’s a smarter way to go about it.

In this post, we’re going to walk through practical, real-world ways to debug your NinjaScript indicators—from simple output tricks to using chart visuals, structured print logic, and even Visual Studio breakpoints. Whether you’re just getting started or you’ve written dozens of indicators, these tips will help you solve problems faster and write more reliable code.

👉 Save this official NinjaTrader Help Guide link:

  1. Print() – NinjaTrader Help Guide
  2. Log() – NinjaTrader Help Guide
  3. Alert() – NinjaTrader Help Guide
  4. Drawing – NinjaTrader Help Guide
  5. Visual Studio Debugging – NinjaTrader Help Guide

If you’re new here, make sure you check out the earlier posts too:

🧰 How You Can Debug in NinjaTrader — All the Tools That Actually Help

NinjaTrader doesn’t give you a big red “Run Debugger” button like other platforms. But that doesn’t mean you’re flying blind. It gives you several tools that—when used the right way—can show you exactly what your code is doing, when it’s doing it, and where it’s failing.

Some tools give you written output. Others work visually. And a few help you track down edge cases or misfires that only happen once. Let’s walk through them with real-world use in mind.

🖨️ Print() — Your Day-One Debugging Friend

This is where almost everyone starts, and for good reason: Print() is fast, easy, and tells you exactly what your code is doing in real time.

Want to know if your condition is firing?

if (Close[0] > Open[0])
    Print("Bullish bar at: " + Time[0]);

Want to make sure your logic is even being hit?

Print("OnBarUpdate() running at bar: " + CurrentBar);

Want to know which data series is executing?

Print("BIP: " + BarsInProgress + " | Time: " + Time[0]);

You’ll use Print() more than you think—especially when debugging conditions that don’t throw errors but quietly don’t behave the way you expect. Just remember: it all goes to the Output window, so keep it open and don’t let it flood.

🪵 Log() — For When You Don’t Want Noise but Still Want Answers

The Log() method is great when you want to track one-time issues, like missing data series or failed setup steps—without blowing up the Output window.

Example:

if (BarsArray[1].Count == 0)
    Log("Secondary series failed to load", LogLevel.Warning);

You’ll see this in the Control Center, Log tab in NinjaTrader. It’s quiet, controlled, and useful for edge cases, especially those that happen during startup or only once.

Use it to:

  • Confirm that data series loaded
  • Flag broken state transitions
  • Quietly capture config issues without distracting from live prints

🎨 Chart-Based Debugging — Visuals That Show You What’s Really Happening

Sometimes, printing to the Output window just isn’t enough. You might need to see when and where something fired. That’s where chart-based debugging comes in.

You’ve got a few powerful options here, and they all show up directly on the chart:

  • Draw.Text() — Label bars with values, tags, or step markers
  • Draw.Dot(), Draw.ArrowUp() — Show where signals or logic fired
  • BackBrush — Change the background color to signal an event
  • PlotBrushes[] or BarBrushes[] — Color plots or bars based on your logic

Let’s say you’re calculating a custom value and want to verify it over time:

Draw.Text(this, "val" + CurrentBar, MySeries[0].ToString("0.00"), 0, Low[0] - TickSize, Brushes.White);

Or maybe you’re testing a signal condition and want to visually mark the bars where it triggers:

if (myCondition)
    Draw.Dot(this, "dot" + CurrentBar, false, 0, Low[0] - 2 * TickSize, Brushes.LimeGreen);

Want to color the whole background when something major happens?

if (myCondition)
    BackBrush = Brushes.DarkRed;

These tools are invaluable when your plot isn’t showing and you don’t know why, or when you want to visually track your logic through the chart bar-by-bar.

🚨 Alert() — Make NinjaTrader Yell at You (In a Good Way)

If you need NinjaTrader to tell you something right now, and you don’t want to stare at the chart or Output window, use Alert().

Example:

if (CrossAbove(SMA(Close, 10), SMA(Close, 20), 1))
    Alert("Crossover", Priority.High, "10/20 SMA Crossover", "Alert1.wav", 10, Brushes.Yellow, Brushes.Black);

This creates a popup and plays a sound when your condition fires. It’s especially useful in real-time testing or live environments when you want confirmation but can’t watch every tick.

🧵 Visual Studio (For When You’re Truly Stuck)

Most of the time, Print(), Draw.Text(), and colored backgrounds are enough to debug your indicator. But if you’re working on a complex strategy, using external classes, or dealing with C# exceptions that don’t make sense—you can attach Visual Studio to NinjaTrader and use a real debugger.

That means:

  • Breakpoints
  • Variable inspection
  • Step-through execution

It takes a few minutes to set up and is overkill for 90% of scripts—but it’s a lifesaver when needed.

So Which Tool Should You Use?

That depends entirely on what you’re trying to debug:

Problem Use This
“Is this line even running?” Print()
“This only happens once during startup.” Log()
“I need to see values on the chart.” Draw.Text(), Draw.Dot(), BackBrush
“I want a sound/pop-up when something triggers.” Alert()
“I’m debugging a crash or exception.” Visual Studio

Now that you know what tools you can use, let’s go over how to place them based on when NinjaTrader actually runs your code—because if you put a Print() in the wrong place, you’ll never see it.

🧭 Where Should You Start Debugging in a NinjaScript Indicator?

If your indicator isn’t doing what you expect, the hardest part isn’t writing a fix—it’s knowing where to even begin.

NinjaScript runs different parts of your code at different times (OnBarUpdate(), OnStateChange(), OnRender(), etc.). But that doesn’t mean you need to learn the whole system.

Here’s how to choose the right starting point—based on what you’re seeing (or not seeing)—and where to put your debug code.

✅ Start in OnBarUpdate() — This Is Your First Stop

If your plots aren’t showing, your signals aren’t firing, or your draw objects aren’t appearing… start here. This is the method that runs once per bar (or tick), and it’s where most of your logic should live.

Drop this in first (there are more examples in the section below):

protected override void OnBarUpdate()
{
    Print("OnBarUpdate: " + Time[0]);
}

If you see output, your indicator is actively running. Now you can debug conditions, values, or logic flow line by line.

If you don’t see anything print, your code isn’t making it that far. Time to move one layer up…

🧱 If OnBarUpdate() Doesn’t Fire, Check OnStateChange()

If NinjaTrader isn’t reaching your main logic, it probably never finished loading the indicator. To check that, go to OnStateChange() and drop in:

protected override void OnStateChange()
{
    Print("State: " + State.ToString());
}

You should see:

State: SetDefaults  
State: Configure  
State: DataLoaded

If you don’t see DataLoaded, NinjaTrader bailed during initialization—maybe because of:

  • A bad AddDataSeries() call
  • A missing or misconfigured plot
  • No historical bars loaded

Fixing that first is important—nothing else will work until NinjaTrader fully loads the script.

🧠 Pro tip: Even advanced devs use this line to troubleshoot indicators that silently fail to initialize.

🖼️ If Logic Runs But Nothing Shows: Use Visual Debugging

When your logic is firing but you don’t see anything on the chart, it’s time to move into chart-based debugging.

Add this inside OnBarUpdate():

Draw.Text(this, "val" + CurrentBar, Close[0].ToString("0.00"), 0, Low[0] - TickSize, Brushes.White);

Now you’ll see the value printed directly under the bar. If your condition should fire but nothing happens, try this:

if (myCondition)
    Draw.Dot(this, "dot" + CurrentBar, false, 0, Low[0] - 2 * TickSize, Brushes.Lime);

These visuals tell you:

  • If your logic is firing on the right bar
  • If your condition is skipping bars unintentionally
  • Whether your plots are being calculated correctly (even if not plotted)

This is the fastest way to bridge the gap between “code is running” and “something is showing.”

🧵 Don’t Start in OnRender() Unless You Know Why

You should only look at OnRender() if:

  • You’ve written custom rendering code
  • You’re drawing lines, regions, or text using SharpDX
  • Your visuals are complex and not showing up as expected

Most indicators never touch this method—so if you’re not overriding it yourself, you can skip it.

If you are debugging inside OnRender(), use Draw.Text() or a Print() in OnBarUpdate() first to confirm your data is valid before blaming render code.

🧭 Where to Start — Based on What You’re Seeing

What You See Where to Start Debugging
Absolutely nothing OnStateChange() → check for DataLoaded
Code loads, but nothing fires OnBarUpdate() → drop a basic Print()
Values update, but chart shows nothing Add Draw.Text() or Draw.Dot() in OnBarUpdate()
You're drawing with custom rendering code Check OnRender() (but only if you wrote in it)

This isn’t about memorizing method names—it’s about knowing where to stick your first debug statement and what it’ll tell you.

From here, you can move into debugging specific issues—like conditions that never trigger or plots that fail silently.

🖨️ Deep Dive: Using Print()

Print() is the most basic, accessible, and powerful debugging tool in NinjaScript. It doesn’t require setup, doesn’t crash your platform, and gives you immediate feedback on what your code is doing.

But too many traders use it incorrectly—or barely scratch the surface of what it’s capable of.

This section shows you how to use Print() the right way, from your very first line to structured outputs that help you debug conditions, cross-check logic, and isolate silent failures across multi-series scripts.

🧠 Why You Should Use Print()

In traditional software development, developers use debuggers to pause execution, step through code, and inspect values. But in NinjaTrader, especially when running historical data or testing in real time, you don’t have that luxury unless you’re using Visual Studio.

So how do you find out what’s going on under the hood?

You print it.

Print() lets you:

  • Confirm whether a block of code is running
  • Check the value of a variable at a specific bar
  • Inspect what’s happening inside a condition
  • Determine which BarsInProgress stream is executing
  • Identify subtle logic bugs that don’t throw errors

And you can do all of that without leaving the chart.

🔌 Where Does Print() Go?

You’ll usually place it in:

  • OnBarUpdate() — for checking logic that runs per bar or tick
  • OnStateChange() — for confirming script load phases
  • Inside custom methods — for testing how helper functions behave
  • Inside if or else branches — to see why a condition passed or failed

💡 If you’re not seeing anything print to the Output window, your code might not be running. Start by dropping a Print("Test") in OnBarUpdate() to confirm basic execution.

🪜 From Basic Prints to Structured Debug Output

✅ Step 1: Confirm execution

If you’re not sure your code is running:

Print("✅ Reached OnBarUpdate at " + Time[0]);

You’ll know for sure that the script is hitting OnBarUpdate() and when.

✅ Step 2: Check a variable’s value

Print("SMA(10): " + SMA(Close, 10)[0]);

Need to check two values?

Print("Close: " + Close[0] + " | Open: " + Open[0]);

Need more structure?

Print($"[{CurrentBar}] {Time[0]} | Close: {Close[0]} | SMA: {SMA(Close, 10)[0]}");

This gives you time, bar index, and values—all in one line.

🔄 Use Cases: Print() in Real Life

Let’s walk through common scenarios where Print() is essential.

🔍 “Is my code running at all?”

protected override void OnBarUpdate()
{
    Print("Running at: " + Time[0]);
}

If you don’t see this output, your script might not be loading fully (check OnStateChange() next).

⚖️ “Why isn’t my condition firing?”

Let’s say your condition isn’t doing what you expect:

if (Close[0] > Open[0])
{
    // Expect this to trigger on bullish bars
    Print("✅ Bullish bar at: " + Time[0]);
}
else
{
    Print("⛔ Not a bullish bar at: " + Time[0] + " | Close: " + Close[0] + " | Open: " + Open[0]);
}

Now you’ll see the actual values that are failing your logic.

🧩 “Which BarsInProgress is running?”

This is huge when working with multi-timeframe scripts:

Print("Bar: " + CurrentBar + " | BIP: " + BarsInProgress + " | Time: " + Time[0]);

You’ll often discover that your logic is running on the wrong series—or not running on your secondary series at all.

⏱️ “Did this condition ever fire during this test?”

Print with a filter:

if (CrossAbove(SMA(Close, 10), SMA(Close, 20), 1))
{
    Print("✅ Crossover at bar " + CurrentBar + " | Time: " + Time[0]);
}

You’ll see exactly when and how often it triggered across your chart.

📋 Formatting Tips That Save Time

  • Include CurrentBar and Time[0] in every debug line
  • Always include BarsInProgress in multi-series scripts
  • Use ToString("0.00") to keep decimal values readable
  • Separate values with | for quick scanning in Output window

Example:

Print($"[{CurrentBar}] {Time[0]} | BIP: {BarsInProgress} | Fast: {fast[0]:0.00} | Slow: {slow[0]:0.00}");

🧼 Avoiding Output Window Overload

The NinjaTrader Output window can only handle so much. Too many lines too fast and it will:

  • Freeze
  • Lag the platform
  • Stop displaying new prints

How to keep it clean:

  • Print only every X bars:
if (CurrentBar % 10 == 0)
    Print("Bar " + CurrentBar);
  • Use a boolean toggle:
if (ShowDebug)
    Print("Debug Info: " + Close[0]);
  • Remove or comment out Print lines when you’re done debugging
  • Don’t leave Print in production-level scripts—it slows performance

If you don’t want your debug visuals to stack up every time the script reloads:

if (State == State.DataLoaded)
    ClearOutputWindow();

🧠 Bonus: Print Smart, Not More

Here are advanced tricks that help you debug smarter:

✅ Compare before and after logic values:

double prior = mySeries[1];
double current = mySeries[0];
Print($"Before: {prior} | After: {current} | Diff: {current - prior}");

✅ Use emojis or tags to flag prints

Print("⚠️ Reversal triggered at " + Time[0]);

That makes key lines easier to spot in a wall of output.

❌ Common Print() Mistakes to Avoid

Mistake Problem Fix
Print("Condition fired"); No context—when? where? Add Time[0], BIP, and variable values
Printing on every bar Floods Output window Throttle with CurrentBar % X == 0
Using Print() in OnRender() Doesn’t run reliably Stick to OnBarUpdate() or helper methods
Forgetting to remove after testing Slows code & clutters logs Clean up once done

💬 Recap

Print() is your first, fastest, and often best way to understand what’s happening inside your NinjaScript. But it’s only as useful as the info you include.

Use it to:

  • Confirm your code is running
  • Track variables and logic behavior
  • Debug execution order and multi-series issues
  • Build a step-by-step view of your script in action

Always include context:

  • Time[0]
  • CurrentBar
  • BarsInProgress
  • Variable values

🪵 Deep Dive: Using Log()

Print() is perfect when you’re actively watching your script run and want constant feedback. But sometimes, you only care about rare conditions—things that happen once, during startup, or under edge cases.

That’s where Log() shines. It lets you report problems, track state, and surface important messages—without cluttering your Output window or slowing down your platform.

🧠 What Is Log()?

The Log() method writes a message to the Control Center, Log tab in NinjaTrader. It can be configured with different severity levels (e.g., info, warning, error), and doesn’t overwhelm your system like Print() can if called repeatedly.

Think of it as a quiet alert system for unusual or important events.

✅ When to Use Log() (Instead of Print())

Use Log() when:

  • A condition should only happen once, and you want to track it
  • You’re debugging script loading or state transitions
  • You want to report config problems to the user (like missing series or settings)
  • You need to debug something that fails silently
  • You’re trying to keep the Output window clean, but still want info

🧪 Real-World Scenarios

🔄 Detecting failed data series setup

if (BarsArray.Length < 2 || BarsArray[1].Count == 0)
    Log("Secondary series failed to load", LogLevel.Warning);

You won’t see this in the Output window—but it’ll show up in the Log tab, exactly once.

🧱 Catching failed state transitions

Let’s say you expect to hit State.DataLoaded, but don’t:

if (State == State.Configure && BarsArray.Length < 2)
    Log("Expected AddDataSeries() setup failed — no secondary data.", LogLevel.Error);

This is huge when debugging why your indicator never hits OnBarUpdate().

🧰 Reporting config mistakes

Maybe a user forgot to set a required property:

if (MyLookback < 1)
    Log("Invalid Lookback setting: Must be >= 1", LogLevel.Error);

Use this instead of crashing the script or silently failing. It also respects NinjaTrader’s logging levels and helps with debugging user settings.

🧾 Log Syntax & Severity Levels

Log("Message", LogLevel.Info);      // General info
Log("Message", LogLevel.Warning);   // Something might go wrong
Log("Message", LogLevel.Error);     // Something definitely went wrong

Where it shows up:

  • Log tab (bottom of NinjaTrader terminal)
  • Log file (in case you need to send to support)
  • Does not appear on chart or Output window

📏 Formatting for Readability

Use the same formatting approach you use with Print():

Log($"[{CurrentBar}] BIP: {BarsInProgress} | Data series not loaded", LogLevel.Warning);

You can include:

  • CurrentBar
  • BarsInProgress
  • Time[0] (if you know you’re in OnBarUpdate())

Just avoid printing every bar—Log() should only fire when something meaningful happens.

🧼 Best Practices for Using Log()

Do This Not This
Log one-time setup failures Don’t log every bar
Include bar/time context if possible Don’t be vague ("Something went wrong")
Use LogLevel.Warning or Error when needed Don’t log everything at Info level
Combine with conditional logic to reduce noise Don’t log things you already Print

🚧 Common Mistakes

Mistake What Happens
Logging inside OnBarUpdate() unconditionally Massive spam in Log tab and potential lag
Using Log() when Print() is better You won’t see real-time updates
Not checking Log tab when debugging init bugs You’ll miss critical info if you only watch Output

🤝 How It Plays with Print()

Think of Log() as the whisper to Print()’s shout.

You can use both in the same script, like this:

if (BarsInProgress == 1 && BarsArray[1].Count == 0)
{
    Print("Secondary series is empty — this is a problem.");
    Log("BarsArray[1] had 0 bars at DataLoaded", LogLevel.Warning);
}

This way you can:

  • Watch real-time debugging in Output
  • Leave a permanent note in the Log tab for post-run review

💬 Summary

Use Log() when you need to:

  • Debug problems that only happen once
  • Catch failed state transitions
  • Track misconfigurations
  • Keep long-running debug notes without output spam

It’s your low-noise, high-signal debugging tool—and complements Print() perfectly.

🎨 Deep Dive: Chart-Based Visuals

When Print() tells you that something happened—but you need to see when and where it happened—chart-based debugging is your best friend.

This is especially useful for:

  • Confirming your logic on historical bars
  • Visually validating signals and calculated values
  • Debugging plot behavior or misalignment
  • Understanding bar-by-bar how your script is progressing

Instead of digging through lines in the Output window, you can just look at your chart and see what your indicator is doing.

🧠 Why Use Chart-Based Debugging?

Because visuals are faster to interpret than text.

You can:

  • Show exact bars where conditions fire
  • Plot calculated values that don’t render normally
  • Visually track whether your logic “misses” expected setups
  • Confirm your series are aligned or firing as expected
  • Debug in real-time or on historical data

Chart-based tools persist on the chart, so you can scroll back, look over your logic, and instantly spot gaps or misfires.

🛠️ Tools You’ll Use

Tool What It Does
Draw.Text() Writes custom text on a specific bar
Draw.Dot() / Draw.ArrowUp() Marks bars with symbols for visual tracking
BackBrush Colors the background of the chart on specific bars
PlotBrushes[] / BarBrushes[] Colors your plots or price bars
Draw.Region() Visualizes ranges between two plots
Draw.Line() Shows calculated support/resistance or debug values

We’ll cover the most practical ones below.

✍️ Draw.Text() – Show Values Directly on the Chart

Want to know what your custom series is doing?

Draw.Text(this, "debug" + CurrentBar, MySeries[0].ToString("0.00"), 0, Low[0] - TickSize, Brushes.White);

✅ Tip: Include CurrentBar in the tag so the text is unique per bar—otherwise it’ll overwrite itself.

Use this to:

  • Show the value of a calculation
  • Confirm logic without a plot
  • Annotate bars where conditions are met

📍 Draw.Dot() – Mark Signal Bars Visually

Need to know when a condition fired?

if (myCondition)
    Draw.Dot(this, "dot" + CurrentBar, false, 0, Low[0] - 2 * TickSize, Brushes.Lime);

Also try:

Draw.ArrowUp(this, "signal" + CurrentBar, false, 0, Low[0] - 2 * TickSize, Brushes.Green);

You’ll see exactly which bars triggered the logic.

🎨 BackBrush – Highlight Entire Bars

Want to color the entire chart background when something happens?

if (myCondition)
    BackBrush = Brushes.DarkRed;

Perfect for:

  • Reversal zones
  • Trend breaks
  • Setup windows
  • Identifying major logic events

📈 PlotBrushes[] – Debug Plot Appearance

If your plot looks wrong—or doesn’t show at all—try coloring it per condition:

if (myCondition)
    PlotBrushes[0][0] = Brushes.Magenta;

Also works for price bars:

if (myCondition)
    BarBrushes[0] = Brushes.LightBlue;

This tells you:

  • Whether the plot is being set
  • When it’s updating
  • If your logic is skipping bars

📊 Draw.Region() and Draw.Line()

Less common, but useful for visualizing value bands or expected levels.

Draw.Line(this, "line" + CurrentBar, false, 10, 4000, 0, 4100, Brushes.Gray);
Draw.Region(this, "region" + CurrentBar, 0, UpperSeries, LowerSeries, null, Brushes.LightGray, Brushes.Transparent, 50);

Use it to test boundaries, spreads, or value zones.

📋 Debugging Examples with Visuals

🧪 Condition should fire but doesn’t?

if (myCondition)
{
    Draw.Dot(this, "dot" + CurrentBar, false, 0, Low[0] - 2 * TickSize, Brushes.LimeGreen);
}
else
{
    Draw.Text(this, "missed" + CurrentBar, "Not met", 0, High[0] + 2 * TickSize, Brushes.Red);
}

📈 Your plot isn’t showing?

Draw.Text(this, "val" + CurrentBar, MySeries[0].ToString("0.00"), 0, Low[0] - TickSize, Brushes.White);
PlotBrushes[0][0] = Brushes.Yellow;

This helps isolate:

  • Is the value NaN?
  • Is it not being set at all?
  • Is the brush being applied but nothing shows?

🚨 Mistakes to Avoid

Mistake Problem
Reusing draw tags (no + CurrentBar) Only one visual shows; everything else is overwritten
Not removing visuals on reload Chart becomes cluttered and unreadable
Using BackBrush without condition guards Entire chart turns red and you don't know why
Overwriting plot colors unintentionally Can make real plots disappear visually

💡 Bonus: Combine with Print()

You can visually mark a bar and print data at the same time:

if (myCondition)
{
    Draw.Dot(this, "dot" + CurrentBar, false, 0, Low[0] - 2 * TickSize, Brushes.Lime);
    Print("Fired on: " + Time[0] + " | Value: " + MySeries[0]);
}

💬 Summary

Chart-based debugging is your bar-by-bar, visual truth-teller. Use it when you:

  • Want to confirm your logic visually
  • Need to debug plots that silently fail
  • Are building something complex and want to see the logic unfold

It turns your indicator into a real-time visual log, right on the price chart—no Output window required.

🚨 Deep Dive: Alert()

Sometimes you don’t have time to scroll through the Output window… or maybe your visual debug objects aren’t obvious enough. That’s where Alert() steps in. It grabs your attention with a sound, a pop-up, and even optional chart visuals—right when your condition fires.

If Print() is for development and Draw() is for review, then Alert() is for in-the-moment awareness.

💬 Author’s Note:
While Alert() can be used for debugging—and I’ve included it here for completeness—I personally don’t use it in that way. If I ever needed that kind of real-time notification or event confirmation during development, I’d rather attach the Visual Studio debugger and step through the logic directly. For me, Alert() is better reserved for production-time user feedback, not development-time issue tracking.

🔔 What Is Alert()?

The Alert() method in NinjaScript triggers a popup, optionally plays a sound, and can apply highlighting to a bar when a condition is met.

It’s best used for:

  • Debugging live or in real-time playback
  • Getting confirmation that a condition fired without babysitting the chart
  • Creating debugging pings for things that shouldn’t happen

📦 Alert Syntax

Alert(string id, Priority priority, string message, string soundFile, int rearmSeconds, Brush backgroundColor, Brush textColor);

Example:

if (CrossAbove(SMA(Close, 10), SMA(Close, 20), 1))
{
    Alert("smaCross", Priority.High, "SMA 10/20 Crossover Triggered", "Alert1.wav", 10, Brushes.Yellow, Brushes.Black);
}

🧠 Why Use Alert() for Debugging?

Because it can do three things that no other method can at the same time:

  1. Make a noise (when you’re doing something else)
  2. Show a popup with a message
  3. Highlight the bar with colors

That makes it perfect for catching rare, but important logic issues—especially when running in playback or live market mode.

🧪 Use Cases for Debugging

📢 Confirm Signal Conditions Are Firing

if (mySignal)
    Alert("debugSignal", Priority.Medium, "Signal fired at: " + Time[0], "Alert3.wav", 5, Brushes.LightGreen, Brushes.Black);

✅ Use this when you’re testing a new condition that should be triggering but isn’t.

🕵️‍♂️ Catch Setup Errors or Invalid States

if (MySeries.IsValidDataPoint(0) == false)
    Alert("badData", Priority.High, "Series data invalid!", "Alert4.wav", 15, Brushes.Red, Brushes.White);

🔍 Useful when debugging why your plots are failing silently.

🚨 Combine with Visuals

You can layer Alert() with a Draw.Dot() or BackBrush so the event is logged, heard, and seen:

if (myCondition)
{
    Alert("debugCombo", Priority.High, "Important event", "Alert2.wav", 10, Brushes.Orange, Brushes.Black);
    Draw.Dot(this, "dot" + CurrentBar, false, 0, Low[0] - TickSize, Brushes.OrangeRed);
}

🧰 Rearm Seconds — Don’t Spam Yourself

The rearmSeconds parameter prevents the alert from firing again within that time window. Use it wisely:

  • 0 = fires on every bar (dangerous)
  • 5–15 = good for real-time scalping/debugging
  • 30+ = for rare event tracking

Example:

Alert("watchlistOverflow", Priority.High, "Watchlist count exceeded", "Alert5.wav", 60, Brushes.Yellow, Brushes.Black);

⚠️ What Can Go Wrong

Mistake Consequence
No rearmSeconds throttle Alerts every bar → spam overload
Using vague id values Alert won’t fire twice on same ID
Using during State.Configure Can throw errors or do nothing
Forgetting the sound file Alert works silently, and you might miss it

✅ Use unique ids like "signal" + CurrentBar or just rotate IDs if debugging.

💡 Pro Tips

  • Test your alert without sound first—make sure logic works
  • Use "Alert1.wav" or "Alert2.wav"—they’re built into NinjaTrader
  • Alerts are non-blocking: they won’t pause code, so chain other debug tools if needed
  • You can add alerts for internal logic too (not just trade setups)

📊 Bonus: Debugging Strategy Events

Want to confirm your strategy is placing or skipping trades?

if (Position.MarketPosition == MarketPosition.Flat && shouldEnterLong)
{
    Alert("entryBlocked", Priority.High, "Long entry skipped due to flat position", "Alert3.wav", 20, Brushes.Blue, Brushes.White);
}

This works great in combination with Print() for tracking execution state + logic failure.

💬 Summary

Alert() is your real-time notification tool for:

  • Live market debugging
  • High-priority condition tracking
  • Combining logic + visual + sound in one go

Use it when you need to know right now that something important has happened—and don’t want to miss it while scanning bars or scrolling logs.

🧵 Deep Dive: Visual Studio Debugging

Most of the time, Print() and chart visuals will get the job done. But when you’re dealing with something more complex—like null reference crashes, odd state behavior, or debugging custom classes—you’ll want to step through your code like a traditional developer.

That’s where Visual Studio debugging comes in.

🧠 Why Use Visual Studio?

Visual Studio gives you what nothing else can: a real-time, line-by-line view of how your code is executing.

Use it to:

  • Set breakpoints to pause execution at specific lines
  • Inspect variables as the script runs
  • Step line-by-line through OnStateChange(), OnBarUpdate(), etc.
  • Catch silent crashes (like null object access or improper state transitions)

Yes, it’s slower to set up—but when you’re stuck, it’s often the only thing that will give you answers.

⚙️ One-Time Setup Checklist

  1. Install Visual Studio 2019 or 2022 (Community Edition is free)
  2. Make sure Debug Mode is enabled in NinjaTrader
  3. Don’t forget to compile from the NinjaScript Editor first—this generates the correct debug DLL

🔄 Step-by-Step: Attaching Visual Studio to NinjaTrader

You can follow this flow every time you want to debug interactively.

🧩 Step 1: Enable Debug Mode

  • Open the NinjaScript Editor
  • Right-click → Check “Enable Debug Mode”
  • Compile once (any script) so NinjaTrader generates the special debug DLL

💡 This is important: NinjaTrader compiles your code into NinjaTrader.Custom.dll, and Debug Mode creates a special version with debug symbols so Visual Studio can step through your code.

🧩 Step 2: Launch Visual Studio

  • In the NinjaScript Editor toolbar, click the Visual Studio icon
  • This opens the NinjaTrader.Custom project automatically in Visual Studio
    (or, navigate manually to Documents\NinjaTrader 8\bin\Custom\ and open NinjaTrader.Custom.csproj)

🧩 Step 3: Attach to the NinjaTrader Process

In Visual Studio:

  • Go to DebugAttach to Process
  • Select NinjaTrader.exe from the list
  • Click Attach

🧠 Make sure “Attach to” is set to “Managed code” or “Automatic: Managed code.”

🧩 Step 4: Set Breakpoints

  • Open your script in Visual Studio
  • Click to the left of any line to set a breakpoint

🧩 Step 5: Run Your Indicator in NinjaTrader

Apply your indicator to a chart, run it, and watch Visual Studio pause execution at the breakpoint.

From there, you can:

  • Hover over variables to inspect them
  • View the call stack
  • Step forward or backward
  • Understand exactly why and when your logic is running

🧨 Performance & Gotchas

Issue Explanation
Visual Studio doesn’t stop at breakpoints You didn’t compile from the NinjaScript editor after enabling Debug Mode
“Source Not Available” You're viewing compiled code with no debug symbols
Execution is slow or choppy That’s normal in Debug Mode—use Calculate.OnBarClose to reduce overhead
Breakpoints are skipped Make sure the NinjaScript was applied to the chart and hit that code path

🧠 Important: Always disable Debug Mode and recompile when you’re done debugging. This ensures NinjaTrader switches back to the faster, release version of the DLL.

✏️ Author Tip: Use Visual Studio to Edit Too

You can also use Visual Studio as your code editor, even if you’re not debugging. Just make sure to:

  • Open the NinjaTrader project (as above)
  • Edit and save the file in Visual Studio
  • Keep the NinjaScript Editor open in NinjaTrader — your changes will auto-compile as soon as you save

Never build from inside Visual Studio. Let NinjaTrader do the compiling.

💬 Summary

Visual Studio is your best friend when:

  • You’re stuck on a crash or silent failure
  • You need to trace variable values across multiple bars
  • You want to see the exact order of execution in NinjaTrader’s lifecycle
  • You’ve tried everything else—and you’re still lost

It’s not for every debug session. But when you need it, nothing else compares.

🧠 Final Thoughts

Debugging in NinjaTrader isn’t about memorizing every lifecycle method or learning every advanced C# feature—it’s about knowing how to observe your code in action and recognize when something doesn’t add up.

Most of the time, you’ll be able to solve a problem with just a few well-placed Print() statements or a Draw.Text() label on the chart. Other times, you’ll need to go deeper—checking OnStateChange() for setup issues, verifying data series load correctly, or even attaching Visual Studio to step through the code line-by-line.

What separates good NinjaScript developers from frustrated ones isn’t perfect code—it’s knowing how to track down the imperfections when the chart doesn’t look right, the plots don’t show, or the logic silently fails.

So the next time you find yourself stuck, go back to the basics:

  • Print it.
  • Mark it.
  • Step through it.
  • And when in doubt—start higher in the script and work your way down.

Happy coding 👨‍💻 and happy debugging 🔍.

🎉 Prop Trading Discounts

💥91% off at Bulenox.com with the code MDT91

Categorized in:

Learn NinjaScript,

Tagged in: