If you’ve written even a little bit of NinjaScript, you’ve probably used a draw object.

They’re one of the most common tools in the platform — and for good reason. Drawing on the chart is straightforward, visual, and incredibly helpful. Whether you’re marking an entry with a dot, showing confirmation text above a candle, or placing arrows where signals fire, draw objects make your code easier to see and understand.

Most traders and coders start using draw tools early on, but few take the time to learn how powerful they can really be. Used well, they can help you:

  • Debug your strategies in real time
  • Visually confirm signals or setups
  • Build more readable and testable indicators

In this post, we’re going to cover:

  • How the Draw.* methods work and how to use them effectively
  • What the global DrawOnPricePanel setting controls
  • How the DrawObjects collection lets you access, modify, or remove draw tools
  • Tips for tagging, styling, and organizing your visuals

By the end, you’ll be able to turn any logic into a visual — and build indicators or strategies that are easier to test, debug, and improve. Let’s dive in ✏️📉

👉 Save this official NinjaTrader Help Guide link:

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

⚙️ Global Setting: DrawOnPricePanel (and How It Affects Everything)

Before you even start drawing on the chart, there’s one setting that quietly controls where your visuals show up: DrawOnPricePanel.

This is a global property available in every indicator, and it determines whether your draw objects (dots, lines, text, arrows, etc.) appear:

  • On the price panel (where your candles or price bars are), or
  • On the indicator panel (where your plots and calculations appear, like RSI or MACD)

By default, NinjaTrader sets this to true, which means all draw objects are shown on the main price panel. That’s usually what you want when marking entries, breakouts, or price-based setups.

But if you’re building a multi-panel indicator — like a custom oscillator — you may want your drawings to stay in the panel where your logic lives, not overlaid on price. That’s where setting DrawOnPricePanel = false; comes in.

🧪 Example:

protected override void OnStateChange()
{
    if (State == State.SetDefaults)
    {
        DrawOnPricePanel = false; // Keeps draw objects in the indicator panel
    }
}

This simple setting gives you more control over where your visual tools are rendered — which is especially important when building clean, organized visuals across multiple panels.

🧰 Understanding the DrawObjects Collection

Every time you use a Draw.* method — or even manually draw something on the chart — NinjaTrader stores that object in a special collection called DrawObjects.

This collection contains every active draw object on the chart tied to your script’s context. That includes:

  • Script-generated objects (like Draw.Dot(), Draw.Text())
  • Manually drawn objects (like lines or zones placed by hand)

You can access, count, or loop through these objects to inspect or modify them in real time.

🔍 What You Can Do with DrawObjects

Access by tag:

var line = DrawObjects["myLineTag"];

Count how many draw objects exist:

int total = DrawObjects.Count;

Loop through all draw objects (safely):

foreach (DrawingTool draw in DrawObjects.ToList())
{
    // Do something
}

⚠️ Why Use .ToList()?

Although DrawObjects is a live, dynamic collection, calling .ToList() creates a snapshot copy that’s safe to iterate over.

Without it, the collection could change mid-loop (e.g., if a new draw object is added or removed), which may cause runtime errors.

🧠 Things to Keep in Mind

  • Manual draw objects might not be added before your indicator begins processing — especially during reloads.
  • Iterating through a large number of draw objects can slow things down, especially on historical data.
  • Objects are disposed automatically after your script reaches State.Terminated (i.e., when the chart is closed or the indicator is removed).

🧪 Use Cases for DrawObjects

  • Update or modify existing draw objects by tag
  • Check if a line was drawn manually or by script
  • Track global drawing tools applied across multiple charts
  • Build logic around what’s already visible on the chart

🔧 Example: Filtering Script vs. User Drawn Objects

foreach (DrawingTool draw in DrawObjects.ToList())
{
    if (draw is DrawingTools.Line line)
    {
        if (line.IsUserDrawn)
            Print("User drew: " + line.Tag);
        else
            Print("Script drew: " + line.Tag);
    }
}

This gives you powerful insight into what’s happening visually on your chart — whether you put it there manually or your script did.

🧱 The Basics of Draw.* Methods

Now that you know where draw objects live (DrawObjects) and how to manage their placement (DrawOnPricePanel), let’s look at how you actually create them.

NinjaTrader provides a set of built-in Draw.* methods that let you place visual markers directly on your chart — from simple text to arrows, lines, and more.

Here’s the general pattern you’ll see across most of them:

🧪 Basic Syntax Example

Draw.Text(this, "signalTag", "Signal Triggered", 0, High[0] + 2, Brushes.White);

🔍 What Each Parameter Means

Parameter Description
this Refers to the current NinjaScript context — usually your indicator.
"signalTag" A tag that uniquely identifies the object. You’ll use this to update or remove it later.
"Signal Triggered" The text or label to show (depends on the draw type).
0 The number of bars ago to draw the object (0 = current bar).
High[0] + 2 The price level to place the object (above the high in this example).
Brushes.White The color or brush used to style the object.

🧠 Where to Use Draw.* Methods

These methods are typically called inside:

  • OnBarUpdate() – for dynamic, per-bar logic
  • OnStateChange() – for drawing things once (like labels or static references)
  • OnRender() – for more advanced custom drawing (not covered in this post)

✅ Return Value: The Drawing Tool Itself

Most Draw.* methods return a specific drawing tool object, like DrawingTool.Text or DrawingTool.Line. That means you can immediately customize the result:

var text = Draw.Text(this, "msg", "Hi", 0, Close[0], Brushes.Yellow);
text.TextAlignment = TextAlignment.Center;
text.IsLocked = true;

We’ll cover more about customizing these objects in a later section. First, let’s walk through the most common draw types you’ll use on a regular basis.

🧪 Common Draw Types You’ll Actually Use

There are many Draw.* methods in NinjaScript, but most indicators and strategies rely on just a few. Below are the core draw tools you’ll actually use — with clear syntax and examples for each.

✏️ Draw.Text()

What it does:
Displays text on the chart at a specific bar and price level. Great for labeling events like signals, invalidations, or bar conditions.

Syntax:

Draw.Text(
    NinjaScriptBase owner,
    string tag,
    string text,
    int barsAgo,
    double y,
    Brush textBrush
);

Example:

Draw.Text(this, "entryText_" + CurrentBar, "Buy", 0, Low[0] - 2, Brushes.Green);

🟡 Draw.Dot()

What it does:
Draws a small dot at a specific location on the chart. Commonly used to mark pivots, signal bars, or confirmation points.

Syntax:

Draw.Dot(
    NinjaScriptBase owner,
    string tag,
    bool isAutoScale,
    int barsAgo,
    double y,
    Brush brush
);

Example:

Draw.Dot(this, "pivotDot_" + CurrentBar, false, 0, High[0] + 1, Brushes.Orange);

📏 Draw.Line()

What it does:
Creates a line between two bars and two prices. Perfect for highlighting trends, breakouts, ranges, or structure levels.

Syntax:

Draw.Line(
    NinjaScriptBase owner,
    string tag,
    bool isAutoScale,
    int startBarsAgo,
    double startY,
    int endBarsAgo,
    double endY,
    Brush brush
);

Example:

Draw.Line(this, "rangeLine_" + CurrentBar, true, 10, High[10], 0, High[0], Brushes.Silver);

⬆️ Draw.ArrowUp() / ⬇️ Draw.ArrowDown()

What it does:
Adds an arrow pointing up or down — typically used to signal entries or exits visually.

Syntax:

Draw.ArrowUp(
    NinjaScriptBase owner,
    string tag,
    bool isAutoScale,
    int barsAgo,
    double y,
    Brush brush
);
Draw.ArrowDown(
    NinjaScriptBase owner,
    string tag,
    bool isAutoScale,
    int barsAgo,
    double y,
    Brush brush
);

Examples:

Draw.ArrowUp(this, "long_" + CurrentBar, false, 0, Low[0] - 1, Brushes.LimeGreen);
Draw.ArrowDown(this, "short_" + CurrentBar, false, 0, High[0] + 1, Brushes.Red);

🧠 Understanding the Syntax Format

All Draw.* methods follow a similar structure. Here’s a quick breakdown of what each parameter typically represents:

Parameter Description
this A reference to the current NinjaScript (usually this).
tag A unique string used to identify the draw object. Reusing it updates the object.
isAutoScale (Only on some draw types) Whether to auto-scale the Y-axis to include the object.
barsAgo How many bars ago to place the object (0 = current bar).
y / price The vertical location (price) on the chart.
text / brush Text label or brush color, depending on the draw type.

Not all draw methods use all of these parameters, and many have multiple overloads (versions of the method with different parameters). To explore additional overloads or advanced options, check the NinjaTrader 8 Help Guide under the Language Reference > Common > Drawing section.

Once you’re familiar with the pattern, learning new draw types is mostly plug-and-play.

🏷️ Tagging: Managing Draw Objects with Strings

Every Draw.* method in NinjaTrader requires a tag — a string that uniquely identifies the draw object. This tag controls whether a draw object gets updated, overwritten, or drawn as a new object each time the code runs.

Understanding how tags work — and choosing between static or dynamic tagging — makes a huge difference in how clean and readable your chart becomes.

🟩 Static Tagging

A static tag is a tag that stays the same every time your code runs.

🔁 Example:

Draw.Text(this, "signalLabel", "Signal Triggered", 0, High[0] + 2, Brushes.Blue);

Because the tag is always "signalLabel", NinjaTrader:

  • Updates the same text label on the chart
  • Removes the previous one and replaces it with the new version
  • Keeps the chart clean with just one object

✅ Use it when:

  • You only want to show one active signal
  • You’re labeling something that should always move with the latest bar
  • You’re debugging a condition and only care about the current bar

🟨 Dynamic Tagging

A dynamic tag is one that changes each time the script runs, usually by adding something like CurrentBar, Time[0], or another unique value.

🧪 Example:

Draw.ArrowUp(this, "entryArrow_" + CurrentBar, false, 0, Low[0] - 1, Brushes.LimeGreen);

Because the tag changes with every bar ("entryArrow_217", "entryArrow_218", etc.), NinjaTrader:

  • Draws a new object each time the condition is met
  • Keeps all historical arrows or dots on the chart
  • Helps you visually backtest or debug every instance a signal fires

✅ Use it when:

  • You want to track and see multiple historical signals
  • You’re building a full signal history on the chart
  • You’re analyzing patterns and need to compare across bars

🧠 Why It Matters Visually

Here’s the difference:

Approach Visual Outcome Chart Clarity
Static Tag One object updates repeatedly Clean chart, single reference point
Dynamic Tag New object for each condition match Historical trace, more cluttered but more informative

🧼 Removing or Managing Draw Objects

Once your script starts drawing on the chart, it’s just as important to know how to remove or manage those objects — especially when you’re using dynamic tagging or testing frequently.

NinjaTrader gives you two main ways to clean up draw objects:

  • Remove a single object by tag
  • Remove all objects created by your script

❌ Remove a Single Object

If you want to delete a specific draw object, you can use its tag with RemoveDrawObject():

RemoveDrawObject("draw object tag");

This is helpful when:

  • You only want to remove one object without disturbing the rest
  • You’re using static tagging and want to clear the object conditionally
  • You’re replacing one label or line with another in real time

🧹 Remove All Script-Generated Objects

To wipe the slate clean, use RemoveDrawObjects():

if (Bars.IsFirstBarOfSession)
    RemoveDrawObjects();

This will remove every object that your script created — not manually drawn items, just those tied to the current indicator or strategy.

Great for:

  • Resetting visuals at the start of a session
  • Clearing out debugging objects when the chart reloads
  • Keeping charts clean during backtesting or real-time testing

🎨 Styling with DrawingTool Properties (Quick Note)

Most Draw.* methods return a drawing tool object that you can modify — like changing line thickness, dash style, text alignment, or locking an object so it doesn’t move.

Example:

var line = Draw.Line(this, "myLine", true, 10, Low[10], 0, Low[0], Brushes.SteelBlue);
line.Stroke.Width = 2;
line.IsLocked = true;

That said, styling can get a bit more complex depending on the object type, where it’s drawn, and how it behaves during chart reloads or template saves.

We’ll cover advanced styling, visual consistency tips, and edge cases in a dedicated follow-up post.

For now, just know that you can style draw objects after creation — and that flexibility will come in handy later.

💡 Real-World Use Cases

Now that you know how to draw, manage, and tag objects — here are a few ways traders and script developers commonly use them:

🐞 Debugging Conditions

Use Draw.Text() or Draw.Dot() to visually confirm when logic fires.

if (CrossAbove(EMA(14), EMA(28), 1))
    Draw.Dot(this, "emaCross_" + CurrentBar, false, 0, High[0] + 1, Brushes.Blue);

This helps you catch mistakes that print statements can’t easily reveal.

🔁 Visual Backtesting

Leave a visible trail of signals — arrows, text, or lines — so you can evaluate how your entries/exits performed over time.

if (LongSignal)
    Draw.ArrowUp(this, "long_" + CurrentBar, false, 0, Low[0] - 1, Brushes.Green);

📊 Marking Trade Zones or Levels

Use lines or labels to highlight session highs, breakout levels, or range zones for decision-making.

Draw.Line(this, "overnightHigh", true, 20, overnightHigh, 0, overnightHigh, Brushes.Gray);

🧠 Journaling on the Chart

Annotate key points directly on your live or playback chart — what worked, what didn’t, or what your logic saw.

Draw objects aren’t just for development — they’re a powerful way to build visual tools that make trading and decision-making easier.

🧽 Final Thoughts: Visual Feedback Builds Confidence

Draw objects are one of the most used — and most useful — tools in NinjaScript.

Whether you’re debugging, backtesting, or building live indicators, being able to see your logic play out on the chart gives you clarity you can’t get from code alone.

In this post, we covered:

  • The role of DrawOnPricePanel and how it affects where your visuals appear
  • How to use and manage draw objects through the DrawObjects collection
  • Syntax and structure of the core Draw.* methods you’ll use the most
  • Why tagging matters, and how it controls what gets updated or added
  • A preview of styling and practical examples for real-world charting

As your NinjaScript skills grow, draw objects will become part of your daily workflow — not just for signal confirmation, but for clarity, testing, and decision-making.

If you’re not drawing on your chart, you’re leaving insight on the table.
Use visuals to trade smarter.

🎉 Prop Trading Discounts

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

Categorized in:

Learn NinjaScript,

Tagged in: