Compare commits

..

2 Commits

Author SHA1 Message Date
Harwinder bc1844b233 Add requirements.txt and usage guide
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-04 10:51:03 -04:00
Harwinder 242df24ca7 Fixed Bugs 2026-05-04 10:51:03 -04:00
9 changed files with 199 additions and 29 deletions
+164
View File
@@ -0,0 +1,164 @@
# ForexBot2 — Usage Guide
## Setup
```bash
pip install -r requirements.txt
```
Set your Twelve Data API key (or it falls back to the key in `config.py`):
```bash
export TWELVE_DATA_API_KEY=your_key_here # Linux/Mac
set TWELVE_DATA_API_KEY=your_key_here # Windows CMD
$env:TWELVE_DATA_API_KEY="your_key_here" # PowerShell
```
---
## Basic Syntax
```
python main.py [OPTIONS]
```
---
## Options
| Option | Default | Description |
|---|---|---|
| `--pairs PAIR [PAIR ...]` | all major pairs | Specific pairs to analyze |
| `--timeframe TF` | `H1` | Primary timeframe: `M5 M15 M30 H1 H4 D1` |
| `--all` | off | Add EUR/GBP, EUR/JPY, GBP/JPY and other cross pairs |
| `--detail` | off | Full indicator breakdown per pair |
| `--top N` | all | Show only the top N signals by strength |
| `--min-grade GRADE` | `F` (show all) | Filter by minimum quality grade: `A+ A B C D F` |
| `--json` | off | Output results as JSON instead of the terminal UI |
| `--watch` | off | Continuous monitoring — refreshes every 5 minutes |
| `--verbose` / `-v` | off | Enable debug logging |
---
## Common Examples
### Analyze all major Forex pairs (default)
```bash
python main.py
```
Analyzes EUR/USD, GBP/USD, USD/JPY, USD/CHF, AUD/USD, USD/CAD, NZD/USD on H1.
---
### Analyze Gold (XAU/USD)
```bash
python main.py --pairs XAUUSD
```
Pass the symbol without the slash. The engine converts it to Twelve Data format automatically.
---
### Gold on the 4-hour chart with full detail
```bash
python main.py --pairs XAUUSD --timeframe H4 --detail
```
---
### Multiple pairs at once
```bash
python main.py --pairs XAUUSD EURUSD GBPUSD
```
---
### Only show high-conviction signals (Grade B or above)
```bash
python main.py --min-grade B
```
---
### Top 3 signals across all pairs including crosses
```bash
python main.py --all --top 3
```
---
### Continuous monitoring — updates every 5 minutes
```bash
python main.py --watch
```
Add `--pairs XAUUSD` to watch a single instrument, or `--all` for everything.
```bash
python main.py --pairs XAUUSD --watch --detail
```
---
### JSON output (for piping or logging)
```bash
python main.py --pairs XAUUSD --json
python main.py --all --json > signals.json
```
---
## Signal Grades
| Grade | Meaning |
|---|---|
| A+ | Strongest — all timeframes aligned, high confidence |
| A | Strong signal, minor divergence |
| B | Good setup, watch for confirmation |
| C | Weak — for reference only |
| D/F | Noise — best ignored |
---
## Supported Symbols
Pass any symbol without slashes. Examples:
| You type | Pair |
|---|---|
| `XAUUSD` | Gold vs USD |
| `EURUSD` | Euro vs USD |
| `GBPUSD` | British Pound vs USD |
| `USDJPY` | USD vs Japanese Yen |
| `GBPJPY` | GBP vs Japanese Yen |
| `USDCAD` | USD vs Canadian Dollar |
| `AUDUSD` | Australian Dollar vs USD |
Any pair supported by Twelve Data can be used.
---
## Output Explained
```
EUR/USD │ Price: 1.08423 │ Regime: trending_up │ Vol: normal
SIGNAL: STRONG BUY │ Score: +62.4 │ Grade: A │ Confidence: 74%
Action: Strong buy signal with multi-timeframe alignment...
Multi-Timeframe: ✓ ALIGNED
M15: BUY (+28.1)
H1: STRONG BUY (+62.4)
H4: BUY (+41.0)
Trade Setup:
Direction: BUY
Entry: 1.08423
Stop Loss: 1.08150 (27.3 pips)
Take Profit 1: 1.08970 (54.7 pips)
Take Profit 2: 1.09517
Risk:Reward: 1:2.0
```
- **Score** — ranges from -100 (strong sell) to +100 (strong buy)
- **Grade** — summary quality of the signal setup
- **Regime** — `trending_up`, `trending_down`, or `ranging`
- **Trade Setup** — auto-calculated entry, SL, and TP based on ATR
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+8 -6
View File
@@ -76,7 +76,7 @@ class TechnicalConfig:
rsi_neutral_upper: float = 60.0
rsi_neutral_lower: float = 40.0
# MACD (12, 26, 9 is standard but we validate)
# MACD (12, 26, 9 is standard)
macd_fast: int = 12
macd_slow: int = 26
macd_signal: int = 9
@@ -110,6 +110,9 @@ class TechnicalConfig:
# Pivot points lookback
pivot_lookback: int = 1
# Divergence detection — how many bars back to scan for swing points
divergence_lookback: int = 14
@dataclass
class SignalConfig:
@@ -130,10 +133,6 @@ class SignalConfig:
# Multi-timeframe confirmation requirements
mtf_agreement_threshold: int = 2 # out of 3 timeframes must agree
# Divergence detection sensitivity
divergence_lookback: int = 14
divergence_min_swing: float = 0.001 # minimum price swing for valid divergence
# Signal cooldown (prevent over-signalling same direction)
cooldown_bars: int = 5
@@ -185,10 +184,13 @@ class PlatformConfig:
# Data source
data_lookback_days: int = 60 # enough for 200 EMA on H1
# Twelve Data API key (overridden by TWELVE_DATA_API_KEY env var)
twelve_data_api_key: str = "f563b22ffdfd4924955decbe1a8c8701"
# Dashboard refresh interval (seconds)
refresh_interval: int = 300 # 5 minutes
# Logging
log_level: str = "INFO"
log_signals_to_file: bool = True
signal_log_path: str = "signals.log"
signal_log_path: str = "signals.log"
+3
View File
@@ -0,0 +1,3 @@
numpy>=1.24
pandas>=2.0
requests>=2.28
+24 -23
View File
@@ -16,16 +16,16 @@ Key principles:
import logging
from dataclasses import dataclass, field
from datetime import datetime, timezone
from typing import Dict, List, Optional, Tuple
from typing import Dict, List, Optional
import pandas as pd
from config import (
PlatformConfig, SignalStrength, Timeframe,
SYMBOL_DISPLAY, MAJOR_PAIRS, CROSS_PAIRS,
SYMBOL_DISPLAY,
)
from data_provider import ForexDataProvider
from technical_engine import TechnicalEngine, TechnicalAnalysis
from engine import TechnicalEngine, TechnicalAnalysis
from news_engine import NewsEngine, FundamentalContext
logger = logging.getLogger(__name__)
@@ -99,7 +99,7 @@ class SignalReport:
class SignalAggregator:
"""
Master signal aggregator.
Orchestrates data fetching, technical analysis across timeframes,
fundamental analysis, and produces final graded signals.
"""
@@ -118,6 +118,12 @@ class SignalAggregator:
reports = []
context = self.news_engine.get_fundamental_context()
# Batch-prefetch all pairs × all needed timeframes (3 API calls instead of 21)
all_timeframes = (
[self.config.primary_timeframe] + self.config.confirmation_timeframes
)
self.data_provider.prefetch_batch(self.config.watch_pairs, all_timeframes)
for symbol in self.config.watch_pairs:
try:
report = self.analyze_pair(symbol, context)
@@ -135,9 +141,7 @@ class SignalAggregator:
symbol: str,
context: Optional[FundamentalContext] = None,
) -> SignalReport:
"""
Complete analysis of a single pair across all layers.
"""
"""Complete analysis of a single pair across all layers."""
if context is None:
context = self.news_engine.get_fundamental_context()
@@ -227,7 +231,7 @@ class SignalAggregator:
def _compute_final_signal(self, report: SignalReport):
"""
Compute the final signal by combining all layers.
Priority:
1. Event risk can downgrade or block signals
2. MTF agreement boosts confidence
@@ -239,9 +243,8 @@ class SignalAggregator:
# ── MTF adjustment ─────────────────────────────────────────
if report.mtf_agreement:
# All timeframes agree — boost confidence
# All timeframes agree — boost confidence and blend scores
confidence = min(confidence + 15, 95)
# Average the MTF scores for more stable signal
all_scores = list(report.mtf_scores.values())
if all_scores:
mtf_avg = sum(all_scores) / len(all_scores)
@@ -251,7 +254,6 @@ class SignalAggregator:
confidence *= 0.7
if len(report.mtf_scores) >= 2:
scores = list(report.mtf_scores.values())
# Check for conflicting directions
has_bull = any(s > 10 for s in scores)
has_bear = any(s < -10 for s in scores)
if has_bull and has_bear:
@@ -259,7 +261,6 @@ class SignalAggregator:
confidence *= 0.6
# ── News sentiment adjustment ──────────────────────────────
sent_weight = self.config.signals.weights.get("sentiment", 0.1)
if abs(report.news_sentiment) > 0.2:
# Sentiment aligns with technical
if (report.news_sentiment > 0 and score > 0) or \
@@ -274,7 +275,7 @@ class SignalAggregator:
# ── Event risk adjustment ──────────────────────────────────
if report.event_risk == "danger":
report.warnings.append(f"EVENT RISK: {report.event_description}")
confidence *= 0.3 # Heavily penalize
confidence *= 0.3 # Heavily penalize — event will disrupt price action
report.action_recommendation = f"WAIT — {report.event_description}"
elif report.event_risk == "caution":
report.warnings.append(f"Upcoming event: {report.event_description}")
@@ -325,7 +326,7 @@ class SignalAggregator:
elif report.signal_quality == "B":
report.action_recommendation = f"{sig_name} — Decent setup, wait for confirmation"
elif report.signal_quality in ("C", "D"):
report.action_recommendation = f"WATCH — Signal present but low confidence"
report.action_recommendation = "WATCH — Signal present but low confidence"
else:
report.action_recommendation = "NO TRADE — No clear signal"
@@ -379,7 +380,14 @@ class SignalAggregator:
)
def _collect_reasons(self, report: SignalReport):
"""Collect bullish/bearish reasons from all indicators."""
"""
Collect bullish/bearish reasons from all indicators.
Each indicator's description is captured once via the indicators
dict. Pattern signals (candlestick) are already included in the
'candlestick' indicator description, so we do NOT re-process
pattern_signals to avoid duplicate entries.
"""
if not report.primary_analysis:
return
@@ -394,15 +402,8 @@ class SignalAggregator:
prefix = "STRONG: " if ind.signal == SignalStrength.STRONG_SELL else ""
report.bearish_reasons.append(f"{prefix}{ind.name}: {ind.description}")
# Add pattern signals
for pattern in report.primary_analysis.pattern_signals:
if any(kw in pattern.lower() for kw in ["bullish", "hammer", "buy"]):
report.bullish_reasons.append(f"Pattern: {pattern}")
elif any(kw in pattern.lower() for kw in ["bearish", "shooting", "sell"]):
report.bearish_reasons.append(f"Pattern: {pattern}")
# Add news context
if report.news_sentiment > 0.1:
report.bullish_reasons.append(f"News: {report.news_description}")
elif report.news_sentiment < -0.1:
report.bearish_reasons.append(f"News: {report.news_description}")
report.bearish_reasons.append(f"News: {report.news_description}")