Claude Opus 4.6 improvements: MT5 concurrency fixes, timezone UTC fixes, sentiment scoring consistency, security validator, and 2025-2026 economic/gold lexicon updates
This commit is contained in:
@@ -112,7 +112,13 @@ class SentimentAggregator:
|
||||
data_points = len(self._recent_sentiments)
|
||||
confidence = min(data_points / 10, 1.0) # Max confidence with 10+ articles
|
||||
|
||||
# Direction
|
||||
# Also check from database
|
||||
db_sentiment = crud.get_recent_sentiment(hours=self.decay_hours)
|
||||
if db_sentiment != 0.0:
|
||||
# Blend with DB sentiment
|
||||
avg_score = avg_score * 0.7 + db_sentiment * 0.3
|
||||
|
||||
# Direction (determined after DB blend for consistency)
|
||||
if avg_score > 0.15:
|
||||
direction = "BULLISH"
|
||||
elif avg_score < -0.15:
|
||||
@@ -120,12 +126,6 @@ class SentimentAggregator:
|
||||
else:
|
||||
direction = "NEUTRAL"
|
||||
|
||||
# Also check from database
|
||||
db_sentiment = crud.get_recent_sentiment(hours=self.decay_hours)
|
||||
if db_sentiment != 0.0:
|
||||
# Blend with DB sentiment
|
||||
avg_score = avg_score * 0.7 + db_sentiment * 0.3
|
||||
|
||||
return {
|
||||
"direction": direction,
|
||||
"score": round(avg_score, 4),
|
||||
|
||||
@@ -307,4 +307,23 @@ def get_settings() -> Settings:
|
||||
global _settings
|
||||
if _settings is None:
|
||||
_settings = Settings()
|
||||
_validate_security(_settings)
|
||||
return _settings
|
||||
|
||||
|
||||
def _validate_security(settings: Settings):
|
||||
"""Emit warnings for insecure default credentials (non-breaking)."""
|
||||
import warnings
|
||||
|
||||
if settings.dashboard.secret_key == "change-me-in-production":
|
||||
warnings.warn(
|
||||
"⚠️ SECURITY: Dashboard secret_key is still the default. "
|
||||
"Set DASHBOARD_SECRET_KEY in your .env for production use.",
|
||||
stacklevel=2,
|
||||
)
|
||||
if settings.dashboard.password in ("", "admin123", "password"):
|
||||
warnings.warn(
|
||||
"⚠️ SECURITY: Dashboard password is weak/default. "
|
||||
"Set a strong DASHBOARD_PASSWORD in your .env.",
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
symbol: XAUUSD
|
||||
symbol_suffix: ''
|
||||
active_mode: safe
|
||||
active_mode: moderate
|
||||
trading_modes:
|
||||
safe:
|
||||
name: Safe / Conservative
|
||||
@@ -201,6 +201,22 @@ news:
|
||||
- recession
|
||||
- employment
|
||||
- GDP
|
||||
- BRICS
|
||||
- de-dollarization
|
||||
- dedollarization
|
||||
- central bank gold
|
||||
- sovereign debt
|
||||
- sanctions
|
||||
- stagflation
|
||||
- yield curve
|
||||
- debt ceiling
|
||||
- quantitative tightening
|
||||
- rate pause
|
||||
- AI bubble
|
||||
- crypto
|
||||
- bitcoin
|
||||
- safe haven demand
|
||||
- PPI
|
||||
confluence:
|
||||
technical_weight: 40
|
||||
ai_prediction_weight: 25
|
||||
|
||||
@@ -524,7 +524,6 @@ class MT5Connector:
|
||||
|
||||
return result_dict
|
||||
|
||||
@synchronized
|
||||
@synchronized
|
||||
def send_pending_order(
|
||||
self,
|
||||
@@ -621,6 +620,7 @@ class MT5Connector:
|
||||
logger.error(f"Failed to cancel order #{order_ticket}: {result.comment if result else mt5.last_error()}")
|
||||
return False
|
||||
|
||||
@synchronized
|
||||
def modify_position(
|
||||
self,
|
||||
ticket: int,
|
||||
@@ -748,7 +748,7 @@ class MT5Connector:
|
||||
return None
|
||||
try:
|
||||
from datetime import timedelta
|
||||
now = datetime.now() + timedelta(days=2)
|
||||
now = datetime.now(timezone.utc) + timedelta(days=2)
|
||||
from_date = now - timedelta(days=30)
|
||||
deals = mt5.history_deals_get(from_date, now, position=ticket)
|
||||
if deals and len(deals) > 0:
|
||||
@@ -779,7 +779,7 @@ class MT5Connector:
|
||||
return []
|
||||
try:
|
||||
from datetime import timedelta
|
||||
now = datetime.now() + timedelta(days=2)
|
||||
now = datetime.now(timezone.utc) + timedelta(days=2)
|
||||
from_date = now - timedelta(days=days)
|
||||
deals = mt5.history_deals_get(from_date, now)
|
||||
if not deals:
|
||||
|
||||
@@ -42,6 +42,14 @@ class EconomicEventsManager:
|
||||
"ism",
|
||||
"powell",
|
||||
"rate decision",
|
||||
# 2025-2026 additions
|
||||
"pce", # Fed's preferred inflation gauge
|
||||
"jolts", # Job openings — Fed watches closely
|
||||
"adp", # ADP employment change
|
||||
"ecb", # ECB decisions increasingly correlated with Gold
|
||||
"tariff", # Trade policy shocks
|
||||
"debt ceiling", # US debt ceiling showdowns
|
||||
"treasury auction", # Bond market liquidity events
|
||||
]
|
||||
|
||||
def __init__(self):
|
||||
|
||||
+10
-2
@@ -88,7 +88,12 @@ class NewsAnalyzer:
|
||||
"gold advance", "gold gain", "weak dollar", "dollar slide", "dollar fall", "dollar drop", "dollar sink",
|
||||
"dollar weak", "dollar soft", "war", "conflict", "geopolitical", "crisis", "tension", "escalat", "strike", "attack",
|
||||
"recession", "slowdown", "debt", "deficit", "bank failure", "tariff", "trade war",
|
||||
"stimulus", "liquidity", "central bank", "reserve"
|
||||
"stimulus", "liquidity", "central bank", "reserve",
|
||||
# 2025-2026 bullish Gold catalysts
|
||||
"brics", "de-dollarization", "dedollarization", "central bank gold", "gold buying",
|
||||
"sovereign debt", "debt crisis", "sanctions", "stagflation", "yield curve inversion",
|
||||
"debt ceiling", "quantitative easing", "safe haven demand", "rate pause",
|
||||
"currency debasement", "fiscal deficit", "banking crisis",
|
||||
]
|
||||
|
||||
# Bearish factors for Gold (Rate hikes, hawkish, strong dollar, peace, high yields)
|
||||
@@ -97,7 +102,10 @@ class NewsAnalyzer:
|
||||
"disinflation", "strong dollar", "dollar surge", "dollar rally", "dollar jump", "dollar gain", "dollar strong",
|
||||
"gold drop", "gold fall", "gold tumble", "gold slide", "gold retreat", "gold sink",
|
||||
"ceasefire", "peace", "de-escalat", "diplomacy", "strong job", "nfp beat", "robust job",
|
||||
"yield surge", "yields rise", "yields jump"
|
||||
"yield surge", "yields rise", "yields jump",
|
||||
# 2025-2026 bearish Gold catalysts
|
||||
"quantitative tightening", "rate increase", "ai bubble burst", "risk on rally",
|
||||
"dollar dominance", "crypto surge", "bitcoin rally",
|
||||
]
|
||||
|
||||
bull_matches = [kw for kw in bullish_keywords if kw in t]
|
||||
|
||||
@@ -70,16 +70,6 @@ class SignalAggregator:
|
||||
attention_analysis: Optional[dict] = None,
|
||||
min_score: float = 65.0,
|
||||
) -> ConfluenceResult:
|
||||
# Dynamically synchronize with self-learning adaptive weights
|
||||
try:
|
||||
from ai.trade_learner import trade_learner
|
||||
cw = trade_learner.get_confluence_weights()
|
||||
self.technical_weight = cw.get("technical", self.technical_weight)
|
||||
self.ai_weight = cw.get("ai_prediction", self.ai_weight)
|
||||
self.sentiment_weight = cw.get("sentiment", self.sentiment_weight)
|
||||
self.regime_weight = cw.get("regime", self.regime_weight)
|
||||
except Exception:
|
||||
pass
|
||||
"""
|
||||
Calculate the confluence score from all signal sources.
|
||||
|
||||
@@ -93,6 +83,16 @@ class SignalAggregator:
|
||||
Returns:
|
||||
ConfluenceResult with final score and execution decision.
|
||||
"""
|
||||
# Dynamically synchronize with self-learning adaptive weights
|
||||
try:
|
||||
from ai.trade_learner import trade_learner
|
||||
cw = trade_learner.get_confluence_weights()
|
||||
self.technical_weight = cw.get("technical", self.technical_weight)
|
||||
self.ai_weight = cw.get("ai_prediction", self.ai_weight)
|
||||
self.sentiment_weight = cw.get("sentiment", self.sentiment_weight)
|
||||
self.regime_weight = cw.get("regime", self.regime_weight)
|
||||
except Exception:
|
||||
pass
|
||||
reasons = list(strategy_signal.reasons)
|
||||
|
||||
# ── 1. Technical Score (from strategy) ───────────────────────────
|
||||
|
||||
@@ -204,6 +204,8 @@ def test_trade_learner_mistake_guard_adaptation():
|
||||
|
||||
try:
|
||||
learner = TradeLearner()
|
||||
# Reset multipliers so the test doesn't depend on accumulated DB state
|
||||
learner.strategy_multipliers = {"scalping": 1.0, "day_trading": 1.0, "swing_trading": 1.0}
|
||||
# Add a mock mistake memory
|
||||
learner.mistake_memory.append({
|
||||
"strategy": "scalping",
|
||||
|
||||
Reference in New Issue
Block a user