CTDMM · Codex
Pine Script Optimization Guide
Optimizing TradingView Pine Scripts for high-frequency strategies — a CTDMM technical how-to focused on performance, confluence logic, and a lineage-grade pine script generator pattern.
Why Pine Script needs a discipline
Pine v5 runs one bar at a time inside TradingView's sandbox. Every tick your script wastes on redundant math, orphan series, or over-drawn plot() calls widens the gap between signal and execution. For high-frequency confluence work — the CTDMM way — you engineer the script like a protocol: Input → Process → Output, with state that survives repaint and logic that survives your own future edits.
1. Structure: the CTDMM engine layout
Split every strategy into four blocks in this exact order. This is the same shape the MioS Codex uses for pattern artifacts.
//@version=5
strategy("CTDMM Confluence Engine", overlay=true, process_orders_on_close=true,
calc_on_every_tick=false, max_labels_count=50)
// 1) INPUTS — grouped, typed, documented
grpTrend = "Trend Engine"
emaFast = input.int(21, "EMA fast", minval=2, group=grpTrend)
emaSlow = input.int(55, "EMA slow", minval=3, group=grpTrend)
useHTF = input.bool(true, "Confirm on HTF", group=grpTrend)
htf = input.timeframe("240", "HTF", group=grpTrend)
// 2) STATE — series computed once per bar
[emaF, emaS] = [ta.ema(close, emaFast), ta.ema(close, emaSlow)]
htfClose = request.security(syminfo.tickerid, htf, close, lookahead=barmerge.lookahead_off)
// 3) LOGIC — pure booleans, no side effects
bullTrend = emaF > emaS and (not useHTF or close > htfClose)
bearTrend = emaF < emaS and (not useHTF or close < htfClose)
longSig = ta.crossover(close, emaF) and bullTrend
shortSig = ta.crossunder(close, emaF) and bearTrend
// 4) ACTIONS — orders and rendering only
if longSig and strategy.position_size <= 0
strategy.entry("L", strategy.long)
if shortSig and strategy.position_size >= 0
strategy.entry("S", strategy.short)
plot(emaF, "EMA fast", color=color.new(color.aqua, 0))
plot(emaS, "EMA slow", color=color.new(color.orange, 0))2. Performance rules that actually matter
- Compute once, reuse. Assign every
ta.*call to a variable at bar top. Callingta.ema()twice compiles twice. - Never branch a series.
x = cond ? ta.rsi(close,14) : nabreaks Pine's series recursion. Computersi = ta.rsi(close, 14)unconditionally, then gate its use. lookahead_offon every HTF fetch. Prevents future-bar leaks — the #1 cause of a strategy that backtests like a god and fails live.calc_on_every_tick=falsefor backtests; only flip on for live intrabar signals you actually consume.- Cap
max_labels_count/max_lines_count.Uncapped drawing crashes the runtime on symbols with dense history. - Prefer
math.*over ternaries.math.max,math.sign,math.avgvectorize and read cleaner than nested? :chains.
3. CTDMM confluence logic
A confluence signal is not a single indicator — it's a vote across orthogonal axes. Score each axis 0 or 1, sum, and fire when the sum crosses a threshold. This is the same rubric MioS uses for its risk radar.
// Axes — pick 4-6, no more. Correlated axes double-count and lie.
trend = emaF > emaS ? 1 : 0
mom = ta.rsi(close, 14) > 55 ? 1 : 0
vol = ta.atr(14) > ta.sma(ta.atr(14), 50) ? 1 : 0
struct = close > ta.highest(high, 20)[1] ? 1 : 0
htfOk = close > htfClose ? 1 : 0
confluence = trend + mom + vol + struct + htfOk
longFire = ta.crossover(confluence, 3) // 3 of 5 axes agree
Rule: never add an axis you cannot explain in one sentence. A CTDMM script has a lineage; every input has a reason.
4. The Pine Script generator pattern
When you build many strategies (as MioS does), stop hand-writing them. Treat Pine as an output format from a template. A minimal generator has three layers:
- Schema — a typed spec (JSON / Zod / Pydantic) describing inputs, axes, weights, thresholds, and execution rules.
- Renderer — a pure function that walks the schema and emits Pine v5 source in the four-block layout above.
- Verifier — a smoke test that pastes the output into TradingView's compiler via API-less lint (or a local Pine linter) and refuses to ship on error.
Every generated script inherits the same header, the same guardrails (lookahead_off, capped draws, computed-once series), and the same confluence rubric. The generator is the only place a rule can change — the fleet updates in one edit.
5. Shipping checklist
- Every
request.securityuseslookahead_off. - No
ta.*call appears twice with identical arguments. - No indicator is computed inside a conditional branch.
strategy(...)declaresprocess_orders_on_close=truefor backtests.max_labels_countandmax_lines_countare set.- Confluence axes ≤ 6, each explainable in one sentence.
- Alert conditions mirror entry conditions exactly — no drift.