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:
- DrawOnPricePanel – NinjaTrader Help Guide
- DrawObjects – NinjaTrader Help Guide
- Drawing – NinjaTrader Help Guide
📚 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
⚙️ 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 logicOnStateChange()
– 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