Architecture
End-to-end pipeline
Capital.com REST (FX candles, account, orders)
│
▼
CapitalDataFeed absolute-minute poll + DTO normalize
│
▼
Indicator state per (symbol, timeframe)
│
┌────┴────┐
HTF LTF
4H / 1H 15m / 5m / 1m
│ │
structure fu_candle
+ zones BullFU / BearFU
│ │
└────┬────┘
▼
mtf_aggregator → confluence (FU + Zone + Bias) → Signal
│
┌────┴────────────────┐
1M Other LTF
│ │
TradeExecutor NotificationDispatcher
(live bid/offer → WhatsApp / Pindo SMS
SL/TP + POST → JSONL + /notifications
/positions)Lifecycle (per candle)
- Poller wakes on absolute minute boundaries.
- Closed candles advance indicator state; the latest bar is the forming candle.
structure.pyupdates HTF bias (BULLISH / BEARISH / NEUTRAL).zones.pyages, mitigates, and emits ACTIVE supply/demand zones.fu_candle.pychecks the forming LTF candle for bull/bear FU.- Forming FU + aligned bias + price inside a confluent HTF zone → Signal. Closed-candle FU does not create trade signals.
- 1M →
TradeExecutoranchors SL/TP to live bid/offer and places via CapitalPOST /api/v1/positions(no notification). - Other LTFs →
NotificationDispatcherfans out toNOTIFICATION_NUMBERS.
Monitoring endpoints: /signals, /zones, /notifications. Each placed order appends an
execution event to INDICATOR_EVENT_LOG_PATH.
Timeframes
| Role | Timeframes | What it does |
|---|---|---|
| HTF Bias | 4H, 1H | CHoCH/BOS → BULLISH / BEARISH / NEUTRAL |
| HTF Zones | 4H, 1H | Supply/demand from confirmed swing sweeps |
| LTF Entry | 15m, 5m | Forming FU → WhatsApp/SMS |
| LTF Auto-execute | 1m | Forming FU → TradeExecutor |
Rule: bias and zones on HTF; FU trigger on LTF only when price is inside a HTF zone and bias aligns
(unless FU_ONLY_MODE=true).
Auto-execution on 1M
When CAPITAL_EXECUTION_ENABLED=true and 1M is in LTF_TIMEFRAMES, 1M FU signals place
positions instead of notifying.
SL/TP are anchored to live market so stale candle levels never land on the wrong side of price:
| Direction | Entry | SL | TP |
|---|---|---|---|
| BUY | offer | offer × (1 − SL_PCT/100) | offer × (1 + SL_PCT/100 × RR_TARGET) |
| SELL | bid | bid × (1 + SL_PCT/100) | bid × (1 − SL_PCT/100 × RR_TARGET) |
Levels are then pushed clear of the broker’s minimum stop distance (+ spread) ×
CAPITAL_EXECUTION_SAFETY_MULTIPLIER.
| Status | When |
|---|---|
PLACED | Broker accepted; includes dealReference and levels actually sent |
FAILED | Broker rejected; poller keeps running |
SKIPPED | No live bid/offer — order not attempted |
Kill switches
CAPITAL_EXECUTION_ENABLED=false(default) — every signal notifies regardless of timeframe.- Drop
1MfromLTF_TIMEFRAMES— stop generating 1M signals. CAPITAL_EXECUTION_USE_MARKET_DISTANCE=false— send signalsl/tp(broker-distance net still runs).- Stay on
CAPITAL_ENVIRONMENT=demountil live trades are reviewed.
Notifications
WhatsApp Cloud API + Pindo SMS. Free-form WhatsApp only delivers inside the 24-hour customer-care
window; set WHATSAPP_TEMPLATE_NAME for unsolicited sends (placeholders {{1}}…{{8}}: direction,
symbol, timeframe, entry, SL, TP, R:R, bias). SMS is capped at ~150 characters.
Log lifecycle: pending → sent → delivered → read, or failed. Events append to
NOTIFICATIONS_LOG_PATH as JSONL.