Engineering notes

Engineering note · Historical chart labels

NinjaTrader Price Labels: Keep the Value That Belongs to Each Line

An old horizontal line should display its own recorded price. If every historical label reads the latest level, moving the text around will not fix the underlying problem. First separate the stored value from where the chart draws it.

  1. 01Identify each segment
  2. 02Retain its price
  3. 03Choose label placement
  4. 04Check scale and reload
Proposed data and display contract for a historical-level indicator. This is a design example, not a tested customer repair.

Clarify what historical means in the request

A public NinjaTrader question began with adding a price beside a line. The important clarification was that every historical level should retain its historical price. That turns a text-placement request into a state-retention requirement.

Ask when a segment starts and when it finishes. Is it a session level, a confirmed pivot or a value that changes on every bar? A level that legitimately evolves during its active interval needs a different rule from one that becomes fixed at creation.

Also define which history should be shown. All retained levels, only those intersecting the visible time range, and only the latest level are different display contracts. The right choice comes from the task, not from the number of objects that happen to fit on one screenshot.

Store a record for each completed segment

One possible design stores a segment identity, start time or bar reference, end reference and price. When the level resets, finish the old record and create a new one. The active segment can still change under its defined rule; completed records should not borrow the active segment’s latest value.

Use the same record to derive the line and its label. If the line comes from historical data but the label reads a current scalar variable, the two can disagree even though each rendering call works correctly.

Keep a stable identity across the line and label. If the implementation uses drawing objects, review how it creates or updates their tags. If it uses custom rendering, review how it selects records for each frame. Do not choose a rewrite before inspecting the existing approach.

  • Segment identity: which historical level is this?
  • Time boundary: where does the segment begin and end?
  • Stored price: which value belongs to this segment?
  • Display state: visible, clipped or intentionally omitted under the agreed rule.

Choose between segment labels and an edge column

A label beside a segment answers which price that segment represents. A column at the right edge can show several retained prices, but it needs an additional way to identify which segment each belongs to. Similar prices may produce overlapping labels.

Write down the collision rule before coding. Options include a separate list, a limited visible selection or offset labels with an explicit connector. If text is moved away from its true price height, make the relationship clear. Otherwise the readability fix can introduce a misleading chart cue.

An inset from the panel edge is a display distance. A price offset is a market-value distance. Keep those settings separate. The owner should not need to change a price value merely to move a label away from the chart border.

Recalculate screen placement when the chart renders

NinjaTrader exposes ChartScale.GetYByValue to convert a value into the chart’s vertical pixel coordinate. A custom-rendered line and its label should use the applicable panel and scale consistently. A pixel captured before a scale change is not a permanent location for that price.

For an OnRender implementation, keep the stored segment price separate from the current drawing coordinates. Redraw against the current viewport. Review the platform’s rendering and SharpDX guidance for the actual implementation, including resource lifetime; this article does not supply a compiled indicator.

Formatting is another independent concern. Use the instrument’s appropriate price representation and check that the displayed text corresponds to the stored value. Do not use label text as the authoritative data record.

Make reloads part of the acceptance example

A historical label that survives a zoom can still disappear or change after reloading the indicator. Decide how records are reconstructed from loaded history or retained state. Keep session settings and data coverage in the reproduction steps so the test compares the same input.

Use a small reviewed sequence with two completed segments and one active segment. Record the intended values before changing the viewport. Then resize, scroll, rescale and reload. Separate a missing historical input from a drawing defect instead of treating both as the same failure.

For a repair request, the useful first source section is the code that creates or resets the level and the code that draws it. Provide only authorized source, with private details removed. The smallest change depends on that evidence; a screenshot alone cannot establish whether the indicator needs a series fix, a drawing-tag fix or a different render loop.

Three acceptance checks

Proposed tests, not executed customer results. Record actual outcomes separately.

A new level starts

Input: Finish one segment and start another with a different recorded price.

Expected: Each retained segment displays its own value. Updating the active segment does not rewrite the completed label.

The viewport changes

Input: Resize, scroll and change the scale while the same segments remain available.

Expected: Line and label remain associated. Any clipping or collision follows the agreed display rule.

The indicator reloads

Input: Reload with the same source version, data range and session settings.

Expected: The defined historical records and label values are reconstructed consistently, or missing data is reported rather than invented.

Sources and related guides

Trading risk disclosure

Futures and forex trading contains substantial risk and is not for every investor. An investor could potentially lose all or more than the initial investment. Risk capital is money that can be lost without jeopardizing one's financial security or lifestyle. Only risk capital should be used for trading, and only those with sufficient risk capital should consider trading. Past performance is not necessarily indicative of future results.

Hypothetical performance disclosure

Hypothetical performance results have many inherent limitations. No representation is being made that any account will or is likely to achieve profits or losses similar to those shown. There are frequently sharp differences between hypothetical performance results and the actual results subsequently achieved by any particular trading program. Hypothetical results are generally prepared with the benefit of hindsight, do not involve financial risk, and cannot completely account for the impact of financial risk in actual trading. Market conditions, the ability to withstand losses, and adherence to a trading program can all materially affect actual results.

NinjaTrader trademark disclosure

NinjaTrader® is a registered trademark of NinjaTrader Group, LLC. No NinjaTrader company has any affiliation with the owner, developer, or provider of the products or services described herein, or any interest, ownership or otherwise, in any such product or service, or endorses, recommends or approves any such product or service.

Testimonials, when shown, may not represent the experience of other clients and are not a guarantee of future performance or success. Virtual-currency trading carries additional risks. See the CFTC customer advisories. Read the full financial risk disclaimer.