Skip to content

Batch and Streaming Patterns

How the strategy layer minimizes MCP round-trips and detects changes between scan cycles.


Parallel Indicator Reads

The strategy's scan.js reads all four indicators in parallel using Promise.all. Each indicator reader makes its own MCP tool calls, and all readers execute concurrently.

const [biasData, sessionData, obData, smtData] = await Promise.all([
  biasReader.read(),       // data_get_pine_tables + data_get_pine_labels
  sessionReader.read(),    // data_get_pine_labels + data_get_pine_lines
  obReader.read(),         // data_get_pine_boxes + data_get_pine_lines + data_get_pine_tables
  smtReader.read(),        // data_get_pine_labels
]);

This produces approximately 8 MCP tool calls per scan cycle, all issued concurrently. The total scan duration is bounded by the slowest individual call rather than the sum of all calls.

Typical Scan Timing

Phase Duration Notes
MCP tool calls (parallel) 800--1500ms Depends on chart complexity and indicator count
Reader parsing 5--20ms String splitting, color matching, type conversion
Interpreter logic 1--5ms State derivation from parsed data
Engine scoring <1ms Confluence computation and decision
Total scan ~1--2 seconds

Poll Mode with Delta Detection

The poll.js module runs scan.js on a configurable interval (POLL_INTERVAL, default 10 seconds) and compares each scan's output against the previous one.

How Delta Detection Works

After each scan, poll.js performs a deep comparison of the new StrategyFlags against the previous scan's flags. Only fields that changed are reported.

// Simplified delta detection logic
function detectDelta(previous, current) {
  const changes = [];

  // Compare every leaf field
  for (const path of allFieldPaths) {
    const prev = getNestedValue(previous, path);
    const curr = getNestedValue(current, path);
    if (prev !== curr) {
      changes.push({ path, from: prev, to: curr });
    }
  }

  return changes;
}

Delta Output Example

When the session hunt locks during a poll cycle:

{
  "scan_number": 15,
  "timestamp": "2026-04-14T13:50:10.000Z",
  "delta": [
    { "path": "session.hunt.lo_swept", "from": false, "to": true },
    { "path": "session.hunt.side", "from": null, "to": "HUNT_LOW" },
    { "path": "decision.setup_valid", "from": false, "to": true },
    { "path": "decision.confluence_score", "from": 0, "to": 7 },
    { "path": "decision.direction", "from": null, "to": "long" }
  ]
}

No-Change Heartbeat

When nothing has changed between scans, only a heartbeat is logged:

{
  "scan_number": 16,
  "timestamp": "2026-04-14T13:50:20.000Z",
  "delta": [],
  "status": "no_change"
}

This keeps the log stream active (confirming the system is running) without flooding it with duplicate data.


batch_execute MCP Tool

The tradingview-mcp server provides a batch_execute tool that can combine multiple tool calls into a single MCP request. This reduces HTTP round-trip overhead when the MCP server is accessed over a network.

Usage

{
  "tool": "batch_execute",
  "params": {
    "calls": [
      {
        "tool": "data_get_pine_tables",
        "params": { "study_filter": "Bias AI" }
      },
      {
        "tool": "data_get_pine_labels",
        "params": { "study_filter": "Session Hunt AI", "verbose": true }
      },
      {
        "tool": "data_get_pine_boxes",
        "params": { "study_filter": "OB AI", "verbose": true }
      },
      {
        "tool": "data_get_pine_lines",
        "params": { "study_filter": "OB AI", "verbose": true }
      }
    ]
  }
}

Return Format

{
  "results": [
    { "tool": "data_get_pine_tables", "result": { "tables": [...] } },
    { "tool": "data_get_pine_labels", "result": { "labels": [...] } },
    { "tool": "data_get_pine_boxes", "result": { "zones": [...] } },
    { "tool": "data_get_pine_lines", "result": { "horizontal_levels": [...] } }
  ]
}

All calls within the batch are executed by the MCP server and their results are returned together. The server may execute them sequentially or in parallel depending on implementation.

When to Use batch_execute

Scenario Recommendation
Local MCP server (same machine) Promise.all with individual calls is fine -- network overhead is negligible
Remote MCP server (over network) batch_execute reduces round-trips from ~8 to 1
High-frequency polling (<5s interval) batch_execute reduces connection churn

The current strategy layer uses Promise.all with individual calls since the MCP server runs locally. Switching to batch_execute is a one-line change in scan.js if network deployment is needed.


Performance Optimization

Use study_filter to Reduce Payload

Without study_filter, Pine graphics tools return objects from all indicators on the chart. If the chart has 10 indicators, data_get_pine_labels returns labels from all 10.

With study_filter, only the target indicator's objects are returned. This reduces:

  • Payload size: 10x fewer objects in a typical multi-indicator chart
  • Parse time: Less data to iterate and filter in the reader
  • Noise: No need to distinguish between indicators in application code

Always use study_filter. The strategy layer never calls Pine graphics tools without it.

Minimize Verbose Calls

The verbose: true parameter adds significant data to each object (colors, positions, sizes). Only use verbose when the reader needs the extra fields:

Tool Verbose Needed? Reason
data_get_pine_labels Sometimes Verbose needed for textColor to detect signal direction in some indicators
data_get_pine_lines Yes style field needed for spent/unspent OB detection
data_get_pine_tables No Row text contains all needed data
data_get_pine_boxes Yes borderColor needed for bullish/bearish OB classification

Scan Interval Tuning

The default POLL_INTERVAL of 10 seconds balances responsiveness with resource usage. Considerations for tuning:

Interval Tradeoff
5 seconds Faster signal detection. Higher CPU and MCP load. Good for active trading sessions.
10 seconds (default) Balanced. Catches most setups within one candle on a 5min chart.
30 seconds Low resource usage. Acceptable for monitoring-only mode where immediate execution is not needed.
60 seconds Minimum for meaningful monitoring. May miss fast-developing setups.

On a 5-minute chart, indicator state changes at most once per candle close (every 5 minutes). A 10-second interval provides ~30 scans per candle, which is more than sufficient to catch any state change promptly.