Adaptive Strategy
🦉 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
AdaptiveStrategy (in src/trading/strategy.py) is a meta-layer on top of the ensemble: instead of predicting price, it audits the bot’s own results and shuts off the conditions under which the bot loses. It is the final gate in the signal pipeline — a trade that clears every other check can still be vetoed here.
The four tracked dimensions
Every resolved trade is fed in via record_trade(direction, regime, confidence, hour, result) (called from the result checker in src/bot.py, and replayed from the SQLite journal on restart). Wins and losses are bucketed along four independent dimensions:
| Dimension | Keys | Example bucket |
|---|---|---|
| Regime | regime name string | "trending_up": {wins: 12, losses: 8} |
| Hour | 0–23 (UTC hour of trade entry) | 14: {wins: 3, losses: 9} |
| Direction | "call" / "put" | |
| Confidence band | "low" (< 0.70), "med" (0.70–0.79), "high" (≥ 0.80) |
A rolling deque of the last 50 trades is also kept for recent-momentum analysis.
The review cycle
The bot constructs the strategy with review_interval=25, min_samples=15 (src/bot.py). Every 25 recorded trades _review() runs; within it, each rule only acts on buckets with at least 15 samples — below that, the win-rate estimate is considered too noisy to act on. A bucket’s win rate is wins / (wins + losses) (0.5 when empty).
Review results are logged under the header 🧠 Adaptive Strategy Review (after N trades): and summarized at the end: 🧠 Review complete. Blocked regimes: ... | Blocked hours: ... | Conf adj: ....
1. Regime blocking — WR < 0.48
Every regime bucket with ≥15 trades and a win rate below 48% is added to blocked_regimes (log: ⛔ Blocking regime '...'). The set is cleared and rebuilt on every review, so a regime that recovers gets unblocked at the next review.
2. Hour blocking — WR < 0.47
Every UTC hour with ≥15 trades and win rate below 47% joins blocked_hours. This operates on top of the static trading_hours whitelist in BotConfig — hours can be individually learned-out even inside the allowed schedule.
3. Direction preference — asymmetric 0.45 / 0.55
If both directions have ≥15 trades, and one direction’s win rate is below 45% while the other’s is above 55%, the winning direction becomes preferred_direction (log: 🔄 Favoring PUT trades ...). Requiring both conditions avoids penalizing a direction merely for a small edge gap.
A non-preferred direction is not hard-blocked. Instead, should_trade demands extra conviction: the trade must clear base_min_conf + 0.08 (i.e. default 0.63 → 0.71) or it is rejected with Non-preferred direction '...' needs conf ≥....
4. Confidence adjustment — +0.05 / −0.03
Based on the low confidence band (< 0.70):
| Low-band condition (≥15 samples) | confidence_adj | Effect |
|---|---|---|
| WR < 0.50 | +0.05 | Raises the effective minimum confidence by 5 percentage points |
| WR > 0.55 | −0.03 | Lowers it by 3 points — take more opportunities |
| otherwise | 0.0 | No change |
should_trade enforces confidence >= base_min_conf + confidence_adj.
5. Adaptive cooldown from recent momentum
If at least 10 trades are in the rolling window, the win rate of the last 10 trades sets an extra between-trade cooldown:
| Recent-10 WR | adaptive_cooldown | Log |
|---|---|---|
| < 0.30 | 300 s (5 min) | 🥶 Recent WR ...% — adding 5min cooldown |
| < 0.40 | 120 s (2 min) | 😐 Recent WR ...% — adding 2min cooldown |
| ≥ 0.40 | 0 | (> 0.65 logs 🔥 On fire!) |
The trade loop reads this via get_extra_cooldown() and refuses to trade until that many seconds have passed since the last trade — an automatic “step away from the table” when the bot is cold. This is separate from, and additive to, the fixed min_wait_between_trades (60 s) and the consecutive-loss cooldown (cooldown_seconds, 300 s after max_consec_losses).
The should_trade gate
Called last in the trade loop with the candidate trade’s direction, regime, confidence, current UTC hour, and cfg.min_confidence. Checks in order:
- Regime in
blocked_regimes→ reject. - Hour in
blocked_hours→ reject. - Non-preferred direction and confidence <
base_min_conf + 0.08→ reject. - Confidence <
base_min_conf + confidence_adj→ reject.
Rejections are logged by the bot as 🧠 Adaptive skip: <reason> (conf=...%).
Persistence
The strategy object itself is not pickled. Instead, on startup _reload_from_journal() in src/bot.py replays every completed trade from the SQLite journal through record_trade, which naturally re-triggers reviews every 25 trades and reconstructs the blocked sets, direction preference, confidence adjustment, and cooldown state (log: 🧠 Adaptive strategy loaded N past trades — [...]).
Risk note: adaptive blocking reduces exposure to historically losing conditions, but it reacts after losses have already occurred and can over-fit to short streaks. It is a damage limiter, not a guarantee of profitability.
See also
- Signal gates — where this gate sits in the pipeline
- Regime detection — the regime labels being tracked
- Risk management guide
- PO_MIN_CONF, trading-hours, cooldown-seconds
- API reference: src.trading.strategy
💡 Want to discuss how AthenaAI makes decisions — or design your own logic like this without writing code? Join the Chipa Discord and give ChipaEditor a try.