← Back to Insights

The Gambler's Fallacy: Automating Dynamic Position Sizing

2025-12-13

Most retail traders trade like they are at a roulette table.

They use "Fixed Lot Sizes." They buy 0.1 BTC every time.

  • If volatility is low, 0.1 BTC is safe.
  • If volatility is high, 0.1 BTC can wipe out 10% of the account in a single wick.

This inconsistency kills portfolios. Even worse is the Gambler's Fallacy—the belief that "I lost the last three, so the next one must win, so I'll bet double."

This is how you get liquidated.

The 1% Rule

Professional risk management is boring but essential. The rule is simple: Never risk more than 1% of your equity on a single trade.

This means if your Stop Loss is hit, you lose exactly 1%. No more, no less.

  • If the Stop Loss is tight (1% away), you can trade a large size.
  • If the Stop Loss is wide (10% away), you must trade a tiny size.

Humans are terrible at calculating this on the fly. We are lazy. We just punch in "1000 contracts" and hope for the best.

The Automaton: Dynamic Sizing Script

We need a script that calculates the volatility (ATR) and tells the bot exactly how much to buy to maintain that perfect 1% risk.

The Code: Pine Script v6 Risk Calculator

This script doesn't just give you a signal; it gives you the Quantity.

//@version=6
indicator("Codon: Dynamic Risk Calculator", overlay=true)

// --- Settings ---
float riskPerTrade = input.float(1.0, "Risk % per Trade") / 100
float accountSize = input.float(100000, "Account Size (USD)")
int atrPeriod = input.int(14, "ATR Period (Volatility)")
float slMultiplier = input.float(2.0, "Stop Loss Multiplier (x ATR)")

// --- Logic ---
float atr = ta.atr(atrPeriod)

// Calculate Stop Loss Distance
// Example: Long Entry at Close, SL at Low - 2*ATR
float slDistance = atr * slMultiplier

// --- The Math ---
// Risk Amount = Account Size * 0.01 (e.g., $1000)
// Position Size = Risk Amount / SL Distance
float riskAmount = accountSize * riskPerTrade
float positionSize = riskAmount / slDistance

// --- Visualization ---
// We plot this in the Data Window so you can send it via Webhook
plot(positionSize, title="Calculated Position Size (Units)", display=display.data_window)

// Visual Label
if barstate.islast
    string txt = "RISK: $" + str.tostring(riskAmount) + "\n" +
                 "SL DIST: " + str.tostring(slDistance, "#.##") + "\n" +
                 "SIZE: " + str.tostring(positionSize, "#.####") + " Units"
    
    label.new(bar_index, high, txt, color=color.blue, textcolor=color.white)

The Automation Layer

This is the advanced implementation. Most basic bots use fixed sizes. To use Dynamic Sizing, we pass this variable in the JSON Payload.

In your TradingView Alert Message, you can use placeholders (variables). Instead of sending "quantity": 100, you send:

{
  "action": "open_long",
  "quantity": "{{plot("Calculated Position Size (Units)")}}"
}

Note: 3Commas supports dynamic variables in specific advanced configurations or via custom signal bots. If using simpler bots, use the script to manually adjust your "Base Order Size" each morning based on current market volatility.

By dynamically adjusting your size, you survive the storms that sink other ships. You treat a 10% dump the same as a 1% dip. The risk is identical. The math protects you from the market, and from yourself.

(Check the footer for the tools capable of dynamic sizing)