You finally got your custom indicator to compile. You drop it on the chart, ready to feel like a genius—aaaand 💥 Unhandled exception in OnBarUpdate().
If you’ve ever had NinjaTrader slap you with one of those cryptic errors or freeze your backtest halfway through, you’re not alone. The good news? There’s a simple tool built into C# that can help you dodge those crashes and keep your script running smooth: try/catch
.
In this post, we’ll break down what try/catch
actually does, how to use it in NinjaScript (without overdoing it), and when it’s better to just fix your logic. From rookie mistakes to advanced debugging and performance tricks, this is your no-fluff guide to writing safer, smarter code.
📚 Related NinjaScript Lessons So Far
If you’re new here, make sure you check out the earlier posts too:
- Understanding the NinjaTrader Indicator Structure
- Variables and Properties in NinjaScript
- OnStateChange() Lifecycle Explained
- OnBarUpdate() Fully Explained
- Learn how to use Series<T>
- Learn NinjaScript Plots
- Learn NinjaScript Lines
- How to use NinjaScript Brushes
- Creating and Using Methods & Functions
- Add-On Your Way to Cleaner Code
- Using Lists, Dictionaries, and Arrays
- Creating and Using Classes Inside an Indicator
- Drawing on the Chart with Draw Objects
- Alerts, PlaySound, and Rearm Control
- Create and Use Custom Enums
- Booleans, If Statements, and Conditions
- Loops (For, While, Foreach)
🤔 What Is try/catch
, Really?
At its core, try/catch
is a way to tell NinjaTrader: “Hey, something might go wrong here—and if it does, don’t blow up the entire script.”
Here’s the basic structure:
try
{
// Code that might fail
}
catch (Exception ex)
{
// Code to run *if* it fails
Print("Error: " + ex.Message);
}
When the code inside the try
block runs, everything’s normal—unless it hits something that throws an exception. If that happens, NinjaTrader jumps straight to the catch
block and skips the rest of the try
. This keeps your chart alive and lets you gracefully handle the issue.
🧪 Without try/catch
, What Happens?
If you don’t handle exceptions, NinjaTrader will stop your strategy or indicator cold. That means:
- Your chart may stop updating
- You’ll get a big error in the Log tab or Output window
- Your strategy will exit or never finish backtesting
Think of try/catch
like a circuit breaker—it doesn’t fix the wiring, but it keeps the house from burning down.
🧠 Real-World Analogy
Imagine you’re unlocking a door. Most of the time, the key works. But what if it doesn’t? Without try/catch
, your script just panics and throws the key into the void. With try/catch
, it calmly says, “Key doesn’t work—let’s try something else.”
🧭 When to Use try/catch
in NinjaScript (and When Not To)
Using try/catch
the right way can save your indicator from unexpected crashes, but slapping it everywhere is a recipe for confusion, slower performance, and hidden bugs. Let’s talk about when it makes sense—and when it really doesn’t.
✅ Good Use Cases
These are the scenarios where try/catch
can actually protect your script and make development smoother:
📉 1. Debugging risky access (like Close[n]
) in early bars
Sometimes, you need to test logic that might reference historical bars that don’t exist yet. NinjaTrader’s SampleTryCatch
indicator shows how to trap those failures without killing the script.
try
{
double total = 0;
for (int i = 1; i <= 10; i++)
total += Close[i]; // This will break if CurrentBar < 10
Value[0] = total / 10;
}
catch (Exception e)
{
Log("Error calculating average: " + e.Message, LogLevel.Warning);
Print(Time[0] + " " + e.ToString());
}
🛑 Don’t leave this in production. Once you find the issue, replace with a proper guard like:
if (CurrentBar < 10)
return;
🎨 2. Rendering with SharpDX brushes
When creating custom visuals using SharpDX, each chart render target needs its own resources. Resizing the chart, changing tabs, or hit-testing can all trigger OnRenderTargetChanged()
, which is where you should safely (re)create things like brushes.
public override void OnRenderTargetChanged()
{
try
{
if (dxBrush != null)
dxBrush.Dispose();
if (RenderTarget != null)
dxBrush = Brushes.Blue.ToDxBrush(RenderTarget);
}
catch (Exception ex)
{
Print("Brush creation error: " + ex.Message);
}
}
This avoids runtime DirectX errors like:
D2DERR_WRONG_RESOURCE_DOMAIN: The resource was realized on the wrong render target.
🔉 3. Optional file or sound input from the user
If you’re letting users set file paths or pick a sound file, they could choose something that doesn’t exist. Wrap those calls so the rest of the script isn’t affected.
try
{
PlaySound(SoundAlert);
}
catch (Exception ex)
{
Print("Could not play sound: " + ex.Message);
}
🚫 Bad Use Cases
These are the scenarios where try/catch
is more harmful than helpful:
❌ Wrapping all of OnBarUpdate()
try
{
// Entire logic inside
}
catch { } // Silent failure = disaster
This hides bugs and makes them hard to track down. Worse, it can severely impact performance if you’re doing this on every bar or tick.
❌ Using it instead of proper checks
Most NinjaTrader errors can be avoided with good pre-conditions:
if (CurrentBar < 10) return;
if (BarsInProgress >= BarsArray.Length) return;
if (!BarsArray[1].IsValidDataPoint(0)) return;
Don’t use try/catch
to cover laziness—it’s a safety net, not a substitute for clean logic.
🧠 Smarter Error Handling: Filters, Fallbacks, and Debug Tricks
Now that you’ve seen how to use try/catch
, let’s make it smarter. We’re going to look at how to catch specific types of errors, give your code a safe fallback, and actually learn from the errors instead of just silencing them.
🎯 Catching Specific Exception Types
You’ve probably seen catch (Exception ex)
—but did you know you can catch specific errors too? C# lets you “stack” multiple catch
blocks to handle different types of problems in different ways.
Let’s break it down:
try
{
double val = Convert.ToDouble(UserInput);
}
catch (FormatException ex)
{
Print("That’s not a valid number format.");
}
catch (OverflowException ex)
{
Print("The number is too big or too small.");
}
catch (Exception ex)
{
Print("Something unexpected went wrong: " + ex.Message);
}
💡 What’s happening here?
FormatException
is thrown whenUserInput
is something like"abc"
—you can’t turn that into a number.OverflowException
happens if the number is so big or small it can’t be stored in adouble
.Exception
is the base class for all exceptions. If nothing else matches, this one will catch it.
🧱 Think of it like this:
- Each
catch
is a filter. - The first one that matches the error gets executed.
- After one
catch
runs, the rest are ignored.
👉 You can stack as many catch
blocks as you want—but only one will run per error.
⚙️ Why This Is Better Than Just Exception
If you always catch everything like this:
catch (Exception ex)
{
Print("Error: " + ex.Message);
}
…you’ll never know what kind of error it was. And if you only care about a certain type (like bad user input), you might end up hiding a bug that should be fixed instead.
By catching specific types:
- You make debugging easier
- You can respond differently to different problems
- You avoid covering up real issues
🪛 Safe Fallbacks with Helper Functions
Instead of wrapping every line in a try/catch
, sometimes it’s cleaner to push risky logic into a helper method.
Example: Division
public double SafeDivide(double numerator, double denominator)
{
try
{
return numerator / denominator;
}
catch (DivideByZeroException)
{
return 0; // or double.NaN or whatever fallback makes sense
}
}
Now in your main code:
double risk = SafeDivide(accountBalance, tradeCount);
🧼 Cleaner. Easier to test. Safer.
📋 Better Logging and Debugging
When something breaks, you want to know:
- What failed
- When it happened (time)
- And ideally, why
Here’s how to get all three:
catch (Exception ex)
{
if (State >= State.Terminated)
return;
Log("Error during processing at " + Time[0], LogLevel.Warning);
Print("Detailed error info: " + ex.ToString());
}
Log()
sends a message to the NinjaTrader Control Center > Log tabPrint()
sends full detail to the Output windowTime[0]
helps you line it up with what was happening on the chart
🛑 Never Swallow Exceptions Silently
This is a common mistake:
catch { } // ❌ Bad: you caught it, but didn’t do anything with it
You just told NinjaTrader: “If something breaks, I don’t want to know about it.” That’s how bugs sneak into production and ruin trading logic.
Always log or print something. Even just:
catch (Exception ex)
{
Print("Something went wrong: " + ex.Message);
}
That tiny print can save you hours of head-scratching later.
📚 What Are DivideByZeroException
, FormatException
, and Exception ex
?
When something goes wrong in your code—like dividing by zero or converting a bad string—C# creates an exception object to describe what broke. This object is thrown, and if you have a try/catch
, you can grab it and do something with it.
Let’s break it down:
catch (DivideByZeroException ex)
DivideByZeroException
is the type of error you’re catching.ex
is just a variable name that holds the error object.- You can use
ex.Message
,ex.StackTrace
, or justPrint(ex.ToString())
to see what happened.
🧠 Why So Many Exception Types?
Because not all errors are created equal. Here’s a quick guide to some common exceptions you’ll see in NinjaScript development:
Exception Type | When It Happens | Example |
---|---|---|
DivideByZeroException | You divide a number by 0 | double avg = total / 0; |
FormatException | You try to convert a string that’s not formatted right | Convert.ToDouble("abc") |
OverflowException | A number is too big or too small for the data type | Convert.ToInt32("99999999999") |
IndexOutOfRangeException | You try to access something outside a list or series | Close[50] when CurrentBar is 10 |
NullReferenceException | You use an object that hasn’t been set (it’s null) | myBrush.Opacity = 0.5f; when myBrush = null |
Exception (generic) | Catches any of the above if you didn’t name it | Always include this as your final safety net |
🧱 Catching Specific vs. Catching Everything
You can have multiple catch
blocks, and C# will pick the first one that matches the actual error type. That’s why order matters:
try
{
// Some risky code
}
catch (FormatException ex)
{
Print("Formatting error: " + ex.Message);
}
catch (Exception ex)
{
Print("General error: " + ex.Message);
}
In this case:
- If a
FormatException
happens, the firstcatch
runs. - If any other error happens, it goes to the second
catch
.
If you put the generic catch (Exception)
first, the specific ones below it are ignored and won’t even compile.
🧭 So… Which Ones Should You Use?
For most NinjaScript work, here’s a practical approach:
- ✅ Start with
catch (Exception ex)
during early development or debugging. - ✅ If you’re working with user input or math, also add:
FormatException
DivideByZeroException
OverflowException
- ✅ If you use custom rendering or SharpDX objects, add:
NullReferenceException
- ✅ Always end with a final
catch (Exception ex)
to catch anything you missed.
You don’t need to use all of them every time—but if you know what kind of error you’re expecting, it’s better to catch it directly.
🔁 Reusable try/catch
: Make Error Handling Clean and Consistent
If you’ve ever copy-pasted the same try/catch
block into multiple spots, you know it starts to clutter your script fast. A better way? Wrap your error handling into a reusable method that you can call anywhere.
💡 The Goal: Keep Your Logic Clean
Instead of this:
try
{
double result = CalculateRisk();
}
catch (Exception ex)
{
Print("Error: " + ex.Message);
}
You can write:
SafeExecute(() =>
{
double result = CalculateRisk();
});
Much cleaner—and easy to reuse.
🛠️ How to Build It
Here’s a simple SafeExecute
method you can drop into any indicator or strategy:
public void SafeExecute(Action action)
{
try
{
action();
}
catch (Exception ex)
{
if (State >= State.Terminated)
return;
Print("SafeExecute error: " + ex.Message);
}
}
This uses C#’s Action
delegate to let you pass in any block of code. It’s a great fit for:
- Isolated calculations
- Property parsing
- Drawing logic
- Rendering segments
✨ Bonus: A Version with Fallback Return Values
What if you want to return a result and catch errors? Here’s a version that gives you a fallback if something breaks:
public T SafeReturn<T>(Func<T> func, T fallback)
{
try
{
return func();
}
catch (Exception ex)
{
Print("SafeReturn error: " + ex.Message);
return fallback;
}
}
Now you can do this:
double risk = SafeReturn(() => CalculateRisk(), 0);
That means if CalculateRisk()
fails, you still get a result—and your chart keeps going.
✅ These patterns are especially useful when you’re working with unreliable data, custom rendering, or user-defined inputs. You protect the core logic of your script without burying everything in repetitive try/catch
blocks.
🧹 Final Thoughts: Error Handling That Doesn’t Suck
Error handling in NinjaScript isn’t about being perfect—it’s about being prepared. You’re building tools in a live, fast-moving environment, and unexpected things will happen: missing bars, null brushes, divide-by-zero math, bad user input… the works.
🛡️ That’s where try/catch
shines—not just as a safety net, but as a debugging ally and code stability booster.
Here’s the short list to keep in mind:
- ✅ Use
try/catch
to protect code that might fail—but don’t wrap everything out of fear. - ✅ Catch specific exceptions (
FormatException
,DivideByZeroException
) when you know what to expect. - ✅ Always log or print the error during development—don’t silently fail.
- ✅ Use guards (
if (CurrentBar < 10) return;
) when you can prevent errors up front. - ✅ Keep your code clean with helpers like
SafeExecute()
andSafeReturn()
.
Remember: the goal isn’t to avoid every error—it’s to write scripts that handle failure gracefully and keep going without breaking your chart or strategy.
Because nothing’s worse than hitting Play on your backtest… and getting slapped with a red log message 2 seconds later.
🎉 Prop Trading Discounts
💥91% off at Bulenox.com with the code MDT91