When you’re building indicators or strategies in NinjaScript, you’ll often find yourself needing to repeat an action—like checking the last 10 bars for a pattern, scanning through a list of values, or cleaning up old draw objects. That’s where loops come in.

Loops let you automate repetitive tasks inside your code, saving you from writing the same line over and over. Whether you’re analyzing historical bars, looping through a list of calculated values, or even scanning for old annotations—loops are the backbone of doing anything over time in NinjaTrader.

But not all loops are created equal. You’ve got:

  • for loops, great for bar-by-bar indexing 👣
  • while loops, perfect for open-ended logic 🌀
  • foreach loops, ideal for lists and collections 📦

In this post, we’ll break down how each loop works, when to use which one, and common mistakes to avoid—so you can write clean, efficient, and powerful NinjaScript code. Let’s loop in! 🔄

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

🧩 The for Loop – Your Go-To for Bar Iteration

If you’re new to coding in NinjaScript, one of the first tools you’ll want to master is the for loop. Why? Because when you want to look back at previous bars—whether that’s 5, 10, or 500 bars ago—you need a structured way to repeat actions in your code.

A for loop lets you do exactly that: run the same piece of logic over and over again, just with different bar indexes or data points.

🧠 What Does a for Loop Actually Do?

A for loop is like saying:

“Start here, do this thing, then move to the next one, and keep going until I say stop.”

In trading terms, imagine walking backwards through your candles—checking something at each one. Maybe you’re looking for the last time price closed above 4200, or maybe you’re summing up volume across 20 bars. A for loop is your way to step through those bars one by one.

🧱 The Basic Structure

Here’s the most basic form of a for loop:

for (int i = 0; i < 10; i++)
{
    // Code that runs each time
}

Let’s break it down:

  • int i = 0: Start counting at 0 (this is your index).
  • i < 10: Keep looping as long as i is less than 10.
  • i++: After each loop, go to the next number (increase i by 1).

This will run the code inside the { ... } ten times, with i going from 0 to 9.

🔍 A Real Example in NinjaScript

Let’s look at a simple real-world scenario: check if the last 10 bars closed above a certain price level:

if (CurrentBar < 10) return; // Don't loop if there aren't enough bars

for (int i = 0; i < 10; i++)
{
    if (Close[i] > 4200)
    {
        Print("Bar " + i + " closed above 4200");
    }
}

In NinjaScript:

  • Close[i] means “the close price from i bars ago“.
  • Close[0] = the current bar
  • Close[1] = the previous bar
  • and so on…

Let’s say the close prices were:

Bar 0 = 4190.25
Bar 1 = 4215.75
Bar 2 = 4207.50
Bar 3 = 4198.00
Bar 4 = 4189.25
Bar 5 = 4222.75
Bar 6 = 4165.00
Bar 7 = 4202.50
Bar 8 = 4179.00
Bar 9 = 4195.25

The output would be:

Bar 1 closed above 4200
Bar 2 closed above 4200
Bar 5 closed above 4200
Bar 7 closed above 4200

🧨 What About break and continue?

These two little keywords help you control your loop even more.

🔓 breakStop the loop completely

Sometimes, you just want to find the first match and then stop searching. You can do that with break.

for (int i = 0; i < 10; i++)
{
    if (Close[i] > 4200)
    {
        Print("First bar above 4200 was: " + i);
        break; // Exit the loop immediately
    }
}

This will only print the first match, and then exit the loop.

🚫 continueSkip this loop, move to the next

If you want to skip over certain bars without stopping the whole loop, use continue.

for (int i = 0; i < 10; i++)
{
    if (Volume[i] < 1000)
        continue; // Skip low-volume bars

    Print("High-volume bar " + i + " closed at " + Close[i]);
}

This skips any bar with low volume and only prints results for the rest.

⏪ Looping Backward Instead of Forward

Sometimes, you’ll want to loop from newest to oldest—this is called looping “backward.”

for (int i = Count - 1; i >= 0; i--)
{
    // Do something from the last bar back to the first
}

You’ll usually do this when working with full data sets (like custom lists or draw objects), or when you’re cleaning things up.

For regular bar-based logic, though, looping forward from i = 0 is the easiest way to start.

✅ When Should You Use a for Loop?

Use a for loop when:

  • You want to scan through previous bars on the chart
  • You’re analyzing data from a Series<double> like Close, High, or Volume
  • You need exact control over how many times the loop runs (like last 5 bars, 20 bars, etc.)
  • You want flexibility to break or skip mid-loop (break, continue)

🔁 The while Loop – Use with Caution

The while loop is a little different from the for loop. Instead of running a set number of times, it keeps running as long as a condition is true. That makes it more flexible—but also riskier if you’re not careful.

🧠 What Does a while Loop Do?

A while loop says:

“Keep doing this thing over and over until the condition becomes false.”

It’s like saying, “Keep moving forward until you hit a red candle,” or “Keep checking bars until I find one with a wick longer than the body.”

🧱 Basic Structure

while (someCondition)
{
    // Repeat this code
}

Unlike a for loop, there’s no automatic counter. You have to manually track and update any values inside the loop—or it’ll run forever.

⚠️ Be Careful! Infinite Loops = Script Crash

If the condition never becomes false, NinjaTrader will get stuck. That’s called an infinite loop, and it will freeze or crash your script.

You must make sure your loop has a way to stop.

✅ A Safe while Loop Example

Let’s say you want to scan backward and find the first bar with a close below 4000:

int i = 0;

while (i < 50) // Limit how far back we check
{
    if (Close[i] < 4000)
    {
        Print("Found a close below 4000 at bar: " + i);
        break; // Stop the loop
    }

    i++; // Don't forget to move to the next bar!
}

What’s happening:

  • i = 0 starts at the current bar
  • We keep checking back until we hit 50 bars
  • If the close is under 4000, we print it and break the loop
  • If we forget i++, the loop never stops = bad 😬

🚨 Common Beginner Mistakes

  • Forgetting to update your counter (i++)
  • Writing a condition that always stays true
  • Not limiting the loop with a max value (like i < 50)

Even if you think your condition is solid, always give your loop an escape hatch. NinjaTrader doesn’t like runaway code.

🤔 When Should You Use while?

Use while only when:

  • You don’t know in advance how many times something will repeat
  • You’re scanning backwards until a condition is met
  • You need to wait for something to change in real-time logic (rare in indicators)

In most NinjaScript cases, a for loop will be better. But if your logic depends on an uncertain condition, while gives you the freedom—just don’t forget the leash.

🔄 The foreach Loop – Iterate Like a Pro

Unlike for and while, which are usually used with bar data like Close[i], the foreach loop is made for collections—things like List<double>, Dictionary<string, double>, or even NinjaTrader’s DrawObjects. If you’ve ever built a list of values and wanted to go through each one without worrying about indexes, this is the loop for you.

🧠 What Is a foreach Loop?

A foreach loop says:

“For every item in this group, do something.”

It’s like going through a grocery list. You’re not counting how many items there are—you’re just grabbing each one in order and doing something with it.

🧱 Basic Structure

Here’s the syntax:

foreach (var item in collection)
{
    // Do something with item
}

More specific example:

List<double> atrList = new List<double>() { 5.2, 4.9, 6.1 };

foreach (double atr in atrList)
{
    Print("ATR value: " + atr);
}

You don’t need to manage indexes (i = 0, i++)—you just work with the items directly. Cleaner and safer in many cases.

📦 Practical Use Case: Loop Through a List of Values

Let’s say you’ve stored recent RSI values in a list and want to calculate the average:

double sum = 0;
List<double> rsiList = new List<double>() { 50.2, 47.8, 49.1 };

foreach (double rsi in rsiList)
{
    sum += rsi;
}

double avg = sum / rsiList.Count;
Print("Average RSI: " + avg);

🎯 Use Case: Loop Through DrawObjects

You can also use foreach to scan and interact with draw objects placed on the chart:

foreach (DrawingTool tool in DrawObjects.ToList())
{
    if (tool.Tag.Contains("MyCustomTag"))
    {
        tool.Pen.Color = Brushes.Red;
    }
}

This is great for managing chart annotations—coloring, hiding, or removing them.

⚠️ Don’t Use foreach with Bar Data!

This is a common mistake. You can’t do this:

foreach (double c in Close) // ❌ Will not compile

Close is a Series<double>, not a List. Stick to for (int i = 0; i < Count; i++) for bar-based data.

✅ When Should You Use foreach?

Use foreach when:

  • You’re working with List<T>, Dictionary<K, V>, or other .NET collections.
  • You don’t need the index—just the value.
  • You want cleaner syntax for things like object cleanup or value summaries.

🎯 Choosing the Right Loop

Now that you’ve seen how for, while, and foreach loops work, the big question is:

Which one should you use—and when?

Choosing the right loop matters because it impacts both readability and performance in NinjaScript. Let’s break it down with some simple guidance.

🔘 Use a for loop when:

  • You’re working with bar data (Close[i], High[i], etc.)
  • You need control over how many times to loop
  • You want to use or compare bar indexes directly (like detecting patterns over last N bars)
  • You’re okay managing loop counters (i = 0; i < N; i++)

Best all-around choice for most NinjaScript tasks.

🔘 Use a while loop when:

  • You don’t know how many iterations you’ll need
  • You’re scanning until a specific condition is met
  • You’re okay manually controlling the counter
  • You add a safety condition like i < 50 to avoid infinite loops

⚠️ Powerful but risky — use only when for doesn’t give you enough flexibility.

🔘 Use a foreach loop when:

  • You’re working with collections (like List<T>, Dictionary<K,V>, or DrawObjects)
  • You don’t care about the index—just the item
  • You want cleaner syntax and less error-prone iteration

🚫 Never use foreach to loop over bar series like Close, Open, or Volume.

🧭 Keep in Mind

These aren’t hard rules—they’re guidelines. In programming, there’s almost always more than one way to solve a problem. What matters is that your code:

  • Does what you expect
  • Is easy to read and understand
  • Runs efficiently inside NinjaTrader’s real-time environment

As you get more comfortable with NinjaScript, you’ll start to mix and match loop types based on your own coding style and what feels most natural to you.

🧼 Common Pitfalls and How to Avoid Them

Loops are powerful—but if you’re not careful, they can crash your script, slow down your charts, or give you bad signals. Here are the most common mistakes traders make when using loops in NinjaScript—and how to stay out of trouble.

1. Forgetting to Exit a while Loop

int i = 0;
while (Close[i] > 4000)
{
    // Missing i++ = infinite loop!
}

Why it’s bad:
This will run forever because i never increases. NinjaTrader will freeze or crash.

Fix it:

while (i < 50 && Close[i] > 4000)
{
    i++;
}

2. Looping Before There’s Enough Data

If you try to access Close[10] when only 5 bars have loaded, you’ll get an error.

Always check this first:

if (CurrentBar < 20) return;

This prevents your code from running until you have enough historical bars to safely loop over.

3. Using foreach on Bar Series

foreach (double price in Close) { } // ❌ This won't compile

You can’t use foreach directly on NinjaTrader’s Series<T> objects like Close, High, or Volume.

Use a for loop instead:

for (int i = 0; i < 20; i++)
{
    double price = Close[i];
}

4. Forgetting to Reset Temporary Variables

If you’re using a variable like int barsAgo = -1; inside OnBarUpdate(), be sure you reset it every time the method is called. Otherwise, old values might carry over.

✅ Best practice:

int barsAgo = -1;

for (int i = 1; i < 50; i++)
{
    if (Close[i] < 4000)
    {
        barsAgo = i;
        break;
    }
}

5. Writing Too Much Logic Inside Loops

It’s tempting to cram everything into one giant loop, but this makes code hard to read and debug.

✅ Break things out into helper functions or clearly label blocks:

for (int i = 0; i < 20; i++)
{
    bool isSpike = High[i] - Close[i] > 10;
    bool isVolumeOK = Volume[i] > 1000;

    if (isSpike && isVolumeOK)
        Draw.Dot(this, "spike" + i, true, i, High[i], Brushes.Orange);
}

Avoiding these mistakes will save you hours of frustration and keep your scripts clean, fast, and stable.

Final Thoughts

Loops are one of the most important tools in your NinjaScript toolbox. Whether you’re scanning for patterns, tracking past signals, managing draw objects, or building complex logic—for, while, and foreach give you the power to repeat, check, and build.

To recap:

  • 🧩 Use **for** loops when working with bar-based data like Close[i] or High[i]. It’s your safest and most versatile loop in NinjaTrader.
  • 🔁 Use **while** loops only when you need to repeat something until a condition is met—but always give it an exit!
  • 🔄 Use **foreach** loops when working with collections like lists or draw objects—never bar series.

And remember: in programming, there’s rarely just one right way to write a loop. What matters most is that your logic is clear, efficient, and does what you expect.

The more you experiment, test, and build, the more natural looping will become. So fire up the NinjaScript Editor, drop in a for loop, and start exploring your charts in ways you never could before.

👨‍💻 Happy coding—and may your conditions always be true (but not forever)! 🔄✨

🎉 Prop Trading Discounts

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

Categorized in:

Learn NinjaScript,

Tagged in: