In NinjaScript, the built-in tools like Series<T> and Values[] are powerful — but sometimes you need more control over your data.

Maybe you want to:

  • Track a custom sequence of highs and lows 🔢
  • Store session-specific information 📅
  • Manage dynamic conditions across multiple bars or timeframes 🔄

That’s where Lists, Dictionaries, and Arrays come in. These C# structures give you a flexible, powerful way to handle historical data exactly the way you need for advanced custom indicators and strategies.

In this guide, we’ll break down:

  • 📋 How Lists help manage growing, changing data
  • 🗂️ How Dictionaries store and recall custom information easily
  • 🔢 How Arrays offer super-fast, fixed-size data storage

By the end, you’ll know when to use each — and how to avoid common mistakes that trip up even experienced NinjaScript coders.

Let’s dive in! 🚀

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

🔢 Arrays in NinjaScript

🧱 What Is an Array?

At its simplest, an array is like a row of boxes 📦📦📦📦📦.
Each box can hold one value — and each box is numbered starting at 0.

You use arrays when you want to store a group of values of the same type (like a group of numbers, booleans, or text).

In NinjaScript (and C#), here’s how you create an array that holds five decimal numbers (called doubles):

double[] recentHighs = new double[5];

Key Points:

  • double[] → The array will hold doubles (decimal numbers)
  • recentHighs → This is the name you gave the array
  • new double[5] → You are making five slots (positions 0 to 4)

🏗️ How Arrays Work

Every array:

  • Has fixed size — once created, it cannot grow or shrink
  • Has indexes — numbering starts at 0
  • Stores only one type of value (all doubles, or all ints, etc.)

Example:
If you write recentHighs[2] = 4200.5;, you’re putting the number 4200.5 into the third slot (index 2).

🚀 Step 1: Create and Fill an Array (First Values)

When you first create an array, all the slots are empty (default value = 0.0 for doubles).
Before you can “shift” or “compare” anything, you need to fill it with real data.

Example of filling the array for the first time with the most recent High prices:

private double[] recentHighs = new double[5]; // 5 slots to hold highs

protected override void OnBarUpdate()
{
    if (CurrentBar < recentHighs.Length)
    {
        // Still filling the array for the first time
        recentHighs[CurrentBar] = High[0];
    }
}

What’s happening here:

  • On the very first bar, CurrentBar == 0, we set recentHighs[0] = High[0]
  • On the second bar, CurrentBar == 1, we set recentHighs[1] = High[0]
  • And so on, until all 5 slots are filled

This way, you build your history before doing anything complicated.

🔄 Step 2: Updating the Array as New Bars Come In

After you’ve filled the array once, you now want to keep it updated with the most recent values.

Since arrays are fixed size, you need to:

  1. Shift the old values backward
  2. Insert the newest value at the front

Example of shifting and updating:

protected override void OnBarUpdate()
{
    // First, fill the array until full
    if (CurrentBar < recentHighs.Length)
    {
        recentHighs[CurrentBar] = High[0];
        return;
    }

    // After it's full, shift all values back by one slot
    for (int i = recentHighs.Length - 1; i > 0; i--)
    {
        recentHighs[i] = recentHighs[i - 1];
    }

    // Insert the newest high at the front (slot 0)
    recentHighs[0] = High[0];
}

What’s happening now:

  • Slot 4 becomes slot 3
  • Slot 3 becomes slot 2
  • Slot 2 becomes slot 1
  • Slot 1 becomes slot 0
  • Then the newest High is put in slot 0

This keeps the array always holding the last 5 Highs, newest first!

✏️ How to Change a Specific Value in an Array

At any time, you can manually update a value by specifying the index:

recentHighs[2] = Close[0]; // Replace the third-highest slot with today's Close

📈 Example: Finding the Highest Value in the Array

Let’s say you want to find the highest value in the array:

double maxHigh = recentHighs[0];

for (int i = 1; i < recentHighs.Length; i++)
{
    if (recentHighs[i] > maxHigh)
        maxHigh = Math.Max(maxHigh, recentHighs[i]);
}

// Now maxHigh holds the highest value from the recentHighs array

✅ This loop checks each slot one-by-one, keeping track of the biggest number it finds.

⚠️ Common Mistakes Beginners Make

Mistake What Happens How to Fix It
❌ Accessing a wrong index (like recentHighs[5] when you only have [0] to [4]) Runtime Error: “Index was outside the bounds of the array” Always stay inside 0 to Length - 1
❌ Forgetting to fill the array before using it Wrong calculations or using 0.0 default values Use CurrentBar to control when to fill vs update
❌ Not shifting before inserting New values overwrite old ones incorrectly Always shift array elements before adding the new value
❌ Never clearing old data when needed Bad or outdated data stays inside Use Array.Clear(recentHighs, 0, recentHighs.Length); to reset

🧹 Clearing an Array (When You Need to Start Over)

Sometimes you want to wipe all the values clean — for example, at the start of a new session.

You can reset the whole array back to default (0.0 for doubles) like this:

Array.Clear(recentHighs, 0, recentHighs.Length);

✅ All the slots from [0] to [4] will be wiped clean and ready for new data!

🚀 Quick Summary of Arrays

  • Arrays are fixed-size, indexed containers for values
  • You must fill them first before you can shift or update them
  • You must manually manage the shifting of old values
  • Arrays are fast and memory-efficient — perfect when you know exactly how much data you need to track
  • Always be careful about indexes and current bar logic

✅ Now you really understand what arrays are, how they work, and how to manage them properly in NinjaScript!

📋 Lists: Flexible and Dynamic

🧱 What Is a List?

A List is very similar to an array — it holds multiple values of the same type.
BUT:

  • Unlike arrays, Lists can grow and shrink whenever you want! 🚀
  • You don’t have to know how many values you need in advance.

Think of a List as a flexible container 🛍️ — you can keep adding new things, removing old things, and changing whatever you want easily.

🛠️ How to Create a List

In NinjaScript (and C#), here’s how you create a List that holds doubles:

List<double> recentHighs = new List<double>();

Key Points:

  • List<double> → The list will hold doubles (decimal numbers)
  • recentHighs → This is the name you gave your list
  • new List<double>() → Creates an empty list that you can fill later

No size is needed! It starts empty and grows when you add things.

✍️ How to Add Items to a List

You use .Add() to insert a new item at the end of the List:

recentHighs.Add(High[0]);

What this does:

  • Adds the current bar’s High price to the end of the list.
  • You can keep calling .Add() — it grows automatically!

🔄 Managing the Size of a List

Because Lists grow forever unless you manage them, you often want to limit how big they get.

For example, if you only want to keep the last 5 highs, you can remove the oldest value after adding a new one:

recentHighs.Add(High[0]); // Add newest value

if (recentHighs.Count > 5) // More than 5 items?
{
    recentHighs.RemoveAt(0); // Remove the oldest (first) item
}

What’s happening:

  • Newest high goes at the end.
  • If the list has grown too big, remove the very first item (oldest value).

This way, your List always contains only the latest 5 highs, automatically!

🖊️ How to Update a Value in a List

You can change any value in a List by indexing it (just like an array):

recentHighs[2] = Close[0]; // Change the third-highest value to the current Close

✅ Indexes work the same way:

  • First item is [0]
  • Second item is [1], etc.

📈 Example: Finding the Highest Value in a List

You can loop through a List exactly like an array:

double maxHigh = recentHighs[0];

for (int i = 1; i < recentHighs.Count; i++)
{
    if (recentHighs[i] > maxHigh)
        maxHigh = Math.Max(maxHigh, recentHighs[i]);
}

✅ This will give you the highest number in the List, no matter how many items are in it.

🧹 How to Clear a List

If you want to wipe the entire list (start over fresh):

recentHighs.Clear();

✅ After .Clear(), the List will have zero items inside, ready to refill.

⚠️ Common Mistakes Beginners Make

Mistake What Happens How to Fix It
❌ Forgetting to limit the List size The List grows forever and uses a lot of memory Add if (recentHighs.Count > X) and remove old values
❌ Indexing the wrong position Runtime Error: “Argument out of range” Always check Count before accessing
❌ Forgetting .Add() List stays empty — no data to work with Make sure .Add() is called inside OnBarUpdate()
❌ Mixing up indexes Wrong values used for comparisons Remember: [0] = first (oldest unless you manage insertion order)

🤔 When Should You Use a List Instead of an Array?

Use a List When… Use an Array When…
You don’t know exactly how many items you’ll have You know exactly how many slots you need
You want to dynamically add/remove items You want ultra-fast fixed-size storage
You want simple, automatic growing without shifting You’re okay manually managing updates and shifts

🧠 Important List Functions to Remember

Function What It Does
.Add(item) Adds a new item to the end
.RemoveAt(index) Removes the item at a specific position
.Count Tells you how many items are in the list
.Clear() Wipes the list back to empty

🚀 Quick Summary of Lists

  • Lists are dynamic — they grow and shrink automatically
  • Easier to manage than arrays for changing amounts of data
  • You must control the size if you only want to track a certain number of recent values
  • Lists are slightly slower than arrays, but much more flexible for 99% of NinjaScript uses

✅ Now you know what Lists are, how to create them, how to update them, and how to manage their size properly in NinjaScript!

🗂️ Dictionaries: Keyed Data Tracking

🧱 What Is a Dictionary?

A Dictionary is a special kind of container that holds pairs of values:

  • A key (like a label)
  • A value (the data you want to store)

Think of it like a filing cabinet 🗄️:

  • Each folder has a name (the key)
  • Inside each folder is a piece of data (the value)

💡 Unlike Arrays and Lists — which use numbered indexes like [0], [1], etc. —
Dictionaries use meaningful labels that you define (like "Monday" or Time[0]).

🛠️ How to Create a Dictionary

Here’s how to create a Dictionary that tracks decimal values (double) using strings as the keys:

Dictionary<string, double> dayHighs = new Dictionary<string, double>();

What this means:

  • The key is a string (like “Monday” or “RTH”)
  • The value is a double (price, level, range, etc.)
  • You can now add, look up, or remove data based on any key you choose

✍️ How to Add or Update Values

To add or update values in a Dictionary, you use the key like this:

dayHighs["Monday"] = High[0]; // Add or update the high for Monday

✅ If “Monday” doesn’t exist yet — it’s added
✅ If it does exist — the value is updated

You can also use variables as keys:

string sessionName = Bars.Session.Name;
dayHighs[sessionName] = High[0];

This lets you track values per session, per bar, or per custom label.

🔎 How to Check If a Key Exists

Before accessing a value, it’s good practice to check if the key already exists:

if (dayHighs.ContainsKey("Monday"))
{
    double high = dayHighs["Monday"];
}

⚠️ Without this check, trying to access a missing key will cause an error.

🔄 Common Use Case: Store Values Per Day

Let’s say you want to track the total range for each trading day:

string dateKey = Time[0].Date.ToString();

if (!dayHighs.ContainsKey(dateKey))
    dayHighs[dateKey] = High[0] - Low[0];
else
    dayHighs[dateKey] += High[0] - Low[0]; // add to previous value

✅ This stores the daily range using the date as a key
✅ On each bar, if the day already exists, it adds to the total

📉 Removing a Value

If you need to delete something from a Dictionary:

dayHighs.Remove("Monday");

This removes the “Monday” entry completely.

🧹 Clearing the Whole Dictionary

Just like Lists, you can reset everything:

dayHighs.Clear();

Useful if you want to start over at the beginning of a new week, session, or strategy cycle.

🧠 Practical Key Types You Can Use

Key Type Example Use Case
string "PreMarket", "LondonOpen" Custom session names
DateTime Time[0].Date Daily or hourly tracking
int CurrentBar or BarsSinceEntryExecution() Bar-by-bar tracking
double Close[0] Uncommon, but possible

⚠️ Common Mistakes Beginners Make

Mistake What Happens How to Fix It
❌ Accessing a key that doesn’t exist Error: “Key not found” Use .ContainsKey() before reading
❌ Using floating-point values (like Time[0]) directly Keys mismatch due to minor differences Use .Date or .ToString("HH:mm") to clean it
❌ Letting the dictionary grow forever High memory usage Clear it periodically, or use logic to prune it
❌ Adding the same key twice unnecessarily Overwrites silently Use .ContainsKey() to control this

🔍 Example: Per-Session Tracking Dictionary

Want to track the highest Close for each session?

string sessionKey = Bars.Session.Name;

if (!dayHighs.ContainsKey(sessionKey))
    dayHighs[sessionKey] = Close[0];
else if (Close[0] > dayHighs[sessionKey])
    dayHighs[sessionKey] = Close[0];

✅ Stores or updates the highest Close seen during that session

🧠 Key Dictionary Methods and Properties

Function What It Does
.Add(key, value) Adds a new key-value pair (error if key exists)
[key] = value Adds or updates a key’s value
.ContainsKey(key) Checks if a key already exists
.Remove(key) Deletes a key and its value
.Clear() Empties the whole dictionary
.Count Tells you how many items are in it

🚀 Quick Summary of Dictionaries

  • Dictionaries store data as key-value pairs
  • Keys let you label and organize your values logically
  • Ideal for tracking daily values, per-session data, custom calculations, and more
  • You must manage key existence and prevent uncontrolled growth

✅ Now you know how to use Dictionaries to build smarter, more flexible indicators and strategies in NinjaScript!

🧪 Real-World Examples: Arrays, Lists, and Dictionaries in Action

Now that you understand how to use these data structures, let’s look at practical ways to apply them in NinjaScript.

Each of the following examples includes:

  • 🎯 A use case (why it’s useful in trading)
  • 🛠️ The structure used (array, list, or dictionary)
  • ✅ The core logic to make it work

📊 Example 1: Custom Volatility Tracker (Array)

🎯 Goal: Track the range of the last 5 bars and calculate the average range
🛠️ Uses: double[] array

private double[] recentRanges = new double[5];

protected override void OnBarUpdate()
{
    if (CurrentBar < recentRanges.Length)
    {
        recentRanges[CurrentBar] = High[0] - Low[0];
        return;
    }

    for (int i = recentRanges.Length - 1; i > 0; i--)
        recentRanges[i] = recentRanges[i - 1];

    recentRanges[0] = High[0] - Low[0];

    double avgRange = 0;
    for (int i = 0; i < recentRanges.Length; i++)
        avgRange += recentRanges[i];

    avgRange /= recentRanges.Length;

    Print("Average 5-bar range: " + avgRange);
}

✅ Good for quick bar-by-bar calcs like ATR alternatives

🪜 Example 2: Dynamic Pullback Tracking (List)

🎯 Goal: Track custom pullbacks and reset when trend breaks
🛠️ Uses: List<double>

private List<double> pullbackLows = new List<double>();

protected override void OnBarUpdate()
{
    // Add newest low
    pullbackLows.Add(Low[0]);

    // Cap the list to the last 10 bars
    if (pullbackLows.Count > 10)
        pullbackLows.RemoveAt(0);

    // Detect a trend shift (simple rule)
    if (Close[0] > Highs[1])
    {
        pullbackLows.Clear(); // reset if new breakout
    }

    // Optional: check for lowest low in the pullback
    double minLow = pullbackLows.Min();
    Draw.Dot(this, "PullbackLow" + CurrentBar, false, 0, minLow, Brushes.Red);
}

✅ Excellent for flexible, event-driven state tracking

📅 Example 3: Session Range Memory (Dictionary)

🎯 Goal: Store and recall total session range per day
🛠️ Uses: Dictionary<string, double>

private Dictionary<string, double> sessionRanges = new Dictionary<string, double>();

protected override void OnBarUpdate()
{
    string sessionKey = Time[0].Date.ToShortDateString();

    double currentRange = High[0] - Low[0];

    if (!sessionRanges.ContainsKey(sessionKey))
        sessionRanges[sessionKey] = currentRange;
    else
        sessionRanges[sessionKey] += currentRange;

    Print("Today's session range so far: " + sessionRanges[sessionKey]);
}

✅ Great for daily stats, signal filtering, and volume/range memory

🔁 Example 4: Reversal Tagging System (Array + Dictionary)

🎯 Goal: Track previous reversal prices and assign them custom names
🛠️ Uses: double[] for recent reversals, Dictionary<string, double> for tagging them

private double[] reversalLevels = new double[3];
private Dictionary<string, double> tagMap = new Dictionary<string, double>();

protected override void OnBarUpdate()
{
    if (/* custom reversal condition */ Close[0] > Open[0] && Close[0] > Close[1])
    {
        // Shift reversal levels
        for (int i = reversalLevels.Length - 1; i > 0; i--)
            reversalLevels[i] = reversalLevels[i - 1];

        reversalLevels[0] = High[0];

        // Label each level with a tag
        tagMap["Rev1"] = reversalLevels[0];
        tagMap["Rev2"] = reversalLevels[1];
        tagMap["Rev3"] = reversalLevels[2];

        foreach (var tag in tagMap)
            Draw.Text(this, tag.Key + CurrentBar, tag.Key + ": " + tag.Value.ToString("0.00"), 0, tag.Value, Brushes.Gold);
    }
}

✅ Combines fast updating (array) with easy labeling (dictionary)

🔄 Example 5: Rolling Bias Score (List)

🎯 Goal: Create a bias score based on conditions met across the last 20 bars
🛠️ Uses: List<int>

private List<int> biasScore = new List<int>();

protected override void OnBarUpdate()
{
    int score = 0;

    if (Close[0] > Open[0]) score += 1;
    if (Close[0] > SMA(Close, 10)[0]) score += 1;
    if (RSI(Close, 14, 3)[0] > 50) score += 1;

    biasScore.Add(score);

    if (biasScore.Count > 20)
        biasScore.RemoveAt(0);

    double avgBias = biasScore.Average();

    if (avgBias >= 2.5)
        Draw.ArrowUp(this, "BiasUp" + CurrentBar, true, 0, Low[0] - 1 * TickSize, Brushes.Green);
}

✅ Makes it easy to track aggregated logic across recent bars

🧠 Final Thoughts

Working with Arrays, Lists, and Dictionaries in NinjaScript might feel like “just programming stuff” at first — but once you start using them in your indicators and strategies, you’ll realize they are the backbone of creative logic and custom signal building.

Arrays give you raw speed and control — great for fixed-size, bar-by-bar analysis.
Lists help you build flexible, evolving conditions — perfect for tracking recent setups or state transitions.
Dictionaries let you track and label complex data across time, sessions, or any condition you define — opening the door to more intelligent logic.

💡 Think of these tools like building blocks: You don’t need all of them in every script. But if you know when and why to use each one, you unlock a new level of clarity and precision in your trading logic.

📚 Keep practicing by:

  • Rebuilding one of your existing indicators using a List or Dictionary
  • Adding session-based logic to an array system
  • Tracking your trades or setups using labeled keys

You don’t need to become a master overnight. Just start applying one new idea at a time — and you’ll get better, faster, and more confident with each new build. 🚀

🎉 Prop Trading Discounts

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

Categorized in:

Learn NinjaScript,

Tagged in: