Skip to content

Payload Format -- Future Indicator Design Guidelines

Current Approach: Natural Visual Encoding

The four existing indicators (Bias AI, Session Hunt AI, OB AI, SMT Divergences) were not designed with MCP consumption in mind. They encode state through natural visual elements: colors, line styles, text patterns, box positions, and table cell backgrounds. The interpreter layer translates these visual encodings into typed strategy state by applying the rules defined in each indicator's contract.

This approach works because:

  1. MCP can read all Pine graphics. The get_pine_labels, get_pine_lines, get_pine_boxes, and get_pine_tables tools return structured data about every visual element on the chart.
  2. The visual encodings are deterministic. A blue solid line always means the same thing. A table cell with a specific bgcolor always encodes the same state.
  3. The interpreters handle all parsing complexity. Each indicator has a dedicated interpreter module that applies contract rules to raw MCP output.
  4. No indicator modifications are required. The indicators run unmodified on TradingView. The entire integration is read-only.

Limitations of Natural Encoding

Limitation Impact
Color-dependent User color customization can break parsing if interpreter is not reconfigured
Implicit structure The meaning of a line is inferred from color + style + position, not declared
No metadata Lines and boxes carry no semantic tags -- "this is an OB top line" is not encoded anywhere
Ambiguous overlap Two indicators using similar colors on the same chart can confuse the interpreter
No versioning If the indicator's visual output changes, there is no version field to detect the mismatch

Structured Payload Options

For future indicators designed specifically for MCP consumption, structured payloads eliminate ambiguity and simplify parsing. Two options are practical within Pine Script's constraints.

Option A: Delimiter-Based Label Text

Encode structured data as delimited strings in label text. Labels are the most flexible Pine element for carrying arbitrary text.

Format

SIGNAL|KEY1:VALUE1|KEY2:VALUE2|KEY3:VALUE3

Example

SIGNAL|BIAS:BULL|CONF:0.85|SESSION:NY_AM|TARGET:5892.50

Parsing

def parse_payload_label(text: str) -> dict:
    parts = text.split("|")
    signal_type = parts[0]
    data = {}
    for part in parts[1:]:
        key, value = part.split(":", 1)
        data[key] = value
    return {"signal": signal_type, **data}

Properties

Property Value
Max label text length ~4000 characters (Pine Script string limit)
Delimiter \| (pipe) for fields, : for key-value
Signal identifier First field (before first pipe)
Value types All strings; interpreter casts to int/float/bool as needed
Visibility Can set label to transparent/tiny to hide from human view

Pine Script Implementation

payload = "SIGNAL|BIAS:BULL|CONF:" + str.tostring(confidence, "#.##") + "|SESSION:" + session_name
label.new(bar_index, close, payload, style=label.style_none, size=size.tiny, textcolor=color.new(color.white, 100))

Using label.style_none with fully transparent text makes the label invisible to the human trader while still readable by MCP.

Option B: JSON in Table Cells

Encode structured data as JSON strings in table cells. Tables can hold arbitrary text per cell and support multiple rows/columns.

Format

{"bias": "bull", "confidence": 0.85, "session": "NY_AM", "target": 5892.50}

Properties

Property Value
Max cell text length ~4000 characters per cell
Format Standard JSON
Table position Use an uncommon position (e.g., position.bottom_left) to avoid conflicts
Visibility Set text color to fully transparent; table acts as hidden data store

Pine Script Implementation

var t = table.new(position.bottom_left, 1, 5, bgcolor=color.new(color.white, 100), border_color=color.new(color.white, 100))
json_payload = '{"bias":"bull","confidence":' + str.tostring(confidence) + ',"session":"' + session_name + '"}'
table.cell(t, 0, 0, json_payload, text_color=color.new(color.white, 100))

Multi-Row Tables for Complex State

Row 0: {"type": "bias", "direction": "bull", "confidence": 0.85}
Row 1: {"type": "hunt", "state": "HUNT_HIGH", "target_hi": 5890, "target_lo": 5870}
Row 2: {"type": "ob", "direction": "buy", "ob_high": 5878, "ob_low": 5872.5}
Row 3: {"type": "smt", "direction": "bull", "pair": "ES", "level": 5865}

Each row is independently parseable. The interpreter reads the table and dispatches each row to the appropriate handler based on the type field.


Option Comparison

Criterion Option A (Delimiter Labels) Option B (JSON Tables)
Parsing complexity Low (string split) Medium (JSON parse)
Data richness Flat key-value only Nested objects, arrays
Time-series data One label per bar (natural) Single table (latest state only)
Historical access Labels persist on chart at their bar Table shows only current values
Conflict risk Low (hidden labels blend in) Low (hidden table in unused position)
Debugging Read label text directly Read table cell text directly
Pine complexity Simple string concatenation String concatenation (no native JSON builder)
Max payload ~4000 chars per label ~4000 chars per cell, multiple cells available

Recommendation

  • Use Option A (delimiter labels) when the signal is bar-specific and historical context matters (e.g., entry signals, pattern detection events).
  • Use Option B (JSON tables) when the signal is a current-state summary that updates every bar (e.g., aggregated indicator state, dashboard data).
  • Use both in combination when an indicator needs to communicate both event history and current state.

Design Guidelines for MCP-Friendly Indicators

1. Separate Human and Machine Channels

Use visible elements (colored lines, boxes, labels with human-readable text) for the trader's benefit. Use hidden elements (transparent labels or table cells) for the MCP payload. Never overload a single element to serve both purposes -- it creates fragile coupling.

2. Include a Version Field

SIGNAL|V:2|BIAS:BULL|CONF:0.85

or

{"version": 2, "bias": "bull", "confidence": 0.85}

The interpreter checks the version field and raises an error if it encounters an unknown version, rather than silently misinterpreting the payload.

3. Include a Timestamp

SIGNAL|V:2|TS:1713100800|BIAS:BULL

The Unix timestamp allows the interpreter to detect stale data (indicator hasn't updated) vs. fresh data.

4. Use Consistent Key Names

Establish a schema and stick to it across all indicators:

Key Type Description
V int Payload version
TS int Unix timestamp
DIR string Direction: BULL, BEAR, NEUTRAL
CONF float Confidence: 0.0 to 1.0
LVL float Price level
STATE string State machine state
SESSION string Session identifier
INST string Instrument/ticker

5. Fail Explicitly

If the indicator cannot compute a valid signal, emit a payload that says so:

SIGNAL|V:2|STATE:NO_DATA|REASON:insufficient_bars

This is better than emitting nothing (which the interpreter cannot distinguish from "indicator not loaded").

6. One Indicator, One Table Position

If using Option B, assign each indicator a unique table position to prevent collisions:

Indicator Table Position
Bias AI position.bottom_right (existing, human-visible)
Session Hunt AI position.bottom_left (machine payload)
OB AI position.top_right (existing, human-visible ATR banner)
SMT Divergences position.top_left (machine payload)

7. Keep Payloads Small

Pine Script string operations are slow. Keep payloads under 500 characters for acceptable performance. If you need more data, split across multiple table rows or labels.


Migration Path

For existing indicators, migration to structured payloads would follow this sequence:

  1. Add hidden payload elements alongside existing visual elements (no breaking changes to human view).
  2. Update the interpreter to prefer structured payloads when available, falling back to visual parsing.
  3. Validate that structured and visual parsing produce identical state for a test period.
  4. Deprecate visual parsing once structured payloads are proven reliable.
  5. Update the contract to document the structured payload as the primary channel.

This is not currently planned for the four existing indicators. The natural visual encoding approach is working and the indicators are not modified. This document exists to guide future indicator development where MCP is a first-class consumer.