Files
ForexBot2/LOGIC.md
T
Harwinder 492b39313a Scan only M15 and H1; keep D1 as confirmation, drop W1 entirely
Trades are intraday (M15/H1) only. D1 stays as a confirmation TF
for both so higher-timeframe trend context still gates A/A+ grades.
W1 is no longer used anywhere — removes one batch call.

Scan now: 3 batch calls (M15, H1, D1) × 7 pairs = 21 credits, ~2 min.
Was:      4 batch calls (M15, H1, D1, W1) = 28 credits, ~3 min.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-05 14:13:44 -04:00

227 lines
9.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ForexBot2 — Engine Logic Reference
## 1. Data Provider (Twelve Data API)
### What the API provides
Each API call returns an OHLCV time series for a currency pair:
| Field | Description |
|----------|------------------------------------|
| Datetime | UTC timestamp of the candle open |
| Open | Opening price |
| High | Highest price during the candle |
| Low | Lowest price during the candle |
| Close | Closing price |
| Volume | Tick volume (limited on Forex) |
Supported intervals: 1min, 5min, 15min, 30min, 1h, 4h, 1day, 1week.
### Supported pairs (free tier — live data)
EURUSD, GBPUSD, USDJPY, USDCHF, AUDUSD, USDCAD, NZDUSD,
EURGBP, EURJPY, GBPJPY, AUDJPY, EURCHF, CADJPY.
All other symbols (XAU, XAG, indices) return no data on the free plan.
### API credit limits (free tier)
- 8 credits per minute
- 800 credits per day
- 1 credit per symbol in a batch request
(7 pairs in one request = 7 credits, not 7 requests)
### Data validation and cleaning
After every fetch the data goes through `_validate_and_clean`:
1. Drop rows where all of Open/High/Low/Close are NaN
2. Forward-fill small gaps (max 3 consecutive bars)
3. Drop rows still missing Close
4. Remove bars with future timestamps (> 5 min ahead of now)
5. Fix OHLC inconsistencies (e.g. High < Low) by clamping
6. Remove extreme outlier bars (> 10 standard deviations return)
7. Sort index and deduplicate (keep last on duplicates)
---
## 2. How Many API Calls Are Made
### Per scan or /signal command
The bot does **one shared prefetch** before spawning TF analyses.
It collects all unique timeframes needed across scans, then makes
one batch API call per timeframe (all pairs in a single request).
Current SCAN_TIMEFRAMES: M15, H1 (only intraday trade signals)
Confirmations:
- M15 uses: H1, D1
- H1 uses: M15, D1
D1 is kept as a confirmation for higher-timeframe trend context but
no D1 trade signals are produced. W1 has been dropped entirely.
Unique timeframes: M15, H1, D1 = **3 batch calls**
Each call: 7 pairs × 1 credit = **7 credits per call**
Total per scan: **3 calls × 7 credits = 21 credits**
With the 8 credits/minute limit:
- Call 1 (7 credits): fires immediately — 1 credit remaining
- Call 2 (7 credits): must wait ~60s for window to clear
- Call 3 (7 credits): waits another ~60s
**Minimum scan time: ~2 minutes.**
After the shared prefetch, the 4 concurrent TF analyses read from
the in-memory cache and make **zero additional API calls**.
### Cache behaviour
Results are cached per symbol+timeframe for `refresh_interval` seconds
(default in PlatformConfig). A second scan within that window skips all
API calls entirely and returns cached data instantly.
---
## 3. Technical Engine — How Signals Are Decided
### Step 1 — Fetch OHLCV data
Primary timeframe data is fetched first. If it fails, the report is
immediately graded F and returned — no further analysis is attempted.
Confirmation timeframe data is fetched next; failures are logged as
warnings but do not abort the analysis.
### Step 2 — Compute 11 indicators
Each indicator returns: value, signal (STRONG_BUY / BUY / NEUTRAL /
SELL / STRONG_SELL), confidence (0–100), and a weight.
| Indicator | Weight | What it measures |
|------------------|--------|-----------------------------------------------|
| EMA Trend | 1.2 | Alignment of fast/medium/slow/trend EMAs |
| MACD | 1.1 | Momentum crossover and histogram direction |
| Ichimoku | 1.1 | Cloud position, TK cross, cloud colour |
| RSI | 1.0 | Overbought/oversold momentum |
| ADX | 1.0 | Trend strength and directional index |
| Bollinger Bands | 0.9 | Price position within volatility envelope |
| Stochastic | 0.8 | Oscillator crossover in OB/OS zones |
| Candlestick | 0.7 | Pattern detection (hammer, engulfing, doji…) |
| Divergence | 1.5 | RSI/MACD divergence from price (reversal) |
| Pivot Points | 0.6 | Classical pivot S/R relative to current price |
| ATR / Volume | 0.0 | Context only — not included in score |
Divergence has the highest weight (1.5) because divergences are strong
reversal predictors. ATR and Volume have weight 0 — they inform the
trade setup and volatility regime but do not vote on direction.
### Step 3 — Classify market regime
Using ADX value and EMA direction:
- `trending_up` / `trending_down`: ADX ≥ strong threshold + EMA aligned
- `ranging`: ADX below threshold
The regime changes indicator weights for the composite score:
- **Trending**: EMA (×1.5), ADX (×1.3), MACD (×1.2) weighted up;
RSI (×0.7) and Bollinger (×0.6) weighted down
- **Ranging**: RSI (×1.4), Bollinger (×1.4), Stochastic (×1.3)
weighted up; EMA (×0.6) and ADX (×0.5) weighted down
### Step 4 — Compute composite score (−100 to +100)
For each indicator:
```
weighted_score = signal_value × weight × regime_multiplier × (confidence / 100)
```
Signal values: STRONG_BUY = +2, BUY = +1, NEUTRAL = 0, SELL = −1, STRONG_SELL = −2
Final composite score = (sum of weighted scores / total weight) × 50
Composite signal thresholds:
- score ≥ +40 → STRONG BUY
- score ≥ +15 → BUY
- score ≤ −40 → STRONG SELL
- score ≤ −15 → SELL
- otherwise → NEUTRAL
### Step 5 — Multi-timeframe (MTF) agreement check
All timeframe signals (primary + confirmations) are collected.
MTF agreement = True if at least `mtf_agreement_threshold` timeframes
all point bullish or all point bearish.
Effect on confidence:
- **Agreement**: confidence +15 (capped at 95); score blended with
average of all TF scores (60% primary, 40% MTF average)
- **Disagreement**: confidence ×0.7
- **Conflict** (some bullish, some bearish): confidence ×0.7 × 0.6 = ×0.42
+ warning added to report
### Step 6 — Fundamental adjustments
Applied in order, each multiplying confidence:
| Condition | Confidence adjustment |
|----------------------------------|-----------------------|
| News aligns with technical | +5 (capped 95) |
| News conflicts with technical | ×0.85 |
| Event risk: caution | ×0.70 |
| Event risk: danger | ×0.30 + block signal |
| Volatility: extreme | ×0.80 |
### Step 7 — Final signal determination
Uses the adjusted score and confidence:
| Condition | Signal |
|----------------------------------|-------------|
| score ≥ +40 and confidence ≥ 65 | STRONG BUY |
| score ≥ +15 and confidence ≥ 50 | BUY |
| score ≤ −40 and confidence ≥ 65 | STRONG SELL |
| score ≤ −15 and confidence ≥ 50 | SELL |
| otherwise | NEUTRAL |
### Step 8 — Quality grade
Combines score, confidence, and MTF agreement into a letter grade:
| Grade | abs(score) | confidence | MTF agreement |
|-------|-----------|------------|---------------|
| A+ | ≥ 50 | ≥ 75 | required |
| A | ≥ 35 | ≥ 65 | required |
| B | ≥ 25 | ≥ 55 | not required |
| C | ≥ 15 | ≥ 45 | not required |
| D | ≥ 10 | any | not required |
| F | < 10 | any | — |
A+ and A require MTF agreement as a hard condition — no matter how
strong the primary score, without timeframe alignment the grade caps at B.
### Step 9 — Trade setup (grades A+, A, B only)
Entry = current close price
Stop Loss = entry ± (ATR × 1.5)
Take Profit 1 = entry ± (SL distance × R:R ratio)
Take Profit 2 = entry ± (SL distance × R:R ratio × 1.5)
ATR is used as the volatility measure so SL/TP adapt to current
market conditions rather than using fixed pip distances.
---
## 4. Signal Flow Summary
```
Telegram /scan or /signal
│
▼
_analyze_all_tfs(pairs)
│
├── prefetch_batch(pairs, [M15, H1, D1])
│ ├── Batch call 1: all pairs @ M15 (7 credits, wait if needed)
│ ├── Batch call 2: all pairs @ H1 (7 credits, wait if needed)
│ └── Batch call 3: all pairs @ D1 (7 credits, wait if needed)
│
└── 2 threads (M15 + H1), all reading from warm cache
│
└── per thread: SignalAggregator.analyze_all_pairs()
│
└── per pair: analyze_pair()
├── fetch_ohlcv (cache hit)
├── TechnicalEngine.analyze()
│ ├── 11 indicators
│ ├── Regime classification
│ └── Composite score
├── MTF agreement check
├── News / event risk adjustments
├── Final signal + grade
└── Trade setup (A+/A/B only)
```