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:
@@ -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 []
|
||||
|
||||
Reference in New Issue
Block a user