diff --git a/config.py b/config.py index 942e32b..b0fd579 100755 --- a/config.py +++ b/config.py @@ -155,7 +155,7 @@ class XauStrategyConfig: h4_rsi_gate: bool = False h1_macd_gate: bool = False rsi_zone: tuple = (40.0, 65.0) - allowed_weekdays: List[int] = field(default_factory=lambda: [0, 1, 2, 3, 4]) # Mon-Fri + allowed_weekdays: List[int] = field(default_factory=lambda: [0, 1, 2, 3, 4, 6]) # Mon-Fri + Sun (Sydney open) sell_min_quality: List[str] = field(default_factory=lambda: ["A+", "A", "B"]) @@ -171,7 +171,7 @@ class FilterConfig: session_end_hour: int = 23 blocked_hours_utc: List[int] = field(default_factory=lambda: [0, 1, 2]) - allowed_weekdays: List[int] = field(default_factory=lambda: [0, 1, 2, 3, 4]) + allowed_weekdays: List[int] = field(default_factory=lambda: [0, 1, 2, 3, 4, 6]) # Mon-Fri + Sun (Sydney open) @dataclass diff --git a/data_provider.py b/data_provider.py index 76be6ce..d67c483 100755 --- a/data_provider.py +++ b/data_provider.py @@ -18,6 +18,21 @@ from config import PlatformConfig, Timeframe, XAUUSD, PAIR_INFO logger = logging.getLogger(__name__) +def _is_forex_weekend(now=None) -> bool: + """Forex market closed: Friday 22:00 UTC → Sunday 22:00 UTC.""" + if now is None: + now = pd.Timestamp.now(tz="UTC") + wd = now.weekday() + hour = now.hour + if wd == 4 and hour >= 22: + return True + if wd == 5: + return True + if wd == 6 and hour < 22: + return True + return False + + class DataIntegrityError(Exception): """Raised when data fails validation checks.""" pass @@ -125,7 +140,7 @@ class ForexDataProvider: now = pd.Timestamp.now(tz="UTC") - if now.weekday() >= 5: + if _is_forex_weekend(now): return True last_bar = df.index[-1] diff --git a/signal_aggregator.py b/signal_aggregator.py index 6a71ed7..07cdf9f 100755 --- a/signal_aggregator.py +++ b/signal_aggregator.py @@ -21,6 +21,19 @@ from news_engine import NewsEngine, FundamentalContext logger = logging.getLogger(__name__) +def _is_forex_weekend(now_utc: datetime) -> bool: + """Forex market closed: Friday 22:00 UTC → Sunday 22:00 UTC (Sydney open).""" + wd = now_utc.weekday() + hour = now_utc.hour + if wd == 4 and hour >= 22: # Friday after 22:00 + return True + if wd == 5: # All Saturday + return True + if wd == 6 and hour < 22: # Sunday before 22:00 + return True + return False + + @dataclass class TradeSetup: pair: str @@ -108,7 +121,7 @@ class SignalAggregator: if pair_info["display"] == "XAU/USD" and self.config.xau_strategy.enabled: xau_cfg = self.config.xau_strategy - if xau_cfg.weekend_filter and now_utc.weekday() >= 5: + if xau_cfg.weekend_filter and _is_forex_weekend(now_utc): report = SignalReport( symbol=symbol, display_name=pair_info["display"], @@ -122,7 +135,7 @@ class SignalAggregator: return report if xau_cfg.allowed_weekdays and now_utc.weekday() not in xau_cfg.allowed_weekdays: - day_names = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri"} + day_names = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} allowed = "/".join(day_names.get(d, str(d)) for d in xau_cfg.allowed_weekdays) report = SignalReport( symbol=symbol, diff --git a/test_all.py b/test_all.py index 665f98f..14f7f0b 100644 --- a/test_all.py +++ b/test_all.py @@ -1491,7 +1491,7 @@ def _(): @test("SCAN_BUTTONS and SCAN_LOOKUP consistency") def _(): - assert len(SCAN_BUTTONS) == 4 # 3 TFs + "Scan All" + assert len(SCAN_BUTTONS) == 5 # 4 TFs + "Scan All" for btn in SCAN_BUTTONS: assert btn["cb"] in SCAN_LOOKUP assert "symbol" in btn