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

This transformation reframes the “TSI Adaptive Scalper v4.2” from a sophisticated signal generator into a fully-fledged, automated execution framework. The original script’s strength lies in its multi-factor confluence score; our strategy will leverage this score as the primary decision-making input, moving beyond simple crossover events.

1. Execution Triggers (Entry & Direction)

The core of the entry logic will pivot from observing signals to acting upon a quantifiable edge. The script’s adjScoreBull and adjScoreBear provide the perfect mechanism for this.

2. Multi-Tiered Exit Logic

A professional exit strategy is not a single point of failure. It’s a dynamic system designed to protect capital and maximize profit.

3. Capital Allocation & Risk Management

Chart signals are meaningless without a mathematical framework for managing risk.

4. Implementation Snippet (Pine Logic)

This snippet demonstrates the conversion of the indicator’s logic into a strategy engine, focusing on the new execution components.

// -------------------------------------------------------------------------- //
// |                 TSI Adaptive Scalper - STRATEGY ENGINE                 | //
// -------------------------------------------------------------------------- //
//@version=5
// 1. STRATEGY DECLARATION
strategy("TSI Scalper [Strategy Engine]", 
     overlay=true, 
     initial_capital=10000, 
     commission_type=strategy.commission.percent, 
     commission_value=0.075, 
     slippage=2, // Slippage in ticks
     process_orders_on_close=true) // Ensures execution on the next bar's open

// --- [PASTE THE ENTIRE ORIGINAL INDICATOR CODE HERE, FROM LINE 10 to ~1000] ---
// ... all the functions, inputs, and calculations from the original script ...

// -------------------------------------------------------------------------- //
// |                      2. STRATEGY-SPECIFIC INPUTS                         | //
// -------------------------------------------------------------------------- //
string g_strat = "⚙️ Strategy Engine"
entryScoreThreshold = input.float(6.0, "Min. Entry Score (0-10)", group=g_strat, minval=0, maxval=10, step=0.5)
riskPerTradePercent = input.float(1.0, "Risk per Trade (%)", group=g_strat, minval=0.1, maxval=5.0, step=0.1)
useTrailingStop   = input.bool(true, "Use Trailing Stop After TP1?", group=g_strat)
trailingAtrMult   = input.float(2.0, "Trailing Stop ATR Multiplier", group=g_strat)
eodHour           = input.int(20, "EOD Close Hour (UTC)", group=g_strat, minval=0, maxval=23)
eodMinute         = input.int(45, "EOD Close Minute (UTC)", group=g_strat, minval=0, maxval=59)

// -------------------------------------------------------------------------- //
// |                         3. EXECUTION LOGIC                               | //
// -------------------------------------------------------------------------- //

// --- Entry Conditions ---
bool longCondition = bullSignal and (adjScoreBull >= entryScoreThreshold) and strategy.opentrades == 0
bool shortCondition = bearSignal and (adjScoreBear >= entryScoreThreshold) and strategy.opentrades == 0

// --- Time-based Exit ---
bool isEod = (hour(time_close, "UTC") == eodHour and minute(time_close, "UTC") >= eodMinute)

if (isEod)
    strategy.close_all(comment="EOD Close")

// --- Position Sizing & Order Placement ---
if (longCondition)
    // 1. Calculate Stops & Targets
    sl_adj   = calcSLMultiplier(adjScoreBull)
    sl_dist  = tpslATR * slATRMult * sl_adj
    sl_price = close - sl_dist
    tp1_price = close + sl_dist * tp1RR
    
    // 2. Calculate Position Size based on Risk
    riskDistancePoints = close - sl_price
    riskAmountEquity = (strategy.equity * riskPerTradePercent) / 100
    positionSize = riskAmountEquity / (riskDistancePoints * syminfo.pointvalue)

    // 3. Execute Orders
    strategy.entry("Long", strategy.long, qty=positionSize, comment="L Entry @" + str.tostring(adjScoreBull, "#.#"))
    strategy.exit("TP1/SL", from_entry="Long", qty_percent=50, profit=tp1_price, stop=sl_price, comment="L TP1/SL")
    // The remaining 50% is managed by the trailing stop logic below

if (shortCondition)
    // 1. Calculate Stops & Targets
    sl_adj   = calcSLMultiplier(adjScoreBear)
    sl_dist  = tpslATR * slATRMult * sl_adj
    sl_price = close + sl_dist
    tp1_price = close - sl_dist * tp1RR

    // 2. Calculate Position Size based on Risk
    riskDistancePoints = sl_price - close
    riskAmountEquity = (strategy.equity * riskPerTradePercent) / 100
    positionSize = riskAmountEquity / (riskDistancePoints * syminfo.pointvalue)

    // 3. Execute Orders
    strategy.entry("Short", strategy.short, qty=positionSize, comment="S Entry @" + str.tostring(adjScoreBear, "#.#"))
    strategy.exit("TP1/SL", from_entry="Short", qty_percent=50, profit=tp1_price, stop=sl_price, comment="S TP1/SL")

// --- Trailing Stop & Breakeven Management ---
var float trailingStopPrice = na

if (strategy.position_size > 0) // We are in a long position
    // Check if TP1 was hit (by checking closed trades) and set stop to breakeven
    if (strategy.closedtrades.exit_comment(strategy.closedtrades-1) == "L TP1/SL")
        strategy.exit("BE/Trail", from_entry="Long", stop=strategy.opentrades.entry_price(0), comment="L B/E")
    
    // If trailing is enabled, manage the trailing stop
    if (useTrailingStop and strategy.opentrades.entry_price(0) < close) // Only trail if in profit
        newTrailingStop = close - (ta.atr(14) * trailingAtrMult)
        trailingStopPrice := na(trailingStopPrice) ? newTrailingStop : math.max(newTrailingStop, trailingStopPrice)
        strategy.exit("BE/Trail", from_entry="Long", stop=trailingStopPrice)

if (strategy.position_size < 0) // We are in a short position
    if (strategy.closedtrades.exit_comment(strategy.closedtrades-1) == "S TP1/SL")
        strategy.exit("BE/Trail", from_entry="Short", stop=strategy.opentrades.entry_price(0), comment="S B/E")

    if (useTrailingStop and strategy.opentrades.entry_price(0) > close)
        newTrailingStop = close + (ta.atr(14) * trailingAtrMult)
        trailingStopPrice := na(trailingStopPrice) ? newTrailingStop : math.min(newTrailingStop, trailingStopPrice)
        strategy.exit("BE/Trail", from_entry="Short", stop=trailingStopPrice)

// Reset trailing stop price on new bar if not in a trade
if (strategy.position_size == 0)
    trailingStopPrice := na