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

Here is the architectural breakdown for transforming the “Bayesian Kelly Strategy” into a production-grade automated execution framework.

The provided script is a portfolio allocation model, not a traditional trading strategy. It’s always invested, merely adjusting its leverage based on a Bayesian-updated return expectation. This is common in quantitative finance but lacks the discrete entry, exit, and risk-control mechanisms essential for a robust, standalone trading system. Our goal is to build these mechanisms around its core signal, f_bayes.

1. Execution Triggers (Entry & Direction)

The original script is always long, varying its size. A production system requires clear, non-ambiguous states: Long, Short, or Flat. We will repurpose the f_bayes variable from a leverage factor into a directional conviction score.

2. Multi-Tiered Exit Logic

The original script’s only exit mechanism is a periodic rebalance. This exposes the system to unlimited downside risk. A professional framework requires a hierarchy of exit rules.

3. Capital Allocation & Risk Management

The original script’s Kelly-based sizing is its core idea, but it’s untethered from a stop-loss, making it theoretical. We will integrate its “conviction score” into a professional, risk-first position sizing model.

4. Implementation Snippet (Pine Logic)

This snippet demonstrates the transition from the allocation model to a structured trading strategy with robust risk and exit management.

//@version=5
// TRANSITIONED TO PRODUCTION-GRADE FRAMEWORK
strategy(
     "Production Bayesian Strategy", 
     overlay=true, 
     process_orders_on_close=true, 
     pyramiding=0, // Explicitly disable pyramiding for clean signal evaluation
     commission_type=strategy.commission.percent,
     commission_value=0.075, // Realistic broker commission (e.g., 0.075%)
     slippage=2 // Realistic slippage in ticks
)

// --- Inputs ---
// Bayesian Calculation Inputs
lookback_p = input.int(252, "Prior Lookback Window", minval=10)
lookback_e = input.int(60, "Evidence Lookback Window", minval=10)
kelly_frac = input.float(0.5, "Kelly Fraction", minval=0, maxval=1)

// Trade Execution & Risk Inputs
entry_threshold = input.float(0.05, "Entry Conviction Threshold")
risk_percent = input.float(1.0, "Risk Per Trade %") / 100
atr_period = input.int(14, "ATR Period")
sl_atr_mult = input.float(2.5, "Stop Loss ATR Multiplier")
trail_atr_mult = input.float(3.0, "Trailing Stop ATR Multiplier")
stagnation_bars = input.int(20, "Max Bars in Trade (Stagnation)")

// --- Core Signal Calculation ---
float ret = math.log(close / close[1])

float p_mu = ta.sma(ret, lookback_p)
float p_var = ta.variance(ret, lookback_p)
float p_prec = p_var > 0 ? 1 / p_var : 0

float s_mu = ta.sma(ret, lookback_e)
float s_var = ta.variance(ret, lookback_e)
float s_prec = s_var > 0 ? 1 / s_var : 0

// MODIFIED: Removed the math.max(..., 0) clamp to allow for negative (short) signals
float f_bayes_raw = (p_prec * p_mu + s_prec * s_mu) * kelly_frac

// --- Volatility & Risk Calculation ---
float atr = ta.atr(atr_period)

// --- Entry Conditions ---
bool isLongEntry = f_bayes_raw > entry_threshold and strategy.position_size == 0
bool isShortEntry = f_bayes_raw < -entry_threshold and strategy.position_size == 0

// --- Exit Conditions ---
bool closeLongSignal = strategy.position_size > 0 and (f_bayes_raw < 0 or bar_index - strategy.opentrades.entry_bar_index(0) > stagnation_bars)
bool closeShortSignal = strategy.position_size < 0 and (f_bayes_raw > 0 or bar_index - strategy.opentrades.entry_bar_index(0) > stagnation_bars)

// --- Position Sizing ---
float stopLossDistance = atr * sl_atr_mult
float riskValue = strategy.equity * risk_percent
float positionSize = riskValue / stopLossDistance

// --- Execution Logic ---
if (isLongEntry)
    // 1. Calculate Stop Loss Price
    float stopLossPrice = close - stopLossDistance
    // 2. Enter Long
    strategy.entry("Long", strategy.long, qty=positionSize)
    // 3. Set Initial Stop Loss & Trailing Stop
    strategy.exit("Exit Long", from_entry="Long", stop=stopLossPrice, trail_price=close, trail_offset=atr * trail_atr_mult)

if (isShortEntry)
    // 1. Calculate Stop Loss Price
    float stopLossPrice = close + stopLossDistance
    // 2. Enter Short
    strategy.entry("Short", strategy.short, qty=positionSize)
    // 3. Set Initial Stop Loss & Trailing Stop
    strategy.exit("Exit Short", from_entry="Short", stop=stopLossPrice, trail_price=close, trail_offset=atr * trail_atr_mult)

// --- Exit Signal Execution ---
if (closeLongSignal)
    strategy.close("Long", comment="Signal Invalidated")

if (closeShortSignal)
    strategy.close("Short", comment="Signal Invalidated")

// --- Plotting for Visualization ---
plot(f_bayes_raw, "Bayesian Conviction", color=f_bayes_raw > 0 ? color.green : color.red)
hline(entry_threshold, "Long Threshold", color=color.new(color.green, 50), linestyle=hline.style_dashed)
hline(-entry_threshold, "Short Threshold", color=color.new(color.red, 50), linestyle=hline.style_dashed)
hline(0, "Zero Line", color=color.new(color.gray, 50))