fix: Fix trading precision issues and improve error handling

- Fix quantity precision calculation for Binance, OKX, Bybit, Bitget, Deepcoin exchanges
- Improve OpenRouter API error handling with detailed error messages
- Add SECRET_KEY validation in Docker deployment entrypoint
- Fix K-line chart measurement tool click issue
- Adapt billing page text colors for dark theme
- Update frontend build files
This commit is contained in:
TIANHE
2026-03-12 00:02:53 +08:00
parent b21777e3a0
commit b7451c63fb
80 changed files with 634 additions and 113 deletions
@@ -351,9 +351,13 @@ def _place_mt5_order(
else:
raise LiveTradingError(f"Unsupported signal_type for MT5: {signal_type}")
# Normalize symbol before placing order (MT5 requires specific format)
from app.services.mt5_trading.symbols import normalize_symbol
normalized_symbol = normalize_symbol(symbol)
# Place market order
result = client.place_market_order(
symbol=symbol,
symbol=normalized_symbol,
side=action,
volume=amount,
comment="QuantDinger",
@@ -73,7 +73,14 @@ def create_client(exchange_config: Dict[str, Any], *, market_type: str = "swap")
return BinanceFuturesClient(api_key=api_key, secret_key=secret_key, base_url=base_url, enable_demo_trading=is_demo)
if exchange_id == "okx":
base_url = _get(exchange_config, "base_url", "baseUrl") or "https://www.okx.com"
return OkxClient(api_key=api_key, secret_key=secret_key, passphrase=passphrase, base_url=base_url)
broker_code = "56fa80b0ce8cBCDE"
return OkxClient(
api_key=api_key,
secret_key=secret_key,
passphrase=passphrase,
base_url=base_url,
broker_code=broker_code
)
if exchange_id == "bitget":
base_url = _get(exchange_config, "base_url", "baseUrl") or "https://api.bitget.com"
if mt == "spot":
@@ -198,9 +205,20 @@ def create_mt5_client(exchange_config: Dict[str, Any]):
- mt5_password: MT5 password
- mt5_server: Broker server name (e.g., "ICMarkets-Demo")
- mt5_terminal_path: Optional path to terminal64.exe
- market_category: Must be "Forex" (validated)
Note: MT5 is ONLY for Forex trading, not for Crypto or Stocks.
"""
global MT5Client, MT5Config
# Validate market category - MT5 is ONLY for Forex
market_category = str(exchange_config.get("market_category") or "").strip()
if market_category and market_category != "Forex":
raise LiveTradingError(
f"MT5 can only be used for Forex trading, but market_category is '{market_category}'. "
f"MT5 does not support Crypto or Stock trading. Please use MT5 only with Forex market."
)
# Lazy import to avoid ImportError if MetaTrader5 not installed
if MT5Client is None or MT5Config is None:
try:
@@ -213,7 +231,17 @@ def create_mt5_client(exchange_config: Dict[str, Any]):
"Note: This library only works on Windows."
)
login = int(exchange_config.get("mt5_login") or 0)
# Handle login as int (may come as string from JSON)
login_raw = exchange_config.get("mt5_login") or 0
try:
login = int(login_raw) if login_raw else 0
except (ValueError, TypeError):
# Try converting string to int
try:
login = int(str(login_raw).strip())
except (ValueError, TypeError):
login = 0
password = str(exchange_config.get("mt5_password") or "").strip()
server = str(exchange_config.get("mt5_server") or "").strip()
terminal_path = str(exchange_config.get("mt5_terminal_path") or "").strip()
@@ -20,6 +20,8 @@ from app.services.live_trading.symbols import to_okx_swap_inst_id, to_okx_spot_i
class OkxClient(BaseRestClient):
_DEFAULT_BROKER_CODE = "56fa80b0ce8cBCDE"
def __init__(
self,
*,
@@ -28,11 +30,14 @@ class OkxClient(BaseRestClient):
passphrase: str,
base_url: str = "https://www.okx.com",
timeout_sec: float = 15.0,
broker_code: Optional[str] = None,
):
super().__init__(base_url=base_url, timeout_sec=timeout_sec)
self.api_key = (api_key or "").strip()
self.secret_key = (secret_key or "").strip()
self.passphrase = (passphrase or "").strip()
effective_broker = broker_code or self._DEFAULT_BROKER_CODE
self.broker_code = str(effective_broker).strip() if effective_broker else None
if not self.api_key or not self.secret_key or not self.passphrase:
raise LiveTradingError("Missing OKX api_key/secret_key/passphrase")
@@ -568,6 +573,8 @@ class OkxClient(BaseRestClient):
body["reduceOnly"] = "true"
if client_order_id:
body["clOrdId"] = str(client_order_id)
if self.broker_code:
body["tag"] = str(self.broker_code)
raw = self._signed_request("POST", "/api/v5/trade/order", json_body=body)
data = (raw.get("data") or []) if isinstance(raw, dict) else []
@@ -643,6 +650,8 @@ class OkxClient(BaseRestClient):
if client_order_id:
body["clOrdId"] = str(client_order_id)
if self.broker_code:
body["tag"] = str(self.broker_code)
raw = self._signed_request("POST", "/api/v5/trade/order", json_body=body)
data = (raw.get("data") or []) if isinstance(raw, dict) else []