Add LOGIC.md — engine decision flow, API call count, indicator weights

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Harwinder
2026-05-05 14:01:48 -04:00
parent 683d070a41
commit 2f6eed7309
+227
View File
@@ -0,0 +1,227 @@
# 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 the 4 TF analyses.
It collects all unique timeframes needed across all scans, then makes
one batch API call per timeframe (all pairs in a single request).
Current SCAN_TIMEFRAMES: M15, H1, D1, W1
Confirmations:
- M15 uses: H1, D1
- H1 uses: M15, D1
- D1 uses: H1, W1
- W1 uses: D1
Unique timeframes: M15, H1, D1, W1 = **4 batch calls**
Each call: 7 pairs × 1 credit = **7 credits per call**
Total per scan: **4 calls × 7 credits = 28 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
- Call 4 (7 credits): waits another ~60s
**Minimum scan time: ~3 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, W1])
│ ├── 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)
│ └── Batch call 4: all pairs @ W1 (7 credits, wait if needed)
│
└── 4 threads (one per TF), 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)
```