AI Expiry Selection

๐Ÿฆ‰ 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

In binary options, choosing how long the trade runs matters almost as much as choosing the direction. ExpirySelector (in src/core/expiry.py) picks an expiry duration for every trade by scoring each candidate against six factors โ€” market regime, volatility, trend strength, model confidence, RSI extremes, and its own learned per-expiry track record โ€” and picking the highest score.

Candidate expiries

The candidates come from BotConfig.expiry_options. The class default is (60, 120, 180, 300) seconds, but the botโ€™s config default is (120, 300, 600) โ€” the v6 comment in src/config.py notes 60s and 180s were dropped as bad performers and 300s had the best observed win rate (69.2%). Configure via PO_EXPIRY_OPTIONS. Options are sorted ascending at construction.

select(regime, features, confidence) is called once per trade, right before order placement in src/bot.py, and returns the winning expiry in seconds.

Inputs read from the feature vector

The selector reads four indicators directly from the feature vector (with fallbacks if the vector is short):

IndicatorFeature indexFallback
volatility (return std)60.01
rsi1350.0
atr170.001
adx2425.0

Note: ATR is extracted but not used in any scoring rule in the current code โ€” only volatility, RSI, and ADX contribute.

The six scoring factors

Every candidate expiry starts at score 0.0 and accumulates the following. Brackets are inclusive threshold checks on the expiry value in seconds.

1. Regime

Regimeโ‰ค60sโ‰ค120sโ‰ค180sโ‰ฅ180sโ‰ฅ300s
Trending (up or down)+0.5+1.0โ€”+2.0+3.0
Volatile+3.0+2.0+1.0โ€”โˆ’1.0 (>180s)
Ranging+2.5 (โ‰ค120s)โ€”+2.0โ€”+1.0 (โ‰ค300s), +0.5 (>300s)

Read the code brackets precisely: for trending, exp >= 300 โ†’ +3.0, elif exp >= 180 โ†’ +2.0, elif exp >= 120 โ†’ +1.0, else +0.5. For volatile, exp <= 60 โ†’ +3.0, elif <= 120 โ†’ +2.0, elif <= 180 โ†’ +1.0, else โˆ’1.0. For ranging, exp <= 120 โ†’ +2.5, elif <= 180 โ†’ +2.0, elif <= 300 โ†’ +1.0, else +0.5. Trending markets reward riding the move longer; volatile markets punish exposure.

2. Volatility (return std, feature index 6)

ConditionEffect
volatility > 0.003 (high)exp <= 120 โ†’ +1.5; exp >= 300 โ†’ โˆ’1.0
volatility < 0.001 (low)exp >= 180 โ†’ +1.0; exp <= 60 โ†’ โˆ’0.5

High volatility favors short exposure; a quiet market needs more time to move at all.

3. ADX (trend strength, feature index 24)

ConditionEffect
adx > 30 (strong trend)exp >= 180 โ†’ +1.5; exp >= 300 โ†’ +0.5 more (cumulative: a 300s+ expiry gets +2.0)
adx < 15 (no trend)exp <= 120 โ†’ +1.0

4. Confidence

ConfidenceEffect
>= 0.75exp >= 180 โ†’ +1.5
>= 0.65exp >= 120 โ†’ +0.5
< 0.65exp <= 120 โ†’ +1.0; exp >= 300 โ†’ โˆ’1.0

Higher-confidence signals can afford longer expiries; marginal signals stay short. Note the ensemble clamp caps confidence at 0.78, so the โ‰ฅ0.75 branch is reachable but narrow.

5. RSI extremes

If rsi > 75 or rsi < 25 (reversal likely): exp <= 120 โ†’ +1.0; exp >= 300 โ†’ โˆ’0.5.

6. Learned past performance

This is the adaptive part. The selector keeps a win/loss counter per expiry duration, fed by record_result(expiry, result) after every resolved trade (called from the result checker in src/bot.py). Once an expiry has at least 5 recorded trades, its empirical win rate boosts or penalizes its score:

score += (wr - 0.50) * 5.0

So a 60% win rate adds +0.5, a 40% win rate subtracts โˆ’0.5, and a 70% winner earns +1.0 โ€” enough to overcome a factor-level disadvantage. Over time the selector converges toward durations that actually win on your account, regardless of what the heuristics say.

The highest-scoring expiry wins (max(scores, key=scores.get)); ties resolve to the first (shortest) candidate encountered.

Persistence

The learned stats survive restarts. AITradingBot._save_brain() pickles expiry_selector.save_state() (the stats dict plus the options list) to a companion file next to the brain: brain_path with .pkl replaced by _expiry.pkl โ€” with the default PO_BRAIN_PATH that is athena_po_brain_expiry.pkl. It is saved every 10 completed trades and on shutdown, and loaded at startup (log line: โฑ Expiry stats loaded: ...). See Persistence.

The running record also appears in trade logs via status_line(), e.g. 120s:55%(20) | 300s:69%(13) (win rate percent and trade count per expiry).

Risk note: the learned win rates are estimates from small samples โ€” with only 5 trades per expiry the boost can chase noise. Losses remain fully possible on any expiry.

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.