Adaptive Strategy

🦉 AthenaAI is an AI-powered ensemble machine-learning trading bot for PocketOption, built on BinaryOptionsToolsV2Get 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:

DimensionKeysExample bucket
Regimeregime name string"trending_up": {wins: 12, losses: 8}
Hour0–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_adjEffect
WR < 0.50+0.05Raises the effective minimum confidence by 5 percentage points
WR > 0.55−0.03Lowers it by 3 points — take more opportunities
otherwise0.0No 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 WRadaptive_cooldownLog
< 0.30300 s (5 min)🥶 Recent WR ...% — adding 5min cooldown
< 0.40120 s (2 min)😐 Recent WR ...% — adding 2min cooldown
≥ 0.400(> 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:

  1. Regime in blocked_regimes → reject.
  2. Hour in blocked_hours → reject.
  3. Non-preferred direction and confidence < base_min_conf + 0.08 → reject.
  4. 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

💡 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.