Strip backtesting, rebalance indicator weights toward leading signals
Remove backtest.py, backtest_gpu.py, metrics.py, local CSV data, Dukascopy loader, and all backtest CLI modes from main.py. Rebalance engine weights: leading indicators (divergence, RSI, stochastic, BB) now carry 66% of signal weight vs 34% for lagging (EMA, MACD). Add ws_twelvedata.py for live tick streaming. Drop pyarrow and tqdm deps.
This commit is contained in:
@@ -1,15 +1,11 @@
|
||||
"""
|
||||
ForexBot2 — Configuration (USD/JPY focus)
|
||||
==========================================
|
||||
Single-pair signal & backtest configuration.
|
||||
All knobs that govern indicator behavior, signal scoring, news handling,
|
||||
and the walk-forward backtester live here.
|
||||
"""
|
||||
|
||||
import os
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Dict, List
|
||||
|
||||
|
||||
class Timeframe(Enum):
|
||||
@@ -85,23 +81,7 @@ class TechnicalConfig:
|
||||
pivot_lookback: int = 1
|
||||
divergence_lookback: int = 14
|
||||
|
||||
# Ablation control — names listed here are skipped during analyze().
|
||||
# Use lowercase keys: ema_trend, rsi, macd, bollinger, stochastic,
|
||||
# adx, ichimoku, divergence, candlestick, pivot, atr, volume.
|
||||
#
|
||||
# Defaults disable indicators that empirically hurt P&L on USD/JPY across
|
||||
# 2024-trend / 2023-chop / 2026-recent ablation sweeps (see project memory):
|
||||
# - pivot: net +9.5% to disable across 3 windows
|
||||
# - candlestick: net +3.4% to disable
|
||||
disabled_indicators: List[str] = field(
|
||||
default_factory=lambda: ["pivot", "candlestick"]
|
||||
)
|
||||
|
||||
|
||||
ALL_INDICATORS: List[str] = [
|
||||
"ema_trend", "rsi", "macd", "bollinger", "stochastic",
|
||||
"adx", "ichimoku", "divergence", "candlestick", "pivot",
|
||||
]
|
||||
disabled_indicators: List[str] = field(default_factory=list)
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -141,67 +121,15 @@ class NewsConfig:
|
||||
|
||||
|
||||
@dataclass
|
||||
class BacktestConfig:
|
||||
"""Walk-forward backtest configuration."""
|
||||
# Data window — None means "all available history"
|
||||
start_date: Optional[str] = None # "YYYY-MM-DD"
|
||||
end_date: Optional[str] = None # "YYYY-MM-DD"
|
||||
max_bars: int = 5000 # Twelve Data ceiling per request
|
||||
|
||||
# Account & sizing
|
||||
initial_balance: float = 10_000.0
|
||||
risk_per_trade_pct: float = 1.0 # % of equity risked per trade
|
||||
|
||||
# Execution realism
|
||||
use_spread_cost: bool = True
|
||||
slippage_pips: float = 0.5 # added to spread on entry & exit
|
||||
one_position_only: bool = True
|
||||
sl_first_on_tie: bool = True # if SL & TP both inside bar, SL hits first
|
||||
|
||||
# Signal gates
|
||||
min_trade_grade: str = "B" # "A+", "A", "B", "C", "D", "F"
|
||||
min_abs_score: float = 0.0 # |final_score| must exceed this to enter
|
||||
|
||||
# Sanity-test knob — flip BUY↔SELL to see if the engine has reversed edge
|
||||
invert_signal: bool = False
|
||||
|
||||
# Regime gate — only trade when a higher-TF trend is confirmed
|
||||
class FilterConfig:
|
||||
"""Regime and session filters for live signals."""
|
||||
regime_filter: bool = False
|
||||
regime_filter_timeframe: Timeframe = Timeframe.H4
|
||||
regime_filter_min_adx: float = 25.0
|
||||
|
||||
# Session gate — only trade during a specified UTC hour window.
|
||||
# 2026 diagnostic backtest showed 07-15 UTC (London + NY) had
|
||||
# 47% WR / +127 pips while off-hours were 0% WR / -571 pips.
|
||||
session_filter: bool = False
|
||||
session_start_hour: int = 7 # UTC, inclusive
|
||||
session_end_hour: int = 16 # UTC, exclusive — so trades fire on 07..15
|
||||
|
||||
# Auto-toggle: enable session filter ONLY when recent realised trades
|
||||
# show adverse expectancy (mean pnl_pct over the last N closed trades
|
||||
# below threshold). Releases automatically once expectancy recovers.
|
||||
# Designed so trending regimes keep all hours, while adverse/chop
|
||||
# regimes auto-restrict to liquid sessions.
|
||||
auto_session_filter: bool = False
|
||||
auto_session_lookback_trades: int = 10
|
||||
auto_session_threshold_pct: float = -0.3
|
||||
|
||||
# Parallelism (used by Optimizer; single-run backtest is sequential)
|
||||
parallel_workers: int = field(default_factory=lambda: os.cpu_count() or 4)
|
||||
|
||||
# Optimizer
|
||||
optimize: bool = False
|
||||
param_grid: Dict[str, list] = field(default_factory=lambda: {
|
||||
# 2 × 2 × 3 × 2 × 2 = 48 combos
|
||||
"atr_sl_multiplier": [1.5, 2.5],
|
||||
"default_rr_ratio": [1.5, 2.5],
|
||||
"min_abs_score": [15.0, 35.0, 60.0],
|
||||
"min_trade_grade": ["B", "A"],
|
||||
"invert_signal": [False, True],
|
||||
})
|
||||
|
||||
# Cache directory for fetched OHLCV (parquet)
|
||||
cache_dir: str = ".cache"
|
||||
session_start_hour: int = 7
|
||||
session_end_hour: int = 16
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -210,7 +138,7 @@ class PlatformConfig:
|
||||
technical: TechnicalConfig = field(default_factory=TechnicalConfig)
|
||||
signals: SignalConfig = field(default_factory=SignalConfig)
|
||||
news: NewsConfig = field(default_factory=NewsConfig)
|
||||
backtest: BacktestConfig = field(default_factory=BacktestConfig)
|
||||
backtest: FilterConfig = field(default_factory=FilterConfig)
|
||||
|
||||
symbol: str = USDJPY
|
||||
display_name: str = DISPLAY
|
||||
@@ -221,12 +149,10 @@ class PlatformConfig:
|
||||
default_factory=lambda: [Timeframe.M15, Timeframe.H4]
|
||||
)
|
||||
|
||||
data_lookback_days: int = 60 # enough for 200 EMA on H1
|
||||
data_lookback_days: int = 60
|
||||
|
||||
twelve_data_api_key: str = "f563b22ffdfd4924955decbe1a8c8701"
|
||||
|
||||
refresh_interval: int = 300 # 5 min cache TTL
|
||||
refresh_interval: int = 300
|
||||
|
||||
log_level: str = "INFO"
|
||||
log_signals_to_file: bool = True
|
||||
signal_log_path: str = "signals.log"
|
||||
|
||||
Reference in New Issue
Block a user