Architecture
An overview of how PineChart executes Pine Script inside MetaTrader 5.
Pipeline Overview
PineChart processes Pine Script through a classic interpreter pipeline:
Pine Script (.txt file)
│
▼
┌─────────┐ ┌─────────┐ ┌──────────────┐
│ Lexer │ ──▶ │ Parser │ ──▶ │ Interpreter │
│ (tokens)│ │ (AST) │ │ (per-bar exec)│
└─────────┘ └─────────┘ └──────────────┘
│
▼
Plots / Drawings / Orders
- Lexer — Tokenizes Pine Script source into 70+ token types, with indentation tracking for Python-style blocks
- Parser — Recursive descent parser builds an AST with 18+ node types (if/else, for/while, switch, function definitions, UDTs, etc.)
- Interpreter — Executes the AST per-bar with full Pine Script semantics: series reverse-access,
var/varippersistence, NA propagation
Per-Bar Execution Model
Pine Script runs once per bar, from bar 0 (oldest) to the current bar. This is fundamentally different from event-driven MQL5 programming.
- Each bar, the interpreter walks the entire AST
- Built-in variables (
open,high,low,close,volume) reflect the current bar’s data - Series access with
[N]looks back N bars from the current position varvariables initialize once and persist across all barsvaripvariables persist across bars AND intrabar ticks
Calculate-once, render-visible: Pine executes once over full history (up to InpMaxBars, default 5000). Plot arrays store all computed values. Panning and scrolling only changes the visible offset — no recalculation needed.
Indicators vs Strategies: Tick Recalculation
Indicators execute per-bar only. Once a bar is calculated, its values are final. When a new tick arrives, the indicator does not re-execute — it waits for the next confirmed bar.
Strategies execute per-tick on the latest bar. Because strategies submit real orders, they need to react to intrabar price changes. PineChart handles this with a snapshot-restore cycle:
- Before the last bar, all TA states are snapshotted
- On each new tick, states are restored to the snapshot and the last bar is re-executed with updated OHLCV data
- This gives strategies fresh signal evaluation on every tick without recalculating the entire 5000-bar history
This means barstate.isrealtime and barstate.isconfirmed behave differently in strategies — a strategy sees multiple executions per bar (one per tick), while an indicator sees exactly one.
Technical Analysis Engine
TA functions compute incrementally using persistent state:
- Each TA call gets a unique state slot via a monotonic counter (
ta.sma@0,ta.sma@1, etc.) - State includes circular buffers (
values[]), running sums, and recursive formula accumulators - Composite functions (like
ta.bbwhich usesta.sma+ta.stdev) chain sub-functions with unique sub-keys - Tuple-return functions return array handles that get destructured automatically
The TA engine spans 6 category modules:
- Moving Averages — SMA, EMA, RMA, WMA, VWMA, HMA, SWMA
- Oscillators — RSI, MACD, Momentum, ROC, Change, CMO
- Volatility — True Range, ATR, StDev, Variance
- Statistics — Highest, Lowest, Cumulative Sum, Linear Regression
- Signals — Crossover, Crossunder, Cross, Rising, Falling
- Indicators — Stochastic, CCI, Williams %R, Bollinger Bands, SuperTrend, DMI, Parabolic SAR, Pivot Points
Multi-Indicator Architecture
PineChart can run N indicators + 1 optional strategy simultaneously:
- Each indicator gets its own isolated execution context (variable scope, UDT pool, table pool, cached AST)
- All indicators share bar data, the plot manager, drawing store, and multi-timeframe data pool
- Plot index offsets prevent cross-indicator collisions
- Indicators are specified via comma-separated filenames in the
InpIndicatorsinput
Rendering Model
Everything draws on an optimized canvas — chart, UI, plots, crosshair, drawings, tables. The rendering pipeline is designed for smooth, lag-free performance with zero flicker, even with multiple indicators and drawing objects active.
Smart indicator panes: Each indicator can render in the main chart pane (overlay) or in its own sub-pane below, with independent price scales and auto-scaling. Pane dividers are draggable.
Theme system: EA color inputs feed a ThemeManager that auto-derives a complete readable palette consumed by all renderers and UI components.
Strategy Execution
Pine Script strategy.* functions map directly to MQL5’s CTrade library:
strategy.entry()/strategy.order()→CTrade::Buy()/CTrade::Sell()strategy.close()/strategy.close_all()→CTrade::PositionClose()strategy.exit()→CTrade::PositionModify()(SL/TP)strategy.cancel()/strategy.cancel_all()→CTrade::OrderDelete()
No custom backtester — MT5’s Strategy Tester provides backtesting for free. Live bar gating ensures real trades only execute on the latest bar.
NA Propagation
PineChart faithfully implements Pine Script’s NA (Not Available) semantics:
napropagates correctly throughout the system- TA functions return
naduring their warmup period (first N-1 bars) - Arithmetic with
napropagates:na + 5 = na - Plot gaps are rendered correctly when values are
na - Auto-scaling excludes
navalues
This ensures that composable TA expressions like ta.linreg(ta.sma(close, 20) - ta.highest(high, 20), 20, 0) produce correct results — inner NAs during warmup propagate cleanly through the chain.