Algorithmic Risk Management: The Math Behind Capital Preservation
How quantitative risk rules, dynamic position sizing, and volatility-adjusted stops prevent ruin in algorithmic execution engines.
1. The Fallacy of Win Rate
Novice traders fixate on high win-rate strategies (e.g. 80%+), often through hidden martingale scaling or catastrophic fat-tail risk. In algorithmic systems, the most profitable and durable strategies typically operate with win rates between 40% and 55%, sustained entirely by asymmetric Risk-to-Reward (R:R) multiples.
A strategy with a 45% win rate that averages 2.5R on winning trades and cuts losers at 1.0R delivers consistent positive mathematical expectation over hundreds of executions.
2. Mathematical Expectancy Formula & Position Sizing
The engine's long-term viability is calculated via Expected Value per trade: EV = (Win Rate × Average Win) - (Loss Rate × Average Loss).
If the expected value is positive, scaling the position size relative to account equity using fractional Kelly criterion or fixed fractional percentage risk (e.g. 1% to 2% max portfolio loss per position) protects the account from drawdowns exceeding mathematical recovery thresholds.
interface PositionSizingParams {
accountEquity: number;
riskPercentage: number; // e.g. 1.0 for 1% portfolio risk
entryPrice: number;
stopLossPrice: number;
contractMultiplier?: number;
}
interface RiskCalculationResult {
riskAmountUsd: number;
positionUnits: number;
perUnitRisk: number;
notionalValueUsd: number;
}
/**
* Calculates exact position sizing based on strict dollar risk budget.
* Enforces capital preservation before trade dispatch to exchange.
*/
export function calculatePositionSize({
accountEquity,
riskPercentage,
entryPrice,
stopLossPrice,
contractMultiplier = 1.0,
}: PositionSizingParams): RiskCalculationResult {
const perUnitRisk = Math.abs(entryPrice - stopLossPrice);
if (perUnitRisk <= 0) {
throw new Error("Invalid stop loss: distance to entry must exceed 0");
}
const riskAmountUsd = accountEquity * (riskPercentage / 100.0);
const positionUnits = (riskAmountUsd / perUnitRisk) / contractMultiplier;
const notionalValueUsd = positionUnits * entryPrice * contractMultiplier;
return {
riskAmountUsd: Number(riskAmountUsd.toFixed(2)),
positionUnits: Number(positionUnits.toFixed(4)),
perUnitRisk: Number(perUnitRisk.toFixed(4)),
notionalValueUsd: Number(notionalValueUsd.toFixed(2)),
};
}3. Volatility-Adjusted Stops (ATR Modeling)
Fixed tick or fixed percentage stops fail when market volatility regimes shift. In high volatility regimes, a static 1% stop triggers on market noise; in low volatility regimes, it leaves too much capital exposed.
Employing the Average True Range (ATR) with dynamic multipliers dynamically expands or contracts stop distances according to real-time market dispersion.
4. Real-World Architecture: Trinity v2 (Hyper Gemma AI Trader)
This mathematical foundation is implemented in production within hyper-gemma-ai-trader — a production-ready Autonomous Quantitative Trading System (Trinity v2) engineered with Bitget Futures, Pure Math Quant Engine (Hurst/Z-Score), MongoDB, Node.js, and TypeScript.
Trinity v2 features a high-speed Pure Math Quant Engine that computes the Hurst Exponent (H) for market regime classification (H < 0.5 mean-reverting vs. H > 0.5 trending momentum) combined with Rolling Z-Score normalization for statistical entries.
AI (Gemma 4) is designed as an optional layer for macro regime analysis rather than a blocking execution bottleneck. By decoupling statistical signal generation from LLM inference, the pure math TypeScript quant engine executes orders with ultra-fast deterministic latency on Bitget Futures.
export interface MarketRegime {
hurst: number;
zScore: number;
regime: "MEAN_REVERTING" | "TRENDING" | "RANDOM_WALK";
tradeAllowed: boolean;
}
/**
* Trinity v2 Pure Math Quant Engine
* Computes Rolling Z-Score and Hurst Exponent for Bitget Futures execution.
* Source: https://github.com/silkiy/hyper-gemma-ai-trader
*/
export class TrinityQuantEngine {
public static calculateZScore(prices: number[], window: number = 20): number {
if (prices.length < window) return 0;
const slice = prices.slice(-window);
const mean = slice.reduce((sum, p) => sum + p, 0) / window;
const variance = slice.reduce((sum, p) => sum + Math.pow(p - mean, 2), 0) / window;
const stdDev = Math.sqrt(variance);
return stdDev === 0 ? 0 : (prices[prices.length - 1] - mean) / stdDev;
}
public static calculateHurst(prices: number[]): number {
if (prices.length < 20) return 0.5;
const returns: number[] = [];
for (let i = 1; i < prices.length; i++) {
returns.push(Math.log(prices[i] / prices[i - 1]));
}
const n = returns.length;
const mean = returns.reduce((acc, r) => acc + r, 0) / n;
const deviations = returns.map((r) => r - mean);
let cumulative = 0;
let maxD = -Infinity;
let minD = Infinity;
for (const d of deviations) {
cumulative += d;
if (cumulative > maxD) maxD = cumulative;
if (cumulative < minD) minD = cumulative;
}
const range = maxD - minD;
const variance = deviations.reduce((acc, d) => acc + d * d, 0) / n;
const stdDev = Math.sqrt(variance) || 1e-8;
const rs = range / stdDev;
return Math.min(Math.max(Math.log(rs) / Math.log(n), 0), 1);
}
}Wildan Silki Sawabiqil Abroor
Software Engineer & Web3 Specialist from Indonesia specializing in Full-Stack development (Next.js, Node.js), Smart Contracts (Solidity, Rust), and algorithmic trading systems.