A Beginner’s Guide to Reusable Logic in NinjaTrader.

As your NinjaScript indicators or strategies grow more complex, your code can start to get messy — fast.

That’s where methods (also known as functions) come in.

In plain English: A method is a reusable block of code that performs a task — so you don’t have to repeat yourself over and over again.

You might already be using built-in methods without realizing it:

SMA(20)         // This is a method!
CrossAbove()    // Also a method!
Draw.Line()     // Yep, another method.

Now it’s time to learn how to create your own.

In this post, we’ll show you:

  • How to write methods that return values or perform actions
  • How to pass in values (parameters)
  • How to use methods to clean up your logic inside OnBarUpdate()
  • Practical examples of methods for signal generation, drawing, and filtering

Whether you want to identify price patterns, simplify your logic, or make your code more modular — knowing how to use methods will level up your NinjaScript skills.

Let’s get started with the basics.

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

📘🧠 What Are Methods (a.k.a. Functions) in NinjaScript?

In NinjaScript — and C# in general — a method is a reusable block of code that performs a task. You define a method once, and then call it wherever you need it.

In short, it’s how you organize logic in a clean, reusable way.

📌 In Plain English

Think of a method like a custom-built tool in your toolbox.

  • You press the button (call the method),
  • It does the job you told it to do,
  • And (optionally) gives you something back (like a true/false or a number).

Example: Imagine you want to know when price crosses above a moving average. Instead of writing the same condition over and over, you wrap that logic into a method like this:

private bool IsBullishCross()
{
    return Close[0] > SMA(20)[0] && Close[1] <= SMA(20)[1];
}

Now, whenever you want to use that logic:

if (IsBullishCross())
    Draw.TriangleUp(this, "bull" + CurrentBar, false, 0, Low[0] - TickSize * 5, Brushes.LimeGreen);

📘 Note on Terminology: In programming, people often use the words method and function interchangeably.

Technically:

  • A function is any block of code that does something and (usually) returns a value.
  • A method is just a function that belongs to a class (like your NinjaScript indicator or strategy).

For NinjaScript, you can treat them the same.
What matters is the implementation — not the name. Just know that when we say method, we’re referring to a function you’ve defined inside your script.

🔁 Why Methods Are Helpful

Most of the time in NinjaScript, you’re building indicators with multiple pieces of logic:

  • Conditions for signals
  • Custom math like ranges or averages
  • Labeling, coloring, and drawing on the chart

Instead of stuffing all of that into OnBarUpdate() and making it a giant mess, methods let you break your script into clean, readable parts.

Clarity: Your code becomes easier to read and understand.
Reusability: If you need that logic somewhere else (like in a strategy), it’s already wrapped and ready.
Debugging: If something breaks, it’s easier to isolate the problem inside one method.

💡 Key Concept: Don’t Repeat Yourself (DRY)

If you’re copying and pasting the same block of code in multiple places — stop and wrap it in a method.

❌ Bad:

if (ShowSignal && Close[0] > SMA(20)[0] && Close[1] <= SMA(20)[1])
    Draw.TriangleUp(...);

if (DoAlert && Close[0] > SMA(20)[0] && Close[1] <= SMA(20)[1])
    Alert(...);

✅ Better:

if (IsBullishCross())
{
    if (ShowSignal) Draw.TriangleUp(...);
    if (DoAlert) Alert(...);
}

It’s not just cleaner — it saves you time, prevents bugs, and makes future updates way easier.

🧪 Quick Example: A Method That Returns a Value

Let’s say you want to calculate the 10-bar average range. Instead of repeating the math every time, write a method:

private double GetAverageRange()
{
    double sum = 0;
    for (int i = 0; i < 10; i++)
        sum += High[i] - Low[i];

    return sum / 10;
}

Then use it inside your OnBarUpdate() logic:

if (GetAverageRange() > 20)
    BackBrushes[0] = Brushes.Orange;

One line, and the calculation is tucked away neatly.

🧩 Method Structure in C#: Anatomy of a Function

Before you start using methods in NinjaScript, it’s important to understand the structure of a basic method in C#. Every method has a purpose — it either performs an action or calculates and returns a value.

Here’s a simple method:

private double CalculateRange()
{
    return High[0] - Low[0];
}

Let’s break that down:

Part What It Means
private Access modifier: Only this script can use the method (we’ll mostly use private in NinjaScript)
double Return type: This method gives back a double (a number with decimals)
CalculateRange() Method name: You choose this — make it descriptive
{ ... } Code block: What the method does when it runs
return Sends the result back to wherever you called the method

📌 What Are Access Modifiers?

In C#, access modifiers control who can use the method:

  • private: Only usable within this class (most common in NinjaScript)
  • public: Usable by other scripts or tools (used when exposing things externally)

🛠️ Stick to private for your internal logic unless you know you want to expose it.

🔢 What Is a Return Type?

The return type tells NinjaTrader what kind of value the method gives back:

  • void = No return value (just does something)
  • bool = True/False logic
  • int, double, float = Numeric results
  • Brush, string, etc. = Other types depending on your needs

If your method calculates something, it will usually return a number or a bool.

🧱 Method Name: Be Descriptive

Choose names that make your code readable. For example:

  • IsBullishSignal() — good
  • Check() — too vague

Treat your method names like labels that explain what’s happening.

📬 Parameters: Passing in Info

You can pass data into your method using parameters:

private bool IsAboveLevel(double level)
{
    return Close[0] > level;
}
  • Here, level is the parameter.
  • You can pass in SMA(20)[0] or any value when calling the method.

🔁 Return Keyword

If your method has a return type (like bool, double, etc.), you must include the return keyword inside your method.

private bool IsUpBar()
{
    return Close[0] > Open[0];
}

No return = Compiler error ❌

Key Takeaway:

  • Think of a method as a toolbox — you open it, do the job, and close it.
  • Whether it gives something back (like a value) or just performs an action, the structure stays mostly the same.

🔁 When Should You Create a Method?

As you start coding more complex indicators and strategies in NinjaScript, your OnBarUpdate() method can get crowded fast. That’s where methods shine — they help you clean up your code, avoid repeating logic, and make everything easier to read, test, and maintain.

✅ Why Use Methods?

Situation Why a Method Helps
You’re repeating the same logic in multiple places Create a method once, call it whenever you need
You want to simplify OnBarUpdate() Break logic into small pieces — name them clearly
You’re debugging something Smaller methods make it easier to isolate bugs
You want to reuse logic in multiple scripts Methods can be reused across indicators and strategies

✂️ Example: Simplify a Cluttered OnBarUpdate()

❌ Messy:

protected override void OnBarUpdate()
{
    if (Close[0] > Open[0] && Close[1] > Open[1] && Close[2] > Open[2])
    {
        if (SMA(14)[0] > SMA(14)[1])
        {
            PlotBrushes[0][0] = Brushes.Green;
        }
    }
}

✅ Better — break into methods:

protected override void OnBarUpdate()
{
    if (IsThreeUpBars() && IsSmaRising())
        PlotBrushes[0][0] = Brushes.Green;
}

private bool IsThreeUpBars()
{
    return Close[0] > Open[0] && Close[1] > Open[1] && Close[2] > Open[2];
}

private bool IsSmaRising()
{
    return SMA(14)[0] > SMA(14)[1];
}

👉 Now your logic is clear, reusable, and easier to debug or improve later.

🔍 Common Use Cases for Methods

Entry/Exit Logic

  • Group together conditions for a trade entry (e.g., breakouts, crossovers)
  • Return true or false to trigger signals

Signal Confirmation

  • Use a method to verify confirmation signals (like volume or volatility conditions)

Pattern Detection

  • Encapsulate logic for things like:
    • Inside bars
    • Engulfing candles
    • Doji formations

Filtering

  • Methods can check for larger trend filters before allowing signals

🧠 Pro Tip: Think of Each Method as a Mini Decision Maker
If you ever catch yourself copying and pasting the same logic, or writing a comment like “Check for trend…” — that’s probably a sign it belongs in its own method.

🔄 void vs. return Methods: What’s the Difference?

When writing methods in NinjaScript (or any C# code), you’ll choose between two types:

Type Purpose
void Executes logic but doesn’t give anything back
return type (e.g., bool, double) Executes logic and returns a value

void Methods: Perform an Action

These are used when you want to do something — like draw on the chart, update a plot, or assign values — but you don’t need a result from the method.

🔧 Example: Drawing a Signal Marker

private void DrawEntryMarker()
{
    Draw.TriangleUp(this, "entry" + CurrentBar, false, 0, Low[0] - TickSize * 5, Brushes.LimeGreen);
}

protected override void OnBarUpdate()
{
    if (CrossAbove(Close, EMA(20), 1))
        DrawEntryMarker();
}

🧠 The DrawEntryMarker() method handles all the drawing — no need to return anything.

return Methods: Give Back a Value

These methods do some calculation or comparison and then return a value that your script can use.

📈 Example: Return a double (Calculation)

private double CalculateRange()
{
    return High[0] - Low[0];
}

protected override void OnBarUpdate()
{
    double range = CalculateRange();

    if (range > 10)
        BackBrushes[0] = Brushes.LightPink;
}

⚖️ Which Should You Use?

If you want to… Use…
Do something visual (draw, update a plot) void
Calculate a value or make a decision return (like bool, double, etc.)

🔁 Bonus Tip: Mix Them!

It’s common to use a return method to make a decision, then call a void method to act on it:

if (IsBullishSignal())
    DrawEntryMarker();

Takeaway:

  • Use void for actions.
  • Use return types for decisions and calculations.
    Both are essential tools to write clean, modular NinjaScript code.

🛠️ Method Examples for NinjaScript

Let’s take everything we’ve learned so far and walk through real method examples you’ll actually use in NinjaTrader.

These are common NinjaScript tasks broken into simple, reusable methods — ranging from basic to more advanced use cases.

✅ Basic Example 1: Method That Returns a Signal

This method checks if the current bar is bullish based on close vs. open.

private bool IsBullishBar()
{
    return Close[0] > Open[0];
}

🧠 Why it’s useful: You can now reuse this logic across multiple conditions:

if (IsBullishBar() && SMA(20)[0] > SMA(20)[1])
    PlotBrushes[0][0] = Brushes.Green;

✅ Basic Example 2: Calculate a Custom Range

This method returns the difference between the current high and low.

private double GetBarRange()
{
    return High[0] - Low[0];
}

You could use this for volatility checks, signal filters, or scaling decisions.

✅ Basic Example 3: Assign a Plot Value

Sometimes your method will perform a calculation and set a value, but not return anything.

private void UpdateSignalPlot()
{
    if (Close[0] > SMA(20)[0])
        Values[0][0] = 1;
    else
        Values[0][0] = 0;
}

Then in OnBarUpdate():

UpdateSignalPlot();

🧠 This is a void method — it performs an action, but doesn’t return a value.

🔄 Advanced Example 1: Method With Parameters

Let’s say you want to create a reusable method to check if any two series have crossed over:

private bool IsCrossover(ISeries<double> series1, ISeries<double> series2)
{
    return CrossAbove(series1, series2, 1);
}

Usage:

if (IsCrossover(Close, EMA(14)))
    Draw.TriangleUp(this, "entry" + CurrentBar, false, 0, Low[0] - TickSize * 5, Brushes.LimeGreen);

🔄 Advanced Example 2: Method That Modifies an Internal Series

If you have a custom Series, you can write to it inside a method:

private void UpdateCustomSeries()
{
    mySignalSeries[0] = Close[0] > SMA(20)[0] ? 1 : 0;
}

This lets you organize your signals cleanly and call UpdateCustomSeries() from OnBarUpdate().

🔄 Advanced Example 3: Encapsulated Logic with Conditional Checks

Let’s say you want to check for both trend and signal conditions:

private bool IsValidBuySetup()
{
    return IsBullishBar() && IsSmaRising() && Volume[0] > SMA(Volume, 20)[0];
}

Takeaway: Start small. Even a one-line method can improve clarity. When in doubt: wrap it in a method.

🚫 Common Beginner Mistakes

Even if you’re comfortable writing basic NinjaScript, it’s easy to make small mistakes when starting to use methods. Here are some of the most common issues — and how to avoid them:

❌ Forgetting to Return a Value

If your method is supposed to return something (like a bool or double), you must include a return statement — or the compiler will throw an error.

// Incorrect
private double CalculateRange()
{
    double range = High[0] - Low[0];
    // return statement missing!
}

// Correct
private double CalculateRange()
{
    return High[0] - Low[0];
}

❌ Using the Wrong Return Type

If your method says it will return a bool, you can’t return a number or string. The data type must match exactly.

// Incorrect
private bool IsReady()
{
    return 1; // ❌ Compiler error: expected bool
}

// Correct
private bool IsReady()
{
    return CurrentBar > 20;
}

❌ Declaring a Method Inside OnBarUpdate()

Methods must be declared outside of any existing method — never nested inside OnBarUpdate() or OnStateChange().

// Incorrect
protected override void OnBarUpdate()
{
    private bool MyMethod() // ❌ You can't do this!
    {
        return true;
    }
}

// Correct
private bool MyMethod()
{
    return true;
}

❌ Misunderstanding Variable Scope

Local variables declared inside one method cannot be accessed from another method.

private void StoreHigh()
{
    double highLevel = High[0];
}

private void CheckHigh()
{
    Print(highLevel); // ❌ Not accessible here!
}

✅ To fix this, use a class-level variable declared outside both methods:

private double highLevel;

private void StoreHigh()
{
    highLevel = High[0];
}

private void CheckHigh()
{
    Print(highLevel); // ✅ Now it works
}

❌ Repeating the Same Logic in Multiple Places

One of the biggest benefits of methods is to avoid repeating yourself. If you’re copying the same logic into multiple spots, extract it into a reusable method instead.

// Instead of repeating:
if (Close[0] > Open[0] && Volume[0] > SMA(Volume, 14)[0]) { ... }
if (Close[0] > Open[0] && Volume[0] > SMA(Volume, 14)[0]) { ... }

// Create a method:
private bool IsStrongBullBar()
{
    return Close[0] > Open[0] && Volume[0] > SMA(Volume, 14)[0];
}

Bottom Line:
Small mistakes can cause compile-time errors — or worse, silent bugs. Start simple, stay organized, and test often.

🧩 Optional: Organizing Utility Methods in a Helper Class

As your scripts grow more complex, it helps to separate out general-purpose utility methods — especially ones you reuse across indicators or strategies.

That’s where a helper class comes in. We will get into this in more detail in the next post.

✅ What’s a Helper Class?

A helper class is a separate, reusable class (often static) that holds common methods you want to access from anywhere.

It’s perfect for:

  • Color and brush utilities (e.g., setting opacity)
  • Custom math or rounding
  • String formatting or tag naming
  • Signal processing logic

🧠 Why Use Helper Classes?

Benefit Description
Code Reuse Write it once, use it in all your scripts
Cleaner NinjaScript Keep your core logic focused (like OnBarUpdate())
Easier Maintenance Fix a bug in one place — not 5 different indicators
Team Collaboration Share a utility file across your team or project

🔧 Example: Brush Utilities in a Static Class

Let’s say you want to reuse your brush opacity helper across all scripts. You could build a static helper class like this:

namespace NinjaTrader.NinjaScript
{
    public static class MdtBrushHelper
    {
        public static Brush ChangeOpacity(Brush baseBrush, int opacityPercent)
        {
            Brush brush = baseBrush.Clone();
            brush.Opacity = opacityPercent * 0.01;
            brush.Freeze();
            return brush;
        }

        public static SolidColorBrush FromArgb(int alpha, Brush baseBrush)
        {
            var solid = (SolidColorBrush)baseBrush;
            return new SolidColorBrush(Color.FromArgb(
                (byte)alpha,
                solid.Color.R,
                solid.Color.G,
                solid.Color.B));
        }
    }
}

Then inside your indicator or strategy:

PlotBrushes[0][0] = MdtBrushHelper.ChangeOpacity(Brushes.Red, 60);

Now you can reuse MdtBrushHelper anywhere in your NinjaScript library.

⚙️ Guidelines for Organizing Helpers

  • Use static for stateless utility methods
  • Group by topic: one helper for math, another for visuals
  • Keep it simple: avoid dependencies on internal script variables

💡 Common Helper Categories

Category Example Methods
Brushes Adjust opacity, blend colors
Signals/Logic IsEngulfing(), IsInsideBar(), etc.
Math RoundToTickSize(), Clamp(), Normalize()
Tags/Text Build unique tag names for draw objects

✅ Final Thoughts

Understanding how to structure and use your own methods (also called functions) is one of the most important skills in NinjaScript. It helps you write code that is:

  • Easier to read
  • Easier to maintain
  • Easier to reuse

Instead of copying and pasting the same logic over and over, you can build small, testable blocks of functionality — and plug them in wherever you need them.

Whether you’re checking for a bullish crossover, calculating a signal strength, or adjusting plot visuals, wrapping that logic into a named method is a habit that will make your coding faster and more scalable.

🚀 What’s Next?

Now that you understand how to build and use methods, the next logical step is applying them to entry and exit logic in your strategies.

But even better — you’ll learn how to centralize your methods in a reusable AddOn utility script. That way, you can store all your favorite functions in one place and reference them across all your indicators and strategies with a single import.

This is the best way to scale your NinjaScript development efficiently — and we’ll show you exactly how to do it in the next post.

🧠 Key Reminders

  • Use methods to simplify OnBarUpdate() and reduce code repetition.
  • Name your methods clearly so they read like English: IsBullishSignal(), GetPullbackStrength(), etc.
  • Use return values when you need an answer; use void when performing an action.
  • Helper classes can take your reusable tools even further across scripts — especially when paired with AddOns.

With a few well-structured methods, you’ll be able to write NinjaScript code that’s not just functional — but clean, powerful, and ready to grow with you

🎉 Prop Trading Discounts

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

Categorized in:

Learn NinjaScript,

Tagged in: