If you’ve been building indicators or strategies in NinjaTrader 8 for more than five minutes, you’ve probably found yourself writing the same utility methods over and over again.
✅ Round to tick size
✅ Get a unique ID
✅ Grab a moving average
✅ Change brush opacity
…and on and on.
Sure, it works… but after a while, your codebase becomes a mess. Indicators balloon with duplicate logic, debugging gets harder, and suddenly everything takes longer than it should.
Looking back, I wish I had understood this approach sooner. It would’ve saved me hours of rewriting the same blocks of code and made debugging way easier. Building a centralized toolbox isn’t just for “clean code” bragging rights — it’s practical, time-saving, and helps you scale your projects the right way.
In the last Learn NinjaScript post, we broke down the anatomy of a method — how they’re structured, how to pass parameters, when to return values, and more. This time, we’re putting that knowledge into action by building something extremely useful: a shared NinjaScript Toolbox 🧰.
This isn’t a NinjaTrader UI AddOn — it’s a lightweight, smart way to house all your most-used functions and methods in one clean, reusable place using partial class
support.
In this post, I’ll show you:
- 🛠 How to organize and structure these shared utilities
- 🔁 How to make them accessible from any indicator
- ✨ The kinds of functions that actually belong in your toolbox
- 🚀 Real-world examples you can copy and drop into your own scripts
Let’s clean up your code, make development faster, and free you up to focus on what really matters — building better logic and making smarter trades. 💡📈
📚 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
🗂️ What Is an “Add-On” in This Context?
Let’s clear something up before we dive in.
When most people think of a NinjaTrader Add-On, they picture the flashy stuff — custom windows, floating panels, dashboards. And they’re not wrong. NinjaTrader defines Add-Ons as powerful tools that let developers create “unprecedented utilities that are seamlessly integrated (visually and functionally)” into the platform.
But there’s another side to that definition — one that’s a little less sexy, but incredibly useful:
🛠️ The utility part.
Behind-the-scenes functions. Helpers. Code that makes everything else cleaner, faster, and more reusable.
That’s what we’re focused on here. This post is about building the functional core of your own Add-On — the kind that doesn’t create a new window, but does give you a powerful set of tools you can call from any indicator or strategy.
We do this using C#’s partial class
feature, which allows you to expand NinjaTrader’s built-in Indicator
class with your own custom methods — safely and cleanly.
So no floating control panels here. Just a lean, practical NinjaScript toolbox that lives under the hood — ready to help you build faster and code smarter.
🛠️ File Structure Overview
Alright, let’s get your toolbox built.
You could throw all your utility methods into one massive .cs
file, but trust me — things get messy fast. A better approach is to break your code up into focused, categorized files. That way, when you need to tweak a brush function or update a moving average method, you’re not digging through a 500-line monster file.
Here’s an example structure I use:
NinjaTrader 8/
└─ bin/
└─ Custom/
└─ AddOns/
├─ mdtPartialClassIndicators.cs // General tools and helpers
├─ mdtMovingAverages.cs // MA logic with enum-based access
├─ mdtChartHelpers.cs // Chart refresh, label placement
├─ mdtBrushTools.cs // Brush opacity, color tweaks
I keep all my shared utility files inside the AddOns
folder — this keeps them separate from the built-in Indicators/
directory and makes it easier to manage across multiple projects.
Each file contains a partial class Indicator
block. When compiled, NinjaTrader automatically merges all those files together, so you can use any of your custom functions directly from any indicator or strategy.
⚠️ A Quick Word on Partial Classes vs. Standalone Classes
Using partial class Indicator
is powerful — but it’s not always the right move.
👉 Use partial classes for utilities you consistently rely on across indicators (like tick rounding, session checks, or brush helpers). These are tools that are universal and lightweight.
👉 Use regular classes when you’re building more specialized logic that doesn’t belong in every script. For example, I have a class that tracks trading sessions with a full set of time/label controls. That’s not a partial class — it’s a standalone class I call when needed from specific indicators.
Bottom line:
Not everything belongs in the Indicator
class. Build your toolbox with intent — partial classes for common tools, standard classes for advanced helpers.
📎 Using partial class
to Inject Shared Methods
So, how do we actually “inject” our utility methods into NinjaTrader?
It’s all thanks to one of the most underrated features in C#: the partial
keyword. By declaring a class as partial
, you can split its definition across multiple files — and NinjaTrader will automatically stitch everything together when compiling your scripts.
✅ Here’s how it works
Let’s say you have this inside mdtPartialClassIndicators.cs
:
namespace NinjaTrader.NinjaScript.Indicators
{
public partial class Indicator
{
public double mdtRound2Tick(double price)
{
return Instrument.MasterInstrument.RoundToTickSize(price);
}
}
}
Boom — now any custom indicator you create can use mdtRound2Tick()
as if it were built-in:
protected override void OnBarUpdate()
{
double entryPrice = mdtRound2Tick(Close[0]);
}
You didn’t have to reference anything or instantiate a helper object — because the method was injected directly into the base Indicator
class through the partial
structure.
🔍 But Wait — Not Everything Belongs in a Partial Class
As mentioned earlier, not every utility is a great fit for this approach.
For example, I have a class that helps me track trading sessions: start time, end time, opening price, first 15-minute high/low, etc. This isn’t something I want baked into every indicator. Instead, I treat it as a standalone class and instantiate it only when I need it.
🧱 Here’s What That Looks Like:
public class mdtSessionTracker
{
private double sessionOpenPrice;
private DateTime sessionStart;
public void Update(double openPrice, DateTime time)
{
sessionOpenPrice = openPrice;
sessionStart = time;
}
public double GetOpen()
{
return sessionOpenPrice;
}
public bool IsNewSession(DateTime currentTime)
{
return currentTime.Date != sessionStart.Date;
}
}
Then in your indicator:
using mdtSessionTracker;
private mdtSessionTracker session;
protected override void OnStateChange()
{
if (State == State.DataLoaded)
session = new mdtSessionTracker();
}
protected override void OnBarUpdate()
{
if (session.IsNewSession(Time[0]))
session.Update(Open[0], Time[0]);
}
Two different styles — each with their place.
🎯 Rule of Thumb:
- Use
partial class Indicator
when the function is generic and reusable across many scripts. - Use a separate class when the logic is specialized or stateful and only needed occasionally.
Let’s dive into real examples of what kinds of utility methods are worth adding to your toolbox — from brush tweaks to time filters to moving average shortcuts. 🧰🧪
🔧 Utility Method Examples
Once you’ve got your partial class
setup, the next question is: what do you actually put in there?
This is where your NinjaScript Toolbox comes alive. These methods should be things you find yourself using over and over again — the behind-the-scenes helpers that make life easier, cleaner, and faster.
Below are some of my go-to categories, with examples from my own toolbox.
🧮 Math & Price Helpers
These are perfect for rounding, comparing, and handling price logic cleanly.
public double mdtRound2Tick(double price)
{
return Instrument.MasterInstrument.RoundToTickSize(price);
}
public static double mdtPercentChange(double current, double previous)
{
if (previous == 0) return 0;
return (current - previous) / previous;
}
public static bool mdtIsWithinRange(double value, double min, double max)
{
return value >= min && value <= max;
}
📊 Series & Bar Logic
These help you simplify common bar-based calculations or patterns.
public static double mdtHighestHigh(ISeries<double> input, int lookback)
{
return Enumerable.Range(0, lookback).Select(i => input[i]).Max();
}
public static double mdtLowestLow(ISeries<double> input, int lookback)
{
return Enumerable.Range(0, lookback).Select(i => input[i]).Min();
}
public bool mdtIsInsideBar()
{
return High[0] <= High[1] && Low[0] >= Low[1];
}
🕒 Time & Session Utilities
Great for identifying session boundaries or filtering based on time.
public bool mdtIsNewSession()
{
return Bars.IsFirstBarOfSession;
}
public bool mdtIsTimeInRange(TimeSpan start, TimeSpan end)
{
TimeSpan currentTime = Time[0].TimeOfDay;
return currentTime >= start && currentTime <= end;
}
🎨 Brush & Visual Tools
Perfect for styling or dynamically changing visuals.
public static Brush mdtBrushChangeOpacity(Brush baseBrush, int opacity)
{
var newBrush = baseBrush.Clone();
newBrush.Opacity = opacity * 0.01;
newBrush.Freeze();
return newBrush;
}
public static SolidColorBrush mdtBrushFromArgb(int alpha, Brush baseBrush)
{
var b = (SolidColorBrush)baseBrush;
return new SolidColorBrush(Color.FromArgb((byte)alpha, b.Color.R, b.Color.G, b.Color.B));
}
💹 Moving Average Access
This one is super helpful if you like to switch between different MAs on the fly.
public ISeries<double> mdtGetMovingAverage(mdtMovingAveragesEnum maType, ISeries<double> input, int period)
{
switch (maType)
{
case mdtMovingAveragesEnum.EMA:
return EMA(input, period);
case mdtMovingAveragesEnum.SMA:
return SMA(input, period);
case mdtMovingAveragesEnum.HMA:
return HMA(input, period);
// Add more as needed
default:
return SMA(input, period);
}
}
🚨 Signal & Candle Logic
Handy for candle pattern filtering or quick signal rules.
public bool mdtIsBullishBar()
{
return Close[0] > Open[0];
}
public bool mdtIsDoji(double threshold = 0.1)
{
double range = High[0] - Low[0];
if (range == 0) return false;
double body = Math.Abs(Close[0] - Open[0]);
return body / range <= threshold;
}
🐞 Debugging Tools
Helpful for cleaner logs or visual markers.
private int lastPrintBar = -1;
public void mdtPrintOncePerBar(string message)
{
if (CurrentBar != lastPrintBar)
{
Print(message);
lastPrintBar = CurrentBar;
}
}
The list goes on. Once you start building your own toolbox, you’ll find new helpers worth adding every week. Just remember:
- If you find yourself copy/pasting code → toolbox it.
- If you use it in 3+ scripts → toolbox it.
- If it helps you debug faster or trade smarter → definitely toolbox it.
🧱 Organizing Your Toolbox (File Structure + Naming Conventions)
When it comes to organizing your NinjaScript toolbox, there’s no one “correct” way to do it — but there are ways that make life a lot easier.
I’ve gone through plenty of trial and error, and what I’ve learned is this:
A little structure goes a long way.
And what works for me might not be perfect for you — so don’t be afraid to tweak it until it fits your workflow.
Here are some general guidelines to help you get started and stay sane 🧼🧠
🗂️ File Structure Tips
You don’t want one giant file with 500+ lines of unrelated code. Splitting things up keeps your utilities modular and easier to manage. A simple structure might look like this:
NinjaTrader 8/
└─ bin/
└─ Custom/
└─ AddOns/
├─ mdtPartialClassIndicators.cs // General helpers (ticks, rounding, logic)
├─ mdtBrushTools.cs // Brushes, colors, opacity
├─ mdtChartHelpers.cs // ChartControl / drawing methods
├─ mdtMath.cs // Math tools, max/min, % change
├─ mdtTimeUtils.cs // Time filters, session logic
├─ mdtMovingAverages.cs // MA access and enums
├─ mdtSessionTracker.cs // (Example of a non-partial, standalone class)
General Rule:
- If the methods are small and commonly used → partial class
- If they involve state, tracking, or are only used in one or two scripts → standalone class
🧠 Naming Conventions That Make Things Easier
Consistent naming pays off when your toolbox starts growing.
Here’s what I personally stick to:
🔤 Prefix Everything
Use a unique prefix like mdt
(for MyDailyTake) on all methods and classes to avoid conflicts and make autocomplete more useful.
mdtRound2Tick()
mdtIsNewSession()
mdtBrushChangeOpacity()
📄 Group by Function
Use consistent words for related tools:
mdtBrush*
for anything dealing with brushesmdtTime*
for anything time/session relatedmdtDraw*
for chart labels and visual markersmdtGet*
for logic that returns valuesmdtIs*
ormdtHas*
for booleans
🧩 Class Naming
mdtPartialClassIndicators.cs
→ your master “general tools” filemdtWhatever.cs
→ each focused file should only contain related helpers- Use PascalCase for class names and methods to stay aligned with C# standards.
🔄 It Might Take Some Tweaking
You won’t get it perfect on day one — and that’s okay.
💡 Try a structure, build with it for a few weeks, and adjust based on what’s annoying or slowing you down. You might decide you want all visual methods in one file, or you might prefer grouping by indicator type (e.g., mdtTrendTools.cs
, mdtReversalLogic.cs
).
The point is: organize it in a way that helps you write, debug, and improve your indicators faster.
🧽 Final Thoughts: Clean Code, Faster Builds, Easier Debugging
Building a NinjaScript toolbox isn’t just about writing cleaner code — it’s about building smarter workflows that help you trade better, develop faster, and spend less time fixing bugs you’ve already solved in the past.
When you centralize your utilities:
- 🧰 You stop rewriting the same functions over and over
- ⚙️ You can test updates in one place and have them apply across every script
- 🧼 Your indicators stay lean, readable, and focused on what they’re actually supposed to do
- 🧪 Debugging gets easier because your logic is separated and predictable
Whether it’s rounding to tick size, checking if you’re in a session, or customizing a brush — once those tools are built into your toolbox, they’re always there, ready to use.
And yeah, it might take some tweaking to find a structure that works perfectly for you…But once it clicks, you’ll wish you had done it sooner (I know I did).
So if you’re tired of bloated indicators and copy-paste madness — build your toolbox. Make your coding life smoother. Your future self will thank you. 👊
🎉 Prop Trading Discounts
💥91% off at Bulenox.com with the code MDT91