Risk management
🦉 AthenaAI is an AI-powered ensemble machine-learning trading bot for PocketOption, built on BinaryOptionsToolsV2 → Get it on GitLab
💬 Need help? Join the Chipa Discord · ⚡ Go no-code with ChipaEditor
AthenaAI’s money management lives in MoneyManager (src/trading/money_manager.py), with additional loss-control gates in the trade loop (src/bot.py) and the adaptive strategy (src/trading/strategy.py). This page walks through each mechanism with the exact formulas and constants from the code.
Stake sizing: fractional Kelly with a confidence multiplier
MoneyManager.compute_stake(confidence, win_rate, payout=0.85) is called before every trade (the bot passes the current overall win rate from its performance tracker and a payout of 0.85). The full formula:
-
Kelly edge — with
p= win rate,q = 1 − p,b= payout:edge = p·b − qIf
edge ≤ 0(orpayout ≤ 0), the function returnsbase_stakeimmediately — no edge, minimum stake. -
Kelly fraction of bankroll analog:
kelly = edge / b fraction = kelly × kelly_fraction # kelly_fraction default 0.50 -
Map onto the configured stake range:
stake = base_stake + fraction × (max_stake − base_stake) -
Confidence multiplier (v6 “gentler scaling”):
stake ×= max(0.5, (confidence − 0.45) × 2.0)That is: 60% confidence → ×0.50, 65% → ×0.65, 70% → ×0.80, 75% → ×0.95, and ×1.0 only at 97.5% (which
PO_MAX_CONFwould reject anyway). The multiplier never exceeds ~0.8 in the default 63–85% confidence band, so it always shrinks the Kelly stake. -
Clamp and round:
stake = clamp(stake, base_stake, max_stake) # then rounded to cents
Because the multiplier is below 1 in practice, the final clamp means the stake only rises above base_stake when the win rate is well above breakeven.
Worked example
Config: base_stake = $25, max_stake = $100, kelly_fraction = 0.50. Trade: win rate 75%, confidence 80%, payout 0.85.
edge = 0.75 × 0.85 − 0.25 = 0.3875
kelly = 0.3875 / 0.85 = 0.4559
fraction = 0.4559 × 0.50 = 0.2279
stake = 25 + 0.2279 × (100 − 25) = $42.10
mult = max(0.5, (0.80 − 0.45) × 2) = 0.70
stake = 42.10 × 0.70 = $29.47
clamp(25, 29.47, 100) → stake = $29.47
Same trade at a 60% win rate: edge = 0.11, kelly = 0.129, stake = 25 + 0.0647 × 75 = $29.85, ×0.70 = $20.90 → clamped up to $25.00 (base). Early on — the performance tracker starts around 50% — nearly every stake is exactly base_stake, so treat PO_BASE_STAKE as your effective per-trade risk.
Note: stake sizing uses payout 0.85 as a hardcoded argument in src/bot.py, not a live payout quote; results are also booked at 0.85.
Daily loss limit
MoneyManager accumulates realized profit into daily_pnl. Before every trade, can_trade() requires:
daily_pnl > −max_daily_loss
Once cumulative losses reach PO_MAX_DAILY_LOSS ($300 default), the trade loop logs ⏸ Daily loss limit reached and stops opening trades. The counter resets when the UTC calendar date changes (New day — resetting daily P&L tracker) — not at your local midnight. The counter is in-memory only: restarting the bot resets it, so don’t restart to “unlock” trading after a bad day.
Consecutive-loss cooldown
Tracked by the performance tracker and enforced in the trade loop: after max_consec_losses (default 3) losses in a row, the bot logs Hit N consecutive losses → cooldown 300s and blocks trading for cooldown_seconds (default 300 s = 5 minutes), then resets the streak counter. Both values are config-only fields (max-consec-losses, cooldown-seconds).
Adaptive cooldowns
Independently of the fixed cooldown, AdaptiveStrategy reviews the last trades every 25 results and sets an extra minimum wait between trades based on the rolling last-10 win rate:
| Recent-10 win rate | Extra cooldown | Log |
|---|---|---|
| < 30% | 300 s | 🥶 Recent WR X% — adding 5min cooldown |
| < 40% | 120 s | 😐 Recent WR X% — adding 2min cooldown |
| ≥ 40% | 0 s | (cleared; 🔥 On fire! above 65%) |
While active you’ll see ⏸ Adaptive cooldown (Ns) diagnostics. The adaptive layer can also block whole regimes and UTC hours and shift the confidence threshold — see Adaptive strategy.
Concurrency and pacing limits
- Max concurrent trades:
max_concurrent_trades(default 1) — no new trade while one is pending. Diagnostic:⏸ Max trades open (1/1). - Minimum wait between trades:
min_wait_between_trades(default 60 s) from the moment the last trade was placed. Diagnostic:⏸ Wait between trades (Ns left).
Both are config-only fields (max-concurrent-trades, min-wait-between-trades).
Trading-hours filter
trading_hours (config-only, trading-hours) whitelists UTC hours. Default: (0, 1, 2, 3, 4, 16, 17, 19, 20, 21, 22, 23) — the code comment attributes the exclusion of 08–15 UTC (and 5–7, 18) to a 546-trade analysis showing consistent losses in those hours. Outside the whitelist the bot logs ⏸ Outside trading hours (HH UTC) and does nothing. Set trading_hours to an empty tuple to trade around the clock (the banner then shows Hours: all).
Layered defense summary
per trade : stake = fractional-Kelly × confidence, clamped [base, max]
per streak : 3 losses → 300 s cooldown; cold last-10 WR → +120/300 s
per day : stop at −$max_daily_loss (UTC-day reset)
always : ≤1 open trade, ≥60 s between trades, UTC-hours whitelistRisk note
These mechanisms limit — but cannot eliminate — losses. Binary options risk the entire stake on every trade; a full losing day still costs max_daily_loss, and the daily limit resets on restart because it is not persisted. Past performance, including any win-rate statistics the bot itself reports, does not guarantee future results. Size PO_BASE_STAKE, PO_MAX_STAKE, and PO_MAX_DAILY_LOSS to amounts you can afford to lose.
See also
- PO_BASE_STAKE, PO_MAX_STAKE, PO_MAX_DAILY_LOSS
- kelly_fraction
- Signal gates — the quality filters that run before money management
- Live trading
💬 Questions about running AthenaAI? Ask in the #trading-bots channel on the Chipa Discord — and if you’d rather design strategies without touching Python, try ChipaEditor.