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! 🔄
📚 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
🧩 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 asi
is less than 10.i++
: After each loop, go to the next number (increasei
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 barClose[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.
🔓 break
– Stop 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.
🚫 continue
– Skip 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>
likeClose
,High
, orVolume
- 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>
, orDrawObjects
) - 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 likeClose[i]
orHigh[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