From c53cb5aae39b260e612bc15191b868e7b8b26c43 Mon Sep 17 00:00:00 2001 From: bast Date: Fri, 6 Nov 2026 10:53:22 +0100 Subject: [PATCH] news mcp --- bots/mcp_server.py | 52 ++++++++++++++++++++++++++++++++++++++++----- mt5-stack.zip | Bin 48062 -> 48778 bytes 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/bots/mcp_server.py b/bots/mcp_server.py index 9f927096..0111d640 100644 --- a/bots/mcp_server.py +++ b/bots/mcp_server.py @@ -132,8 +132,8 @@ class MockBridge(MT5Bridge): "trade_mode": "DEMO", } - async def symbols(self) -> List[str]: - return self.SYMBOLS + async def symbols(self, search: Optional[str] = None) -> List[str]: + return [x for x in self.SYMBOLS if not search or search.upper() in x] async def symbol_info(self, symbol: str) -> Dict[str, Any]: if symbol not in self.BASE_PRICES: @@ -367,15 +367,53 @@ class LiveBridge(MT5Bridge): "trade_mode": "DEMO" if info.trade_mode == 0 else "REAL", } - async def symbols(self) -> List[str]: + async def symbols(self, search: Optional[str] = None) -> List[str]: await self.ensure() + if search: + syms = self.mt5.symbols_get(group=f"*{search}*") + return [s.name for s in syms] if syms else [] syms = self.mt5.symbols_get() if syms is None: return [] return [s.name for s in syms if s.visible] + def _resolve(self, symbol: str) -> str: + """Broker-Symbolnamen finden und in der Marktübersicht aktivieren. + PU Prime u.a. hängen Suffixe an (z.B. XAUUSD -> XAUUSD.s), und Symbole + ausserhalb der Marktübersicht liefern keine Ticks. + Reihenfolge: SYMBOL_MAP (bots.env) -> exakter Name -> Name mit Suffix.""" + cache = getattr(self, "_symbol_cache", None) + if cache is None: + cache = self._symbol_cache = {} + for pair in os.getenv("SYMBOL_MAP", "").split(","): + if "=" in pair: + k, v = pair.split("=", 1) + cache[k.strip().upper()] = v.strip() # z.B. XAUUSD=XAUUSD.s + key = symbol.upper() + name = cache.get(key) + if name is None: + # Endpunkte schreiben Symbole gross ("XAUUSD.S"), der Broker-Name ist aber + # case-sensitiv ("XAUUSD.s") -> über den Basisnamen suchen, Gross/Klein egal + base = key.split(".")[0] + cands = [c.name for c in (self.mt5.symbols_get(group=f"*{base}*") or [])] + exact = [n for n in cands if n.upper() == key] + prefixed = sorted((n for n in cands if n.upper().startswith(base)), key=len) + if exact: + name = exact[0] + elif prefixed: + name = prefixed[0] + else: + raise HTTPException(404, f"Symbol {symbol} not found at broker") + if name != symbol: + log.info(f"Symbol {symbol} -> {name} (broker name)") + cache[key] = name + if not self.mt5.symbol_select(name, True): + log.warning(f"symbol_select({name}) failed: {self.mt5.last_error()}") + return name + async def symbol_info(self, symbol: str) -> Dict[str, Any]: await self.ensure() + symbol = self._resolve(symbol) info = self.mt5.symbol_info(symbol) if info is None: raise HTTPException(404, f"Symbol {symbol} not found") @@ -395,6 +433,7 @@ class LiveBridge(MT5Bridge): async def ohlc(self, symbol: str, timeframe: str, bars: int, start_pos: int = 0) -> List[Dict]: await self.ensure() + symbol = self._resolve(symbol) import pandas as pd # Check if seconds timeframe @@ -440,6 +479,7 @@ class LiveBridge(MT5Bridge): to_ts: Unix timestamp Ende """ await self.ensure() + symbol = self._resolve(symbol) import pandas as pd from datetime import datetime, timezone @@ -575,6 +615,7 @@ class LiveBridge(MT5Bridge): comment: str = "") -> Dict[str, Any]: """Open a market order.""" await self.ensure() + symbol = self._resolve(symbol) # Get symbol info for filling info = self.mt5.symbol_info(symbol) @@ -688,6 +729,7 @@ class LiveBridge(MT5Bridge): async def tick(self, symbol: str) -> Dict[str, Any]: await self.ensure() + symbol = self._resolve(symbol) tick = self.mt5.symbol_info_tick(symbol) if tick is None: raise HTTPException(404, f"No tick for {symbol}") @@ -839,8 +881,8 @@ async def account(): @app.get("/symbols") -async def symbols(): - syms = await bridge.symbols() +async def symbols(search: Optional[str] = Query(None, description="z.B. XAU – sucht in ALLEN Broker-Symbolen")): + syms = await bridge.symbols(search) if search else await bridge.symbols() return {"count": len(syms), "symbols": syms} diff --git a/mt5-stack.zip b/mt5-stack.zip index 5a00175f2ec2b6e75f432b065168cd4abc350296..31a522bba159abb74c501c833a7c931e1e474c8c 100644 GIT binary patch delta 9891 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