An autonomous multi-agent trading signal system. Data flows from Yahoo Finance through 7 AI agents, an ensemble scorer, and a paper trading engine — all connected via RabbitMQ.
Every 5 minutes, the data-pipeline fetches new 1h candles from Yahoo Finance for all watchlist symbols, stores them in TimescaleDB, then publishes a message to RabbitMQ. All agents consume that message, run their analysis, and publish results back. The orchestrator collects everything, runs the ensemble scorer, and paper-trades if conditions are met.
Role: Fetches market data from Yahoo Finance every 5 minutes and stores 1-hour candles in TimescaleDB.
| Parameter | Value | Role |
|---|---|---|
| Fetch interval | 5 minutes | How often new data is pulled |
| Candle interval | 1h | Bar size for all analysis |
| Min rows per symbol | 50 | Minimum rows before agents analyze |
| Backfill days | 90 | Historical data fetched when adding a symbol |
Each agent analyzes the same data from a different angle. They run in parallel and publish their findings to RabbitMQ.
What it does: Computes classic technical indicators — RSI, MACD, EMA crossovers — and generates buy/sell signals at extreme readings.
| Parameter | Old | New | Role |
|---|---|---|---|
| RSI Oversold Tuned | < 30 | < 25 | Only signal BUY when RSI is deeply oversold |
| RSI Overbought Tuned | > 70 | > 75 | Only signal SELL when RSI is deeply overbought |
| MACD Strength Tuned | 0.70 fixed | 0.40 + hist% | Scales with crossover magnitude (capped at 0.90) |
| EMA Cross Strength | 0.80 | 0.80 | Confidence for golden/death cross (rare event) |
| RSI Period | 14 | 14 | Standard lookback for RSI calculation |
| MACD Parameters | 12/26/9 | 12/26/9 | Standard MACD fast/slow/signal EMAs |
RSI formula: strength = (threshold - rsi) / threshold. At RSI=10: old strength=0.67, new=0.60. MACD strength now rewards larger crossovers.
What it does: Measures volatility via ATR (Average True Range), sets dynamic stop-loss and take-profit levels, and follows the SMA(50) trend direction.
| Parameter | Old | New | Role |
|---|---|---|---|
| SL Multiple Tuned | 2.0× ATR | 2.0× ATR | Stop-loss = price ∓ 2 × ATR (unchanged) |
| TP Multiple Tuned | 3.0× ATR | 2.0× ATR | Take-profit tightened from 3× to 2× ATR for more achievable targets on 1h candles |
| Volatility Warn | 4% | 4% | Warns when ATR exceeds 4% of price |
| Trend Filter | SMA(50) | SMA(50) | Direction follows 50-period moving average trend |
Why TP was tightened: At 3× ATR on 1h candles, take-profits were 2-4% away — rarely hit before 2× ATR stop-losses. Now risk:reward is 1:1, more achievable.
What it does: Trains an XGBoost classifier on 14 technical features (returns, volatility, volume ratios, RSI, MACD) to predict whether price will go up or down in the next 5 bars. Retrains automatically on each cycle.
| Parameter | Value | Role |
|---|---|---|
| Features | 14 | Technical indicators used for training |
| Prediction horizon | 5 bars (5h) | How far ahead the model predicts |
| Min samples | 100 | Minimum rows before training |
| Auto-retrain | Every cycle | Model retrains on latest data each run |
ML_PREDICTION weight in ensemble: 0.17 (was 0.15 — increased now that XGBoost crash is fixed).
What it does: Fetches latest news headlines from Yahoo Finance, scores them with VADER sentiment analysis, and signals when sentiment is strongly positive or negative.
| Parameter | Old | New | Role |
|---|---|---|---|
| Sentiment Threshold Tuned | ±0.35 | ±0.40 | Stricter threshold reduces VADER noise |
| Max Articles | 10 | 10 | Number of headlines analyzed |
| Strength Cap | 0.95 | 0.95 | Max confidence for news signals |
VADER scores range from -1 (very negative) to +1 (very positive). Threshold ±0.35 previously caught borderline sentiment.
What it does: Detects abnormal volume spikes (>2 standard deviations from the 20-bar mean), which often precede significant price moves.
| Parameter | Value | Role |
|---|---|---|
| Spike threshold | > 2.0σ | Standard anomaly detection (95th percentile) |
| Lookback period | 20 bars | Window for mean/std calculation |
| Min rows | 30 | Minimum data required |
What it does: Checks trend alignment across short (12h), medium (3 day), and long (10 day) timeframes. All 3 agreeing = high confidence signal.
| Parameter | Value | Role |
|---|---|---|
| SHORT period | 12 bars | ~12 hours of 1h candles |
| MEDIUM period | 72 bars | ~3 days |
| LONG period | 240 bars | ~10 days |
| All-agree strength | 0.75 | Confidence when all 3 align |
| Majority strength | 0.45 | Confidence when 2/3 agree |
What it does: Identifies swing highs/lows from the last 60 bars, then signals when price approaches these levels (potential bounce/rejection) or breaks through them (trend continuation).
| Parameter | Value | Role |
|---|---|---|
| Lookback | 60 bars | How far back to find S/R levels |
| Proximity threshold | 1.5% | How close price must be to a level before signaling |
| Breakout threshold | 0.5% | Minimum breakthrough to classify as breakout |
Role: Collects all agent signals and consolidates them into a single buy/sell/hold decision per symbol. Uses weighted voting with normalization.
| Signal Type | Old Weight | New Weight | Change | Why |
|---|---|---|---|---|
| RSI | 0.20 | 0.20 | — | Most influential technical indicator |
| MACD | 0.15 | 0.15 | — | Momentum confirmation |
| EMA_CROSS | 0.15 | 0.15 | — | Major trend change signal |
| ML_PREDICTION Tuned | 0.15 | 0.17 | +0.02 | XGBoost works now; more weight for ML |
| RISK Tuned | 0.05 | 0.12 | +0.07 | Best SL/TP provider deserves more voice |
| MULTI_TF | 0.15 | 0.15 | — | Trend confirmation across timeframes |
| VOLUME_ANOMALY | 0.10 | 0.10 | — | Volume spikes are reliable signals |
| S_R_LEVEL | 0.10 | 0.10 | — | Support/resistance proximity |
| NEWS_SENTIMENT Tuned | 0.10 | 0.08 | -0.02 | VADER can be noisy; reduced weight slightly |
| Parameter | Old | New | Role |
|---|---|---|---|
| CONFIDENCE_THRESHOLD | 0.25 | 0.25 | Minimum score to emit a consolidated signal |
| CONFLICT_MARGIN Tuned | 0.10 | 0.15 | Tighter — need stronger consensus before signaling |
The scorer normalizes by the sum of weights that actually fired, so only the relative proportions matter. Increasing RISK from 0.05→0.12 makes it 2.4× more influential when it fires.
Role: Manages a virtual $100K portfolio. Opens LONG positions on BUY consolidated signals, closes them on SELL signals. Uses risk-based position sizing.
| Parameter | Value | Role |
|---|---|---|
| Initial Capital | $100,000 | Starting portfolio value |
| Max Concurrent | 5 | Maximum open positions at once |
| Max Drawdown | 15% | Circuit breaker — stops trading if P&L drops this much |
| Risk Per Trade | 1% of equity | Risk-based sizing: loss if stopped out = 1% of portfolio |
| Fallback Notional | $1,000 | Used when no stop-loss is available for sizing |
When a BUY signal arrives with a stop-loss level, the engine calculates:
quantity = (equity × risk_per_trade_pct) / |entry - stop_loss|
This means every trade risks exactly 1% of current equity. If equity = $100K and SL is $5 away, position = $1,000 / $5 = 200 shares ($20,000 notional).
Role: Listens to RabbitMQ for consolidated signals and sends formatted Telegram messages. Also handles user commands.
| Command | Action |
|---|---|
/signals | Show latest signals for all symbols |
/watchlist | Show current watchlist |
/pnl | Show portfolio P&L and open positions |
/add SYMBOL | Add a symbol to watchlist |
/remove SYMBOL | Remove a symbol from watchlist |
/backtest SYMBOL | Run a backtest for a symbol |
Duplicate signals are suppressed for 60 minutes via fingerprint-based deduplication to avoid message spam.
Every 5 minutes:
1. Data Pipeline fetches 1h candles from Yahoo Finance
2. Writes to TimescaleDB (stock_data table)
3. Publishes "data.raw" message to RabbitMQ
4. All 7 agents consume the message in parallel:
┌─ Technical (RSI, MACD, EMA)
├─ Risk (ATR, SL/TP, SMA trend)
├─ Prediction (XGBoost — 14 features)
├─ News (VADER sentiment)
├─ Volume (z-score anomaly)
├─ Multi-TF (3 timeframes)
└─ S/R Level (support/resistance)
5. Each agent publishes signals to RabbitMQ
6. Orchestrator collects all signals
7. Ensemble Scorer consolidates into buy/sell/hold
8. Paper Trader executes (opens/closes positions)
9. Telegram Bot sends notification (if not duplicate)
| # | File | Change | Impact |
|---|---|---|---|
| 1 | technical_agent.py | RSI thresholds: 30→25 (oversold), 70→75 (overbought) | Fewer but more extreme RSI signals — less noise, higher quality |
| 2 | technical_agent.py | MACD strength: fixed 0.7 → 0.4 + hist% (capped 0.9) | Rewards genuine large crossovers; weak crossovers get lower confidence |
| 3 | risk_agent.py | TP_ATR_MULTIPLE: 3.0 → 2.0 | Tighter take-profits — more achievable on 1h candles, better risk:reward |
| 4 | signal_scorer.py | RISK weight: 0.05 → 0.12 | Risk agent's trend filter + ATR levels now have more ensemble influence |
| 5 | signal_scorer.py | ML_PREDICTION weight: 0.15 → 0.17 | XGBoost is fixed, deserves slightly more weight |
| 6 | signal_scorer.py | NEWS_SENTIMENT weight: 0.10 → 0.08 | VADER can be noisy, reduced slightly |
| 7 | signal_scorer.py | CONFLICT_MARGIN: 0.10 → 0.15 | Stronger consensus needed — reduces weak conflicting signals |
| 8 | news_agent.py | Sentiment threshold: ±0.35 → ±0.40 | Fewer but more reliable news signals |
After this page was created, run docker compose up -d --build ai-agents to deploy the tuned parameters.
After tuning, monitor these metrics to evaluate whether the changes helped: