Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Indicators to Strategy Blueprint

The provided script is a sophisticated visualization tool, displaying RSI and Z-Score values as speedometers. While excellent for discretionary analysis, it contains no execution logic. To transform this into a production-ready automated framework, we must extract the core metrics—RSI for momentum and Z-Score for mean-reversion—and build a robust trading engine around them.

The proposed strategy will be a Mean-Reversion system with Momentum Confirmation. It will aim to enter trades when the price is statistically overextended (identified by the Z-Score) and shows initial signs of reverting (confirmed by the RSI).

1. Execution Triggers (Entry & Direction)

The core premise is to fade extreme price moves. We will use the Z-Score to identify a statistical anomaly and the RSI to confirm that momentum is beginning to shift, providing a trigger for entry.

Execution Nuances

2. Multi-Tiered Exit Logic

A static exit strategy is a primary cause of failure. A professional system must adapt to market volatility and protect profits dynamically.

3. Capital Allocation & Risk Management

Position sizing is the most critical component of a trading system’s long-term viability. We will abandon fixed-lot sizing in favor of a precise risk-based model.

4. Implementation Snippet (Pine Logic)

The following code block demonstrates the transformation of the visual indicator into a complete strategy, incorporating the professional-grade components discussed. All visual drawing functions have been removed to focus purely on the execution engine.

//@version=5
// --- STRATEGY DECLARATION ---
strategy(
     "RSI & Z-Score Mean Reversion Engine", 
     overlay=true, 
     process_orders_on_close=true,
     initial_capital=100000,
     default_qty_type=strategy.fixed, // We will calculate quantity manually
     commission_type=strategy.commission.percent,
     commission_value=0.04, // Realistic commission for retail brokers
     slippage=2 // 2 ticks of slippage per order
     )

// --- STRATEGY INPUTS ---
// Risk Management
risk_percent = input.float(1.0, title="Risk Per Trade %", minval=0.1, maxval=5.0, step=0.1)
// Z-Score Parameters
z_len   = input.int(20, title="Z-Score Length", minval=2)
z_entry_threshold = input.float(2.0, title="Z-Score Entry Threshold (±)", minval=1.0, step=0.1)
// RSI Parameters
rsi_len = input.int(14, title="RSI Length")
rsi_confirm_upper = input.int(70, title="RSI Bearish Confirmation Level")
rsi_confirm_lower = input.int(30, title="RSI Bullish Confirmation Level")
// Exit Parameters
atr_len = input.int(14, title="ATR Length for Stops")
atr_stop_multiplier = input.float(2.5, title="ATR Stop Loss Multiplier")
rr_tp1 = input.float(1.5, title="Take Profit 1 Risk/Reward Ratio")
max_bars_in_trade = input.int(100, title="Max Bars in Stagnant Trade")

// --- INDICATOR CALCULATIONS ---
// RSI Metric
rsi_metric = ta.rsi(close, rsi_len)
// Z-Score Metric
z_mean = ta.sma(close, z_len)
z_std  = ta.stdev(close, z_len)
z_raw  = z_std != 0.0 ? (close - z_mean) / z_std : 0.0
// Volatility
atr_val = ta.atr(atr_len)

// --- ENTRY CONDITIONS ---
longCondition = z_raw < -z_entry_threshold and ta.crossover(rsi_metric, rsi_confirm_lower)
shortCondition = z_raw > z_entry_threshold and ta.crossunder(rsi_metric, rsi_confirm_upper)

// --- RISK MANAGEMENT & POSITION SIZING ---
stop_distance_points = atr_val * atr_stop_multiplier
risk_per_trade_currency = (risk_percent / 100) * strategy.equity
position_size = risk_per_trade_currency / (stop_distance_points * syminfo.pointvalue)

// --- EXECUTION LOGIC ---
// Store stop and target levels in variables to manage exits
var float long_stop_price = na
var float long_tp1_price = na
var float short_stop_price = na
var float short_tp1_price = na

// Long Entry Logic
if (longCondition and strategy.position_size == 0)
    long_stop_price := close - stop_distance_points
    long_tp1_price := close + (stop_distance_points * rr_tp1)
    strategy.entry("Long", strategy.long, qty=position_size)
    // Place initial SL and TP1 orders for 50% of the position
    strategy.exit("Long TP1/SL", from_entry="Long", qty_percent=50, profit=long_tp1_price, loss=long_stop_price)

// Short Entry Logic
if (shortCondition and strategy.position_size == 0)
    short_stop_price := close + stop_distance_points
    short_tp1_price := close - (stop_distance_points * rr_tp1)
    strategy.entry("Short", strategy.short, qty=position_size)
    // Place initial SL and TP1 orders for 50% of the position
    strategy.exit("Short TP1/SL", from_entry="Short", qty_percent=50, profit=short_tp1_price, loss=short_stop_price)

// --- EXIT MANAGEMENT ---
// Breakeven & Trailing Stop Logic
var bool long_tp1_hit = false
var bool short_tp1_hit = false

if strategy.position_size > 0
    // Check if TP1 was hit on the current bar
    if not long_tp1_hit and high >= long_tp1_price
        long_tp1_hit := true
    // If TP1 has been hit, manage the remainder with a trailing stop (move to breakeven first)
    if long_tp1_hit
        breakeven_price = strategy.opentrades.entry_price(0)
        trailing_stop_price = math.max(breakeven_price, high - stop_distance_points) // ATR Trail
        strategy.exit("Long Trail", from_entry="Long", loss=trailing_stop_price)
    // Stagnation Exit
    if barssince(longCondition) > max_bars_in_trade
        strategy.close("Long", comment="Stagnation Exit")

if strategy.position_size < 0
    // Check if TP1 was hit on the current bar
    if not short_tp1_hit and low <= short_tp1_price
        short_tp1_hit := true
    // If TP1 has been hit, manage the remainder with a trailing stop (move to breakeven first)
    if short_tp1_hit
        breakeven_price = strategy.opentrades.entry_price(0)
        trailing_stop_price = math.min(breakeven_price, low + stop_distance_points) // ATR Trail
        strategy.exit("Short Trail", from_entry="Short", loss=trailing_stop_price)
    // Stagnation Exit
    if barssince(shortCondition) > max_bars_in_trade
        strategy.close("Short", comment="Stagnation Exit")

// Reset TP hit flags when flat
if strategy.position_size == 0
    long_tp1_hit := false
    short_tp1_hit := false

// EOD Exit (Example for a specific time)
is_eod_exit = time_close("1D") > 0 and hour == 15 and minute >= 50 // Example: Exit at 15:50
if is_eod_exit
    strategy.close_all(comment="EOD Exit")