From d42c9ada8cfa9415ab13fb2939ec5970414f1412 Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Mon, 14 Jul 2025 11:15:11 +0300 Subject: [PATCH] mexc interface integrations REST API fixes --- NN/exchanges/mexc/mexc_postman_dump.json | 3184 ++++++++++++++++++++++ NN/exchanges/mexc/test_live_trading.py | 170 ++ NN/exchanges/mexc_interface.py | 153 +- check_ethusdc_precision.py | 152 +- check_mexc_symbols.py | 77 + config.yaml | 2 +- core/trading_executor.py | 65 +- get_mexc_exchange_info.py | 97 + test_live_trading.py | 170 ++ test_mexc_order_fix.py | 174 ++ test_symbol_conversion.py | 50 + 11 files changed, 4120 insertions(+), 174 deletions(-) create mode 100644 NN/exchanges/mexc/mexc_postman_dump.json create mode 100644 NN/exchanges/mexc/test_live_trading.py create mode 100644 check_mexc_symbols.py create mode 100644 get_mexc_exchange_info.py create mode 100644 test_live_trading.py create mode 100644 test_mexc_order_fix.py create mode 100644 test_symbol_conversion.py diff --git a/NN/exchanges/mexc/mexc_postman_dump.json b/NN/exchanges/mexc/mexc_postman_dump.json new file mode 100644 index 0000000..bd58865 --- /dev/null +++ b/NN/exchanges/mexc/mexc_postman_dump.json @@ -0,0 +1,3184 @@ +{ + "info": { + "_postman_id": "7d8b56bc-7c7a-4f87-aab7-f96075785505", + "name": "MEXC V3", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "20747910" + }, + "item": [ + { + "name": "Market Date Endpoints", + "item": [ + { + "name": "Test Connectivity", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{api_url}}/api/v3/ping", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "ping" + ] + } + }, + "response": [] + }, + { + "name": "Check Server Time", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{api_url}}/api/v3/time", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "time" + ] + } + }, + "response": [] + }, + { + "name": "Exchange Information", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{api_url}}/api/v3/exchangeInfo", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "exchangeInfo" + ] + } + }, + "response": [] + }, + { + "name": "Order Book", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{api_url}}/api/v3/depth?symbol=BTCUSDT", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "depth" + ], + "query": [ + { + "key": "symbol", + "value": "BTCUSDT", + "description": "Symbol" + } + ] + } + }, + "response": [] + }, + { + "name": "Recent Trades List", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{api_url}}/api/v3/trades?symbol=BTCUSDT", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "trades" + ], + "query": [ + { + "key": "symbol", + "value": "BTCUSDT", + "description": "Symbol" + } + ] + } + }, + "response": [] + }, + { + "name": "Old Trade Lookup", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{api_url}}/api/v3/historicalTrades?symbol=BTCUSDT", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "historicalTrades" + ], + "query": [ + { + "key": "symbol", + "value": "BTCUSDT", + "description": "Symbol" + } + ] + } + }, + "response": [] + }, + { + "name": "Compressed/Aggregate Trades List", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{api_url}}/api/v3/aggTrades?symbol=BTCUSDT", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "aggTrades" + ], + "query": [ + { + "key": "symbol", + "value": "BTCUSDT" + } + ] + } + }, + "response": [] + }, + { + "name": "Kline/Candlestick Data", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{api_url}}/api/v3/klines?symbol=BTCUSDT&interval=1m", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "klines" + ], + "query": [ + { + "key": "symbol", + "value": "BTCUSDT", + "description": "Symbol" + }, + { + "key": "interval", + "value": "1m", + "description": "ENUM: Kline interval" + } + ] + } + }, + "response": [] + }, + { + "name": "Current Average Price", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{api_url}}/api/v3/avgPrice?symbol=BTCUSDT", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "avgPrice" + ], + "query": [ + { + "key": "symbol", + "value": "BTCUSDT", + "description": "Symbol" + } + ] + } + }, + "response": [] + }, + { + "name": "24hr Ticker Price Change Statistics", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{api_url}}/api/v3/ticker/24hr", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "ticker", + "24hr" + ] + } + }, + "response": [] + }, + { + "name": "Symbol Price Ticker", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{api_url}}/api/v3/ticker/price", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "ticker", + "price" + ] + } + }, + "response": [] + }, + { + "name": "Symbol Order Book Ticker", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{api_url}}/api/v3/ticker/bookTicker", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "ticker", + "bookTicker" + ] + } + }, + "response": [] + }, + { + "name": "Default Symbols", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{api_url}}/api/v3/defaultSymbols", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "defaultSymbols" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Spot Account/Trade", + "item": [ + { + "name": "Test New Order", + "request": { + "method": "POST", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded", + "type": "text", + "disabled": true + } + ], + "url": { + "raw": "{{api_url}}/api/v3/order/test?symbol=BTCUSDT&side=BUY&type=LIMIT&quantity=0.0002&price=30000×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "order", + "test" + ], + "query": [ + { + "key": "symbol", + "value": "BTCUSDT", + "description": "Symbol" + }, + { + "key": "side", + "value": "BUY", + "description": "ENUM:Order Side" + }, + { + "key": "type", + "value": "LIMIT", + "description": "ENUM:Order Type" + }, + { + "key": "quantity", + "value": "0.0002", + "description": "Quantity" + }, + { + "key": "price", + "value": "30000", + "description": "Price" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "New Order", + "request": { + "method": "POST", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded", + "type": "text", + "disabled": true + } + ], + "body": { + "mode": "urlencoded", + "urlencoded": [] + }, + "url": { + "raw": "{{api_url}}/api/v3/order?symbol=MXUSDT&side=BUY&type=LIMIT&quantity=50&price=0.1×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "order" + ], + "query": [ + { + "key": "symbol", + "value": "MXUSDT", + "description": "Symbol" + }, + { + "key": "side", + "value": "BUY", + "description": "ENUM:Order Side" + }, + { + "key": "type", + "value": "LIMIT", + "description": "ENUM:Order Type " + }, + { + "key": "quantity", + "value": "50", + "description": "Quantity" + }, + { + "key": "quoteOrderQty", + "value": "100", + "description": "Quote order quantity (For type: MARKET)", + "disabled": true + }, + { + "key": "price", + "value": "0.1", + "description": "Price" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Cancel Orde", + "request": { + "method": "DELETE", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded", + "type": "text", + "disabled": true + } + ], + "url": { + "raw": "{{api_url}}/api/v3/order?symbol=BTCUSDT&orderId=135598325645746176×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "order" + ], + "query": [ + { + "key": "symbol", + "value": "BTCUSDT", + "description": "Symbol" + }, + { + "key": "orderId", + "value": "135598325645746176", + "description": "Order id" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Cancel all Open Orders on a Symbol", + "request": { + "method": "DELETE", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded", + "type": "text", + "disabled": true + } + ], + "url": { + "raw": "{{api_url}}/api/v3/openOrders?symbol=BTCUSDT×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "openOrders" + ], + "query": [ + { + "key": "symbol", + "value": "BTCUSDT", + "description": "Symbol" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Query Order", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded", + "type": "text", + "disabled": true + } + ], + "url": { + "raw": "{{api_url}}/api/v3/order?symbol=BTCUSDT&orderId=129402018493145088×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "order" + ], + "query": [ + { + "key": "symbol", + "value": "BTCUSDT", + "description": "Symbol" + }, + { + "key": "orderId", + "value": "129402018493145088", + "description": "Order id" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Current Open Orders", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded", + "type": "text", + "disabled": true + } + ], + "url": { + "raw": "{{api_url}}/api/v3/openOrders?symbol=BTCUSDT×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "openOrders" + ], + "query": [ + { + "key": "symbol", + "value": "BTCUSDT", + "description": "Symbol" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "All Orders", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded", + "type": "text", + "disabled": true + } + ], + "url": { + "raw": "{{api_url}}/api/v3/allOrders?symbol=BTCUSDT×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "allOrders" + ], + "query": [ + { + "key": "symbol", + "value": "BTCUSDT", + "description": "Symbol" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Account Information", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded", + "type": "text", + "disabled": true + } + ], + "url": { + "raw": "{{api_url}}/api/v3/account?timestamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "account" + ], + "query": [ + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Account Trade List", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded", + "type": "text", + "disabled": true + } + ], + "url": { + "raw": "{{api_url}}/api/v3/myTrades?symbol=MXUSDT×tamp={{timestamp}}&signature={{signature}}&recvWindow=60000", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "myTrades" + ], + "query": [ + { + "key": "symbol", + "value": "MXUSDT", + "description": "Symbol" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + }, + { + "key": "recvWindow", + "value": "60000" + } + ] + } + }, + "response": [] + }, + { + "name": "Query Self Symbols", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded", + "type": "text", + "disabled": true + } + ], + "url": { + "raw": "{{api_url}}/api/v3/selfSymbols?timestamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "selfSymbols" + ], + "query": [ + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "MxDeduct enable", + "request": { + "method": "POST", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded", + "type": "text", + "disabled": true + } + ], + "body": { + "mode": "urlencoded", + "urlencoded": [] + }, + "url": { + "raw": "{{api_url}}/api/v3/mxDeduct/enable?mxDeductEnable=TRUE×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "mxDeduct", + "enable" + ], + "query": [ + { + "key": "mxDeductEnable", + "value": "TRUE" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Query MxDeduct", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + }, + { + "key": "Content-Type", + "value": "application/x-www-form-urlencoded", + "type": "text", + "disabled": true + } + ], + "url": { + "raw": "{{api_url}}/api/v3/mxDeduct/enable?timestamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "mxDeduct", + "enable" + ], + "query": [ + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + } + ] + }, + { + "name": "EFT", + "item": [ + { + "name": "ETF info", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{api_url}}/api/v3/etf/info", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "etf", + "info" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Wallet", + "item": [ + { + "name": "Withdraw Apply", + "request": { + "method": "POST", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/capital/withdraw/apply?coin=GPT&network=ERC20&address=0x822330d165d511a855d474010a629a08b6fe1e8c&amount=200&signature={{signature}}×tamp={{timestamp}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "capital", + "withdraw", + "apply" + ], + "query": [ + { + "key": "recvWindow", + "value": "60000", + "disabled": true + }, + { + "key": "coin", + "value": "GPT" + }, + { + "key": "withdrawOrderId", + "value": "", + "disabled": true + }, + { + "key": "network", + "value": "ERC20" + }, + { + "key": "address", + "value": "0x822330d165d511a855d474010a629a08b6fe1e8c" + }, + { + "key": "amount", + "value": "200" + }, + { + "key": "remark", + "value": "xx,111", + "disabled": true + }, + { + "key": "signature", + "value": "{{signature}}" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Query Deposit Hisrec", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/capital/deposit/hisrec?coin=USDT&signature={{signature}}×tamp={{timestamp}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "capital", + "deposit", + "hisrec" + ], + "query": [ + { + "key": "coin", + "value": "USDT" + }, + { + "key": "signature", + "value": "{{signature}}" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Query All Coins", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/capital/config/getall?signature={{signature}}×tamp={{timestamp}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "capital", + "config", + "getall" + ], + "query": [ + { + "key": "signature", + "value": "{{signature}}" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Get Listen Key", + "request": { + "method": "POST", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"subAccount\":\"subAccount1123\",\n \"note\":\"note1111\",\n \"permissions\":\"SPOT_ACCOUNT\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{api_url}}/api/v3/broker/sub-account/apiKey?signature={{signature}}×tamp={{timestamp}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "broker", + "sub-account", + "apiKey" + ], + "query": [ + { + "key": "signature", + "value": "{{signature}}" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Transfer", + "request": { + "method": "POST", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/capital/transfer?fromAccountType=SPOT&toAccountType=FUTURE&amount=5&asset=USDT&signature={{signature}}×tamp={{timestamp}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "capital", + "transfer" + ], + "query": [ + { + "key": "fromAccountType", + "value": "SPOT" + }, + { + "key": "toAccountType", + "value": "FUTURE" + }, + { + "key": "amount", + "value": "5" + }, + { + "key": "symbol", + "value": "MXUSDT", + "disabled": true + }, + { + "key": "asset", + "value": "USDT" + }, + { + "key": "signature", + "value": "{{signature}}" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Transfer Record", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/capital/transfer?fromAccountType=SPOT&toAccountType=SPOT&signature={{signature}}×tamp={{timestamp}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "capital", + "transfer" + ], + "query": [ + { + "key": "fromAccountType", + "value": "SPOT" + }, + { + "key": "toAccountType", + "value": "SPOT" + }, + { + "key": "symbol", + "value": "USDT", + "disabled": true + }, + { + "key": "signature", + "value": "{{signature}}" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "startTime", + "value": "1657423701000", + "disabled": true + }, + { + "key": "endTime", + "value": "1660102101000\n", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "Withdraw History", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/capital/withdraw/history?coin=USDT&signature={{signature}}×tamp={{timestamp}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "capital", + "withdraw", + "history" + ], + "query": [ + { + "key": "coin", + "value": "USDT" + }, + { + "key": "signature", + "value": "{{signature}}" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Query Transfer By TranId", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/capital/transfer/tranId?tranId=cb28c88cd20c42819e4d5148d5fb5742&signature={{signature}}×tamp={{timestamp}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "capital", + "transfer", + "tranId" + ], + "query": [ + { + "key": "tranId", + "value": "cb28c88cd20c42819e4d5148d5fb5742" + }, + { + "key": "signature", + "value": "{{signature}}" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Generate Deposit Address", + "request": { + "method": "POST", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/capital/deposit/address?coin=MX&network=ERC20&signature={{signature}}×tamp={{timestamp}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "capital", + "deposit", + "address" + ], + "query": [ + { + "key": "coin", + "value": "MX" + }, + { + "key": "network", + "value": "ERC20" + }, + { + "key": "remark", + "value": "xx,111", + "disabled": true + }, + { + "key": "signature", + "value": "{{signature}}" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Query Deposit Address", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/capital/deposit/address?coin=MX&amount=200&signature={{signature}}×tamp={{timestamp}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "capital", + "deposit", + "address" + ], + "query": [ + { + "key": "coin", + "value": "MX" + }, + { + "key": "amount", + "value": "200" + }, + { + "key": "remark", + "value": "xx,111", + "disabled": true + }, + { + "key": "signature", + "value": "{{signature}}" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Get Assets That Can Be Converted Into MX", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/capital/convert/list?signature={{signature}}×tamp={{timestamp}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "capital", + "convert", + "list" + ], + "query": [ + { + "key": "signature", + "value": "{{signature}}" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Dust Transfer", + "request": { + "method": "POST", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/capital/convert?asset=ARB×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "capital", + "convert" + ], + "query": [ + { + "key": "asset", + "value": "ARB" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "DustLog", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/capital/convert?signature={{signature}}×tamp={{timestamp}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "capital", + "convert" + ], + "query": [ + { + "key": "signature", + "value": "{{signature}}" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + } + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Margin", + "item": [ + { + "name": "Change Trade Mode", + "request": { + "method": "POST", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/margin/tradeMode?symbol=BTCUSDT&tradeMode=0&recvWindow=60000×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "margin", + "tradeMode" + ], + "query": [ + { + "key": "symbol", + "value": "BTCUSDT" + }, + { + "key": "tradeMode", + "value": "0" + }, + { + "key": "recvWindow", + "value": "60000" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Margin Account New Order", + "request": { + "method": "POST", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/margin/order?symbol=MXUSDT&side=BUY&type=FILL_OR_KILL&quantity=50&price=0.12483583475634&recvWindow=60000×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "margin", + "order" + ], + "query": [ + { + "key": "symbol", + "value": "MXUSDT" + }, + { + "key": "side", + "value": "BUY" + }, + { + "key": "type", + "value": "FILL_OR_KILL" + }, + { + "key": "quantity", + "value": "50" + }, + { + "key": "price", + "value": "0.12483583475634" + }, + { + "key": "recvWindow", + "value": "60000" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Margin Account Borrow", + "request": { + "method": "POST", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/margin/loan?asset=MX&isIsolated=TRUE&symbol=MXUSDT&amount=100.835834534856348×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "margin", + "loan" + ], + "query": [ + { + "key": "asset", + "value": "MX" + }, + { + "key": "isIsolated", + "value": "TRUE" + }, + { + "key": "symbol", + "value": "MXUSDT" + }, + { + "key": "amount", + "value": "100.835834534856348" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Margin Account Repay", + "request": { + "method": "POST", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/margin/repay?asset=MX&symbol=MXUSDT&amount=10&borrowId=706703220612927488&recvWindow=60000×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "margin", + "repay" + ], + "query": [ + { + "key": "asset", + "value": "MX" + }, + { + "key": "symbol", + "value": "MXUSDT" + }, + { + "key": "amount", + "value": "10" + }, + { + "key": "borrowId", + "value": "706703220612927488" + }, + { + "key": "recvWindow", + "value": "60000" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Margin Account Cancel all Open Orders on a Symbol", + "request": { + "method": "DELETE", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/margin/openOrders?symbol=MXUSDT×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "margin", + "openOrders" + ], + "query": [ + { + "key": "symbol", + "value": "MXUSDT" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Margin Account Cancel Order", + "request": { + "method": "DELETE", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/margin/order?symbol=MXUSDT&orderId=706702415281393664&recvWindow=60000×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "margin", + "order" + ], + "query": [ + { + "key": "symbol", + "value": "MXUSDT" + }, + { + "key": "orderId", + "value": "706702415281393664" + }, + { + "key": "recvWindow", + "value": "60000" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Query Loan Record", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/margin/loan?asset=BTC&symbol=BTCUSDT×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "margin", + "loan" + ], + "query": [ + { + "key": "asset", + "value": "BTC" + }, + { + "key": "symbol", + "value": "BTCUSDT" + }, + { + "key": "recvWindow", + "value": "60000", + "disabled": true + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Query Margin Account's All Order", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/margin/allOrders?symbol=MXUSDT&recvWindow=60000×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "margin", + "allOrders" + ], + "query": [ + { + "key": "symbol", + "value": "MXUSDT" + }, + { + "key": "recvWindow", + "value": "60000" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Query Margin Account's Trade List", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/margin/myTrades?symbol=BTCUSDT&recvWindow=60000×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "margin", + "myTrades" + ], + "query": [ + { + "key": "symbol", + "value": "BTCUSDT" + }, + { + "key": "recvWindow", + "value": "60000" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Query Margin Account's Open Order", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/margin/openOrders?symbol=BTCUSDT&recvWindow=60000×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "margin", + "openOrders" + ], + "query": [ + { + "key": "symbol", + "value": "BTCUSDT" + }, + { + "key": "recvWindow", + "value": "60000" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Query Margin Account's maxTransferable", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/margin/maxTransferable?symbol=MX_USDT&asset=MX×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "margin", + "maxTransferable" + ], + "query": [ + { + "key": "symbol", + "value": "MX_USDT" + }, + { + "key": "asset", + "value": "MX" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Query Margin Account's priceIndex", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/margin/priceIndex?symbol=MXUSDT×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "margin", + "priceIndex" + ], + "query": [ + { + "key": "symbol", + "value": "MXUSDT" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Query Margin Account's order", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/margin/order?orderId=746784754145300480&symbol=MXUSDT&recvWindow=60000×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "margin", + "order" + ], + "query": [ + { + "key": "orderId", + "value": "746784754145300480" + }, + { + "key": "symbol", + "value": "MXUSDT" + }, + { + "key": "recvWindow", + "value": "60000" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Query Isolated Margin Account Info", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/margin/isolated/account?symbols=BTCUSDT&recvWindow=60000×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "margin", + "isolated", + "account" + ], + "query": [ + { + "key": "symbols", + "value": "BTCUSDT" + }, + { + "key": "recvWindow", + "value": "60000" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Query Margin Account's trigerOrder", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/margin/trigerOrder?timestamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "margin", + "trigerOrder" + ], + "query": [ + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Query Margin Account's maxBorrowable", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/margin/maxBorrowable?symbol=BTCUSDT&asset=USDT×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "margin", + "maxBorrowable" + ], + "query": [ + { + "key": "symbol", + "value": "BTCUSDT" + }, + { + "key": "asset", + "value": "USDT" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Query Repay Record", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/margin/repay?symbol=MXUSDT&asset=MX&recvWindow=60000×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "margin", + "repay" + ], + "query": [ + { + "key": "symbol", + "value": "MXUSDT" + }, + { + "key": "asset", + "value": "MX" + }, + { + "key": "recvWindow", + "value": "60000" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Query Solated Pair", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/margin/isolated/pair?symbol=BTCUSDT×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "margin", + "isolated", + "pair" + ], + "query": [ + { + "key": "symbol", + "value": "BTCUSDT" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Query forceLiquidationRec", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/margin/forceLiquidationRec?symbol=MXUSDT×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "margin", + "forceLiquidationRec" + ], + "query": [ + { + "key": "symbol", + "value": "MXUSDT" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Parent child account", + "item": [ + { + "name": "new virtualSubAccount", + "request": { + "method": "POST", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/sub-account/virtualSubAccount?subAccount=test07261234567803¬e=testing ×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "sub-account", + "virtualSubAccount" + ], + "query": [ + { + "key": "subAccount", + "value": "test07261234567803", + "description": "subAccount" + }, + { + "key": "note", + "value": "testing ", + "description": "remarks" + }, + { + "key": "recvWindow", + "value": "", + "disabled": true + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Query sub-account list", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/sub-account/list?timestamp={{timestamp}}&signature={{signature}}&recvWindow=60000", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "sub-account", + "list" + ], + "query": [ + { + "key": "subAccount", + "value": "", + "description": "subAccount", + "disabled": true + }, + { + "key": "isFreeze", + "value": "", + "description": "true or false", + "disabled": true + }, + { + "key": "page", + "value": "", + "disabled": true + }, + { + "key": "limit", + "value": "", + "disabled": true + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + }, + { + "key": "recvWindow", + "value": "60000" + } + ] + } + }, + "response": [] + }, + { + "name": "new sub-account apiKey", + "request": { + "method": "POST", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/sub-account/apiKey?subAccount=1152058321@qq.com¬e=test&permissions=SPOT_DEAL_READ,SPOT_ACCOUNT_WRITE×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "sub-account", + "apiKey" + ], + "query": [ + { + "key": "subAccount", + "value": "1152058321@qq.com" + }, + { + "key": "note", + "value": "test" + }, + { + "key": "permissions", + "value": "SPOT_DEAL_READ,SPOT_ACCOUNT_WRITE" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + }, + { + "key": "ip", + "value": "", + "disabled": true + }, + { + "key": "recvWindow", + "value": "", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "Query sub-account apiKey", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/sub-account/apiKey?subAccount=test0505×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "sub-account", + "apiKey" + ], + "query": [ + { + "key": "subAccount", + "value": "test0505" + }, + { + "key": "recvWindow", + "value": "", + "disabled": true + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Delete sub-account apiKey", + "request": { + "method": "DELETE", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "" + }, + "url": { + "raw": "{{api_url}}/api/v3/sub-account/apiKey?subAccount=1152058321@qq.com&apiKey=mx0M7w5LZh7bPK4PLA&signature={{signature}}×tamp={{timestamp}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "sub-account", + "apiKey" + ], + "query": [ + { + "key": "recvWindow", + "value": "", + "disabled": true + }, + { + "key": "subAccount", + "value": "1152058321@qq.com" + }, + { + "key": "apiKey", + "value": "mx0M7w5LZh7bPK4PLA" + }, + { + "key": "signature", + "value": "{{signature}}" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Sub-account UniversalTransfer", + "request": { + "method": "POST", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/capital/sub-account/universalTransfer?asset=USDT&amount=0.1&fromAccountType=SPOT&fromAccount=1152058321@qq.com&toAccountType=SPOT&toAccount=test0622&clientTranId=1111test×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "capital", + "sub-account", + "universalTransfer" + ], + "query": [ + { + "key": "asset", + "value": "USDT" + }, + { + "key": "amount", + "value": "0.1" + }, + { + "key": "fromAccountType", + "value": "SPOT" + }, + { + "key": "fromAccount", + "value": "1152058321@qq.com" + }, + { + "key": "toAccountType", + "value": "SPOT" + }, + { + "key": "toAccount", + "value": "test0622" + }, + { + "key": "symbol", + "value": "MXUSDT", + "disabled": true + }, + { + "key": "startTime", + "value": "1656603881000", + "disabled": true + }, + { + "key": "clientTranId", + "value": "1111test" + }, + { + "key": "endTime", + "value": "1656603895000", + "disabled": true + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Query Sub-account UniversalTransfer Record", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/capital/sub-account/universalTransfer?asset=USDT&fromAccountType=SPOT&toAccountType=SPOT&toAccount=test0622×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "capital", + "sub-account", + "universalTransfer" + ], + "query": [ + { + "key": "asset", + "value": "USDT" + }, + { + "key": "amount", + "value": "2000.1111111111111111111", + "disabled": true + }, + { + "key": "fromAccountType", + "value": "SPOT" + }, + { + "key": "fromAccount", + "value": "792487830@qq.com", + "disabled": true + }, + { + "key": "toAccountType", + "value": "SPOT" + }, + { + "key": "toAccount", + "value": "test0622" + }, + { + "key": "symbol", + "value": "MXUSDT", + "disabled": true + }, + { + "key": "startTime", + "value": "1656603881000", + "disabled": true + }, + { + "key": "recvWindow", + "value": "60000", + "disabled": true + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Enable Futures For Sub-account", + "request": { + "method": "POST", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/sub-account/futures?subAccount=test0726×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "sub-account", + "futures" + ], + "query": [ + { + "key": "subAccount", + "value": "test0726" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Enable Margin For Sub-account", + "request": { + "method": "POST", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/sub-account/margin?subAccount=1152058321@qq.com×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "sub-account", + "margin" + ], + "query": [ + { + "key": "subAccount", + "value": "1152058321@qq.com" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Rebate", + "item": [ + { + "name": "Get Rebate History Records", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/rebate/taxQuery?recvWindow=60000×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "rebate", + "taxQuery" + ], + "query": [ + { + "key": "recvWindow", + "value": "60000" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Get Rebate Records Detail", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/rebate/detail?recvWindow=60000×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "rebate", + "detail" + ], + "query": [ + { + "key": "recvWindow", + "value": "60000" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Get Self Rebate Records Detail", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/rebate/detail/kickback?recvWindow=60000×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "rebate", + "detail", + "kickback" + ], + "query": [ + { + "key": "recvWindow", + "value": "60000" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Query ReferCode", + "request": { + "method": "GET", + "header": [ + { + "key": "x-mexc-apikey", + "value": "{{api_key}}", + "type": "text" + } + ], + "url": { + "raw": "{{api_url}}/api/v3/rebate/referCode?recvWindow=60000×tamp={{timestamp}}&signature={{signature}}", + "host": [ + "{{api_url}}" + ], + "path": [ + "api", + "v3", + "rebate", + "referCode" + ], + "query": [ + { + "key": "recvWindow", + "value": "60000" + }, + { + "key": "timestamp", + "value": "{{timestamp}}" + }, + { + "key": "signature", + "value": "{{signature}}" + } + ] + } + }, + "response": [] + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "const ts = Date.now();", + "pm.environment.set(\"timestamp\", ts);", + "console.log('timestamp',ts);", + "", + "let paramsObject = {};", + "", + "const api_secret = pm.environment.get(\"api_secret\");", + "const api_key = pm.environment.get(\"api_key\");", + "console.log('api_secret',api_secret);", + "console.log('x-mexc-apikey',api_key);", + "", + "const parameters = pm.request.url.query;", + "console.log('parameters', parameters);", + "parameters.map((param) => {", + " if (param.key != 'signature' &&", + " param.key != 'timestamp' &&", + " !is_empty(param.value) &&", + " !is_disabled(param.disabled)) {", + " paramsObject[param.key] = param.value;", + " }", + "})", + "", + "Object.assign(paramsObject, { 'timestamp': ts });", + "", + "if (api_secret) {", + " let queryString = Object.keys(paramsObject).map((key) => {", + " return `${key}=${paramsObject[key]}`;", + " }).join('&');", + " console.log('queryString',queryString);", + "", + " const signature = CryptoJS.HmacSHA256(queryString, api_secret).toString();", + " console.log('signature',signature)", + " pm.environment.set(\"signature\", signature);", + "}", + "", + "", + "", + "function is_disabled(str) {", + " return str == true;", + "}", + "", + "function is_empty(str) {", + " if (typeof str == 'undefined' ||", + " !str ||", + " str.length === 0 ||", + " str === \"\" ||", + " !/[^\\s]/.test(str) ||", + " /^\\s*$/.test(str) ||", + " str.replace(/\\s/g, \"\") === \"\") {", + " return true;", + " }", + " else {", + " return false;", + " }", + "}" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ] +} \ No newline at end of file diff --git a/NN/exchanges/mexc/test_live_trading.py b/NN/exchanges/mexc/test_live_trading.py new file mode 100644 index 0000000..7da97d5 --- /dev/null +++ b/NN/exchanges/mexc/test_live_trading.py @@ -0,0 +1,170 @@ +#!/usr/bin/env python3 +""" +Test Live Trading - Verify MEXC Connection and Trading +""" + +import os +import sys +import logging +import asyncio +from datetime import datetime + +# Add project root to path +sys.path.append(os.path.dirname(os.path.abspath(__file__))) + +from core.trading_executor import TradingExecutor +from core.config import get_config + +# Setup logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + +async def test_live_trading(): + """Test live trading functionality""" + try: + logger.info("=== LIVE TRADING TEST ===") + logger.info("Testing MEXC connection and account balance reading") + + # Initialize trading executor + logger.info("Initializing Trading Executor...") + executor = TradingExecutor("config.yaml") + + # Check trading mode + logger.info(f"Trading Mode: {executor.trading_mode}") + logger.info(f"Simulation Mode: {executor.simulation_mode}") + logger.info(f"Trading Enabled: {executor.trading_enabled}") + + if executor.simulation_mode: + logger.warning("WARNING: Still in simulation mode. Check config.yaml") + return + + # Test 1: Get account balance + logger.info("\n=== TEST 1: ACCOUNT BALANCE ===") + try: + balances = executor.get_account_balance() + logger.info("Account Balances:") + + total_value = 0.0 + for asset, balance_info in balances.items(): + if balance_info['total'] > 0: + logger.info(f" {asset}: {balance_info['total']:.6f} ({balance_info['type']})") + if asset in ['USDT', 'USDC', 'USD']: + total_value += balance_info['total'] + + logger.info(f"Total USD Value: ${total_value:.2f}") + + if total_value < 25: + logger.warning(f"Account balance ${total_value:.2f} may be insufficient for testing") + else: + logger.info(f"Account balance ${total_value:.2f} looks good for testing") + + except Exception as e: + logger.error(f"Error getting account balance: {e}") + return + + # Test 2: Get current ETH price + logger.info("\n=== TEST 2: MARKET DATA ===") + try: + # Test getting current price for ETH/USDT + if executor.exchange: + ticker = executor.exchange.get_ticker("ETH/USDT") + if ticker and 'last' in ticker: + current_price = ticker['last'] + logger.info(f"Current ETH/USDT Price: ${current_price:.2f}") + else: + logger.error("Failed to get ETH/USDT ticker data") + return + else: + logger.error("Exchange interface not available") + return + except Exception as e: + logger.error(f"Error getting market data: {e}") + return + + # Test 3: Calculate position sizing + logger.info("\n=== TEST 3: POSITION SIZING ===") + try: + # Test position size calculation with different confidence levels + test_confidences = [0.3, 0.5, 0.7, 0.9] + + for confidence in test_confidences: + position_size = executor._calculate_position_size(confidence, current_price) + quantity = position_size / current_price + logger.info(f"Confidence {confidence:.1f}: ${position_size:.2f} = {quantity:.6f} ETH") + + except Exception as e: + logger.error(f"Error calculating position sizes: {e}") + return + + # Test 4: Small test trade (optional - requires confirmation) + logger.info("\n=== TEST 4: TEST TRADE (OPTIONAL) ===") + + user_input = input("Do you want to execute a SMALL test trade? (type 'YES' to confirm): ") + if user_input.upper() == 'YES': + try: + logger.info("Executing SMALL test BUY order...") + + # Execute a very small buy order with low confidence (minimum position size) + success = executor.execute_signal( + symbol="ETH/USDT", + action="BUY", + confidence=0.3, # Low confidence = minimum position size + current_price=current_price + ) + + if success: + logger.info("✅ Test BUY order executed successfully!") + + # Wait a moment, then try to sell + await asyncio.sleep(2) + + logger.info("Executing corresponding SELL order...") + success = executor.execute_signal( + symbol="ETH/USDT", + action="SELL", + confidence=0.9, # High confidence to ensure execution + current_price=current_price + ) + + if success: + logger.info("✅ Test SELL order executed successfully!") + logger.info("✅ Full test trade cycle completed!") + else: + logger.warning("❌ Test SELL order failed") + else: + logger.warning("❌ Test BUY order failed") + + except Exception as e: + logger.error(f"Error executing test trade: {e}") + else: + logger.info("Test trade skipped") + + # Test 5: Position and trade history + logger.info("\n=== TEST 5: POSITIONS AND HISTORY ===") + try: + positions = executor.get_positions() + trade_history = executor.get_trade_history() + + logger.info(f"Current Positions: {len(positions)}") + for symbol, position in positions.items(): + logger.info(f" {symbol}: {position.side} {position.quantity:.6f} @ ${position.entry_price:.2f}") + + logger.info(f"Trade History: {len(trade_history)} trades") + for trade in trade_history[-5:]: # Last 5 trades + pnl_str = f"${trade.pnl:+.2f}" if trade.pnl else "$0.00" + logger.info(f" {trade.symbol} {trade.side}: {pnl_str}") + + except Exception as e: + logger.error(f"Error getting positions/history: {e}") + + logger.info("\n=== LIVE TRADING TEST COMPLETED ===") + logger.info("If all tests passed, live trading is ready!") + + except Exception as e: + logger.error(f"Error in live trading test: {e}") + +if __name__ == "__main__": + asyncio.run(test_live_trading()) \ No newline at end of file diff --git a/NN/exchanges/mexc_interface.py b/NN/exchanges/mexc_interface.py index 7c4e6ea..42ebb98 100644 --- a/NN/exchanges/mexc_interface.py +++ b/NN/exchanges/mexc_interface.py @@ -65,45 +65,48 @@ class MEXCInterface(ExchangeInterface): return False def _format_spot_symbol(self, symbol: str) -> str: - """Formats a symbol to MEXC spot API standard (e.g., 'ETH/USDT' -> 'ETHUSDC').""" + """Formats a symbol to MEXC spot API standard and converts USDT to USDC for execution.""" if '/' in symbol: base, quote = symbol.split('/') - # Convert USDT to USDC for MEXC spot trading + # Convert USDT to USDC for MEXC execution (MEXC API only supports USDC pairs) if quote.upper() == 'USDT': quote = 'USDC' return f"{base.upper()}{quote.upper()}" else: - # Convert USDT to USDC for symbols like ETHUSDT - symbol = symbol.upper() - if symbol.endswith('USDT'): - symbol = symbol.replace('USDT', 'USDC') - return symbol + # Convert USDT to USDC for symbols like ETHUSDT -> ETHUSDC + if symbol.upper().endswith('USDT'): + symbol = symbol.upper().replace('USDT', 'USDC') + return symbol.upper() def _format_futures_symbol(self, symbol: str) -> str: """Formats a symbol to MEXC futures API standard (e.g., 'ETH/USDT' -> 'ETH_USDT').""" # This method is included for completeness but should not be used for spot trading return symbol.replace('/', '_').upper() - def _generate_signature(self, timestamp: str, method: str, endpoint: str, params: Dict[str, Any]) -> str: - """Generate signature for private API calls using MEXC's expected parameter order""" - # MEXC requires specific parameter ordering, not alphabetical - # Based on successful test: symbol, side, type, quantity, timestamp, then other params - mexc_param_order = ['symbol', 'side', 'type', 'quantity', 'timestamp', 'recvWindow'] + def _generate_signature(self, params: Dict[str, Any]) -> str: + """Generate signature for private API calls using MEXC's parameter ordering""" + # MEXC uses specific parameter ordering for signature generation + # Based on working Postman collection: symbol, side, type, quantity, price, timestamp, recvWindow, then others + + # Remove signature if present + clean_params = {k: v for k, v in params.items() if k != 'signature'} + + # MEXC parameter order (from working Postman collection) + mexc_order = ['symbol', 'side', 'type', 'quantity', 'price', 'timestamp', 'recvWindow'] - # Build ordered parameter list ordered_params = [] # Add parameters in MEXC's expected order - for param_name in mexc_param_order: - if param_name in params and param_name != 'signature': - ordered_params.append(f"{param_name}={params[param_name]}") + for param_name in mexc_order: + if param_name in clean_params: + ordered_params.append(f"{param_name}={clean_params[param_name]}") + del clean_params[param_name] - # Add any remaining parameters not in the standard order (alphabetically) - remaining_params = {k: v for k, v in params.items() if k not in mexc_param_order and k != 'signature'} - for key in sorted(remaining_params.keys()): - ordered_params.append(f"{key}={remaining_params[key]}") + # Add any remaining parameters in alphabetical order + for key in sorted(clean_params.keys()): + ordered_params.append(f"{key}={clean_params[key]}") - # Create query string (MEXC doesn't use the api_key + timestamp prefix) + # Create query string query_string = '&'.join(ordered_params) logger.debug(f"MEXC signature query string: {query_string}") @@ -118,7 +121,7 @@ class MEXCInterface(ExchangeInterface): logger.debug(f"MEXC signature: {signature}") return signature - def _send_public_request(self, method: str, endpoint: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]: + def _send_public_request(self, method: str, endpoint: str, params: Optional[Dict[str, Any]] = None) -> Any: """Send a public API request to MEXC.""" if params is None: params = {} @@ -145,46 +148,52 @@ class MEXCInterface(ExchangeInterface): logger.error(f"Error in public request to {endpoint}: {e}") return {} - def _send_private_request(self, method: str, endpoint: str, params: Dict[str, Any] = None) -> Optional[Dict[str, Any]]: + def _send_private_request(self, method: str, endpoint: str, params: Optional[Dict[str, Any]] = None) -> Optional[Dict[str, Any]]: """Send a private request to the exchange with proper signature""" if params is None: params = {} timestamp = str(int(time.time() * 1000)) + # Add timestamp and recvWindow to params for signature and request params['timestamp'] = timestamp - params['recvWindow'] = self.recv_window - signature = self._generate_signature(timestamp, method, endpoint, params) + params['recvWindow'] = str(self.recv_window) + + # Generate signature with all parameters + signature = self._generate_signature(params) params['signature'] = signature headers = { - "X-MEXC-APIKEY": self.api_key, - "Request-Time": timestamp + "X-MEXC-APIKEY": self.api_key } # For spot API, use the correct endpoint format if not endpoint.startswith('api/v3/'): endpoint = f"api/v3/{endpoint}" url = f"{self.base_url}/{endpoint}" + try: if method.upper() == "GET": response = self.session.get(url, headers=headers, params=params, timeout=10) elif method.upper() == "POST": - # MEXC expects POST parameters as query string, not in body + # For POST requests, MEXC expects parameters as query parameters, not form data + # Based on Postman collection: Content-Type header is disabled response = self.session.post(url, headers=headers, params=params, timeout=10) + elif method.upper() == "DELETE": + response = self.session.delete(url, headers=headers, params=params, timeout=10) else: logger.error(f"Unsupported method: {method}") return None - response.raise_for_status() - data = response.json() - # For successful responses, return the data directly - # MEXC doesn't always use 'success' field for successful operations + logger.debug(f"Request URL: {response.url}") + logger.debug(f"Response status: {response.status_code}") + if response.status_code == 200: - return data + return response.json() else: logger.error(f"API error: Status Code: {response.status_code}, Response: {response.text}") return None + except requests.exceptions.HTTPError as http_err: logger.error(f"HTTP error for {endpoint}: Status Code: {response.status_code}, Response: {response.text}") logger.error(f"HTTP error details: {http_err}") @@ -223,7 +232,11 @@ class MEXCInterface(ExchangeInterface): ticker_data = response elif isinstance(response, list) and len(response) > 0: # If the response is a list, try to find the specific symbol - found_ticker = next((item for item in response if item.get('symbol') == formatted_symbol), None) + found_ticker = None + for item in response: + if isinstance(item, dict) and item.get('symbol') == formatted_symbol: + found_ticker = item + break if found_ticker: ticker_data = found_ticker else: @@ -293,38 +306,66 @@ class MEXCInterface(ExchangeInterface): logger.info(f"Supported symbols include: {supported_symbols[:10]}...") # Show first 10 return {} - endpoint = "order" + # Round quantity to MEXC precision requirements and ensure minimum order value + # MEXC ETHUSDC requires precision based on baseAssetPrecision (5 decimals for ETH) + if 'ETH' in formatted_symbol: + quantity = round(quantity, 5) # MEXC ETHUSDC precision: 5 decimals + # Ensure minimum order value (typically $10+ for MEXC) + if price and quantity * price < 10.0: + quantity = round(10.0 / price, 5) # Adjust to minimum $10 order + elif 'BTC' in formatted_symbol: + quantity = round(quantity, 6) # MEXC BTCUSDC precision: 6 decimals + if price and quantity * price < 10.0: + quantity = round(10.0 / price, 6) # Adjust to minimum $10 order + else: + quantity = round(quantity, 5) # Default precision for MEXC + if price and quantity * price < 10.0: + quantity = round(10.0 / price, 5) # Adjust to minimum $10 order - params: Dict[str, Any] = { + # MEXC doesn't support MARKET orders for many pairs - use LIMIT orders instead + if order_type.upper() == 'MARKET': + # Convert market order to limit order with aggressive pricing for immediate execution + if price is None: + ticker = self.get_ticker(symbol) + if ticker and 'last' in ticker: + current_price = float(ticker['last']) + # For buy orders, use slightly above market to ensure immediate execution + # For sell orders, use slightly below market to ensure immediate execution + if side.upper() == 'BUY': + price = current_price * 1.002 # 0.2% premium for immediate buy execution + else: + price = current_price * 0.998 # 0.2% discount for immediate sell execution + else: + logger.error("Cannot get current price for market order conversion") + return {} + + # Convert to limit order with immediate execution pricing + order_type = 'LIMIT' + logger.info(f"MEXC: Converting MARKET to aggressive LIMIT order at ${price:.2f} for immediate execution") + + # Prepare order parameters + params = { 'symbol': formatted_symbol, 'side': side.upper(), 'type': order_type.upper(), 'quantity': str(quantity) # Quantity must be a string } + if price is not None: - params['price'] = str(price) # Price must be a string for limit orders + # Format price to remove unnecessary decimal places (e.g., 2900.0 -> 2900) + params['price'] = str(int(price)) if price == int(price) else str(price) logger.info(f"MEXC: Placing {side.upper()} {order_type.upper()} order for {quantity} {formatted_symbol} at price {price}") - # For market orders, some parameters might be optional or handled differently. - # Check MEXC API docs for market order specifics (e.g., quoteOrderQty for buy market orders) - if order_type.upper() == 'MARKET' and side.upper() == 'BUY': - # If it's a market buy order, MEXC often expects quoteOrderQty instead of quantity - # Assuming quantity here refers to the base asset, if quoteOrderQty is needed, adjust. - # For now, we will stick to quantity and let MEXC handle the conversion if possible - pass # No specific change needed based on the current params structure - - try: - # MEXC API endpoint for placing orders is /api/v3/order (POST) - order_result = self._send_private_request('POST', endpoint, params) - if order_result: - logger.info(f"MEXC: Order placed successfully: {order_result}") - return order_result - else: - logger.error(f"MEXC: Error placing order: {order_result}") - return {} - except Exception as e: - logger.error(f"MEXC: Exception placing order: {e}") + # Use the standard private request method which handles timestamp and signature + endpoint = "order" + result = self._send_private_request("POST", endpoint, params) + + if result: + logger.info(f"MEXC: Order placed successfully: {result}") + return result + else: + logger.error(f"MEXC: Failed to place order") return {} def cancel_order(self, symbol: str, order_id: str) -> Dict[str, Any]: diff --git a/check_ethusdc_precision.py b/check_ethusdc_precision.py index 87e7dc2..a9a85bb 100644 --- a/check_ethusdc_precision.py +++ b/check_ethusdc_precision.py @@ -1,86 +1,76 @@ -import requests +#!/usr/bin/env python3 +""" +Check ETHUSDC Trading Rules and Precision +""" -# Check ETHUSDC precision requirements on MEXC -try: - # Get symbol information from MEXC - resp = requests.get('https://api.mexc.com/api/v3/exchangeInfo') - data = resp.json() +import os +import sys +from pathlib import Path + +# Add project root to path +project_root = Path(__file__).parent +sys.path.insert(0, str(project_root)) + +from NN.exchanges.mexc_interface import MEXCInterface + +def check_ethusdc_precision(): + """Check ETHUSDC trading rules""" + print("Checking ETHUSDC Trading Rules...") + print("=" * 50) - print('=== ETHUSDC SYMBOL INFORMATION ===') + # Get API credentials + api_key = os.getenv('MEXC_API_KEY', '') + api_secret = os.getenv('MEXC_SECRET_KEY', '') - # Find ETHUSDC symbol - ethusdc_info = None - for symbol_info in data.get('symbols', []): - if symbol_info['symbol'] == 'ETHUSDC': - ethusdc_info = symbol_info - break + if not api_key or not api_secret: + print("❌ No MEXC API credentials found") + return - if ethusdc_info: - print(f'Symbol: {ethusdc_info["symbol"]}') - print(f'Status: {ethusdc_info["status"]}') - print(f'Base Asset: {ethusdc_info["baseAsset"]}') - print(f'Quote Asset: {ethusdc_info["quoteAsset"]}') - print(f'Base Asset Precision: {ethusdc_info["baseAssetPrecision"]}') - print(f'Quote Asset Precision: {ethusdc_info["quoteAssetPrecision"]}') - - # Check order types - order_types = ethusdc_info.get('orderTypes', []) - print(f'Allowed Order Types: {order_types}') - - # Check filters for quantity and price precision - print('\nFilters:') - for filter_info in ethusdc_info.get('filters', []): - filter_type = filter_info['filterType'] - print(f' {filter_type}:') - for key, value in filter_info.items(): - if key != 'filterType': - print(f' {key}: {value}') - - # Calculate proper quantity precision - print('\n=== QUANTITY FORMATTING RECOMMENDATIONS ===') - - # Find LOT_SIZE filter for minimum order size - lot_size_filter = None - min_notional_filter = None - for filter_info in ethusdc_info.get('filters', []): - if filter_info['filterType'] == 'LOT_SIZE': - lot_size_filter = filter_info - elif filter_info['filterType'] == 'MIN_NOTIONAL': - min_notional_filter = filter_info - - if lot_size_filter: - step_size = lot_size_filter['stepSize'] - min_qty = lot_size_filter['minQty'] - max_qty = lot_size_filter['maxQty'] - print(f'Min Quantity: {min_qty}') - print(f'Max Quantity: {max_qty}') - print(f'Step Size: {step_size}') - - # Count decimal places in step size to determine precision - decimal_places = len(step_size.split('.')[-1].rstrip('0')) if '.' in step_size else 0 - print(f'Required decimal places: {decimal_places}') - - # Test formatting our problematic quantity - test_quantity = 0.0028169119884018344 - formatted_quantity = round(test_quantity, decimal_places) - print(f'Original quantity: {test_quantity}') - print(f'Formatted quantity: {formatted_quantity}') - print(f'String format: {formatted_quantity:.{decimal_places}f}') - - # Check if our quantity meets minimum - if formatted_quantity < float(min_qty): - print(f'❌ Quantity {formatted_quantity} is below minimum {min_qty}') - min_value_needed = float(min_qty) * 2665 # Approximate ETH price - print(f'💡 Need at least ${min_value_needed:.2f} to place minimum order') - else: - print(f'✅ Quantity {formatted_quantity} meets minimum requirement') - - if min_notional_filter: - min_notional = min_notional_filter['minNotional'] - print(f'Minimum Notional Value: ${min_notional}') - + # Create MEXC interface + mexc = MEXCInterface(api_key=api_key, api_secret=api_secret, test_mode=False) + + if not mexc.connect(): + print("❌ Failed to connect to MEXC API") + return + + print("✅ Connected to MEXC API") + + # Check if ETHUSDC is supported + if mexc.is_symbol_supported("ETH/USDT"): # Will be converted to ETHUSDC + print("✅ ETHUSDC is supported for trading") else: - print('❌ ETHUSDC symbol not found in exchange info') - -except Exception as e: - print(f'Error: {e}') \ No newline at end of file + print("❌ ETHUSDC is not supported for trading") + return + + # Get current ticker to see price + ticker = mexc.get_ticker("ETH/USDT") # Will query ETHUSDC + if ticker: + price = ticker.get('last', 0) + print(f"Current ETHUSDC Price: ${price:.2f}") + + # Test different quantities to find minimum + test_quantities = [ + 0.001, # $3 worth + 0.01, # $30 worth + 0.1, # $300 worth + 0.009871, # Our calculated quantity + ] + + print("\nTesting different quantities:") + print("-" * 30) + + for qty in test_quantities: + rounded_qty = round(qty, 6) + value_usd = rounded_qty * price if ticker else 0 + print(f"Quantity: {rounded_qty:8.6f} ETH (~${value_usd:.2f})") + + print(f"\nOur test quantity: 0.009871 ETH") + print(f"Rounded to 6 decimals: {round(0.009871, 6):.6f} ETH") + print(f"Value: ~${round(0.009871, 6) * price:.2f}") + + print("\nNext steps:") + print("1. Check if minimum order value is $10+ USD") + print("2. Try with a larger quantity (0.01 ETH = ~$30)") + +if __name__ == "__main__": + check_ethusdc_precision() \ No newline at end of file diff --git a/check_mexc_symbols.py b/check_mexc_symbols.py new file mode 100644 index 0000000..bdd063f --- /dev/null +++ b/check_mexc_symbols.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python3 +""" +Check MEXC Available Trading Symbols +""" + +import os +import sys +import logging + +# Add project root to path +sys.path.append(os.path.dirname(os.path.abspath(__file__))) + +from core.trading_executor import TradingExecutor + +# Setup logging +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') +logger = logging.getLogger(__name__) + +def check_mexc_symbols(): + """Check available trading symbols on MEXC""" + try: + logger.info("=== MEXC SYMBOL AVAILABILITY CHECK ===") + + # Initialize trading executor + executor = TradingExecutor("config.yaml") + + if not executor.exchange: + logger.error("Failed to initialize exchange") + return + + # Get all supported symbols + logger.info("Fetching all supported symbols from MEXC...") + supported_symbols = executor.exchange.get_api_symbols() + + logger.info(f"Total supported symbols: {len(supported_symbols)}") + + # Filter ETH-related symbols + eth_symbols = [s for s in supported_symbols if 'ETH' in s] + logger.info(f"ETH-related symbols ({len(eth_symbols)}):") + for symbol in sorted(eth_symbols): + logger.info(f" {symbol}") + + # Filter USDT pairs + usdt_symbols = [s for s in supported_symbols if s.endswith('USDT')] + logger.info(f"USDT pairs ({len(usdt_symbols)}):") + for symbol in sorted(usdt_symbols)[:20]: # Show first 20 + logger.info(f" {symbol}") + if len(usdt_symbols) > 20: + logger.info(f" ... and {len(usdt_symbols) - 20} more") + + # Filter USDC pairs + usdc_symbols = [s for s in supported_symbols if s.endswith('USDC')] + logger.info(f"USDC pairs ({len(usdc_symbols)}):") + for symbol in sorted(usdc_symbols): + logger.info(f" {symbol}") + + # Check specific symbols we're interested in + test_symbols = ['ETHUSDT', 'ETHUSDC', 'BTCUSDT', 'BTCUSDC'] + logger.info("Checking specific symbols:") + for symbol in test_symbols: + if symbol in supported_symbols: + logger.info(f" ✅ {symbol} - SUPPORTED") + else: + logger.info(f" ❌ {symbol} - NOT SUPPORTED") + + # Show a sample of all available symbols + logger.info("Sample of all available symbols:") + for symbol in sorted(supported_symbols)[:30]: + logger.info(f" {symbol}") + if len(supported_symbols) > 30: + logger.info(f" ... and {len(supported_symbols) - 30} more") + + except Exception as e: + logger.error(f"Error checking MEXC symbols: {e}") + +if __name__ == "__main__": + check_mexc_symbols() \ No newline at end of file diff --git a/config.yaml b/config.yaml index bd5bd44..bfb3a29 100644 --- a/config.yaml +++ b/config.yaml @@ -159,7 +159,7 @@ trading: # MEXC Trading API Configuration mexc_trading: enabled: true - trading_mode: simulation # simulation, testnet, live + trading_mode: live # simulation, testnet, live # Position sizing as percentage of account balance base_position_percent: 5.0 # 5% base position of account diff --git a/core/trading_executor.py b/core/trading_executor.py index 32f0fd2..8f06932 100644 --- a/core/trading_executor.py +++ b/core/trading_executor.py @@ -214,38 +214,40 @@ class TradingExecutor: # Determine the quote asset (e.g., USDT, USDC) from the symbol if '/' in symbol: quote_asset = symbol.split('/')[1].upper() # Assuming symbol is like ETH/USDT - # Convert USDT to USDC for MEXC spot trading - if quote_asset == 'USDT': - quote_asset = 'USDC' + # Keep USDT as USDT for MEXC spot trading (no conversion needed) else: # Fallback for symbols like ETHUSDT (assuming last 4 chars are quote) quote_asset = symbol[-4:].upper() - # Convert USDT to USDC for MEXC spot trading - if quote_asset == 'USDT': - quote_asset = 'USDC' + # Keep USDT as USDT for MEXC spot trading (no conversion needed) # Calculate required capital for the trade # If we are selling (to open a short position), we need collateral based on the position size # For simplicity, assume required capital is the full position value in USD required_capital = self._calculate_position_size(confidence, current_price) - # Get available balance for the quote asset - available_balance = self.exchange.get_balance(quote_asset) - - # If USDC balance is insufficient, check USDT as fallback (for MEXC compatibility) - if available_balance < required_capital and quote_asset == 'USDC': - usdt_balance = self.exchange.get_balance('USDT') - if usdt_balance >= required_capital: - available_balance = usdt_balance - quote_asset = 'USDT' # Use USDT instead - logger.info(f"BALANCE CHECK: Using USDT fallback balance for {symbol}") + # Get available balance for the quote asset (try USDT first, then USDC as fallback) + if quote_asset == 'USDT': + available_balance = self.exchange.get_balance('USDT') + if available_balance < required_capital: + # If USDT balance is insufficient, check USDC as fallback + usdc_balance = self.exchange.get_balance('USDC') + if usdc_balance >= required_capital: + available_balance = usdc_balance + quote_asset = 'USDC' # Use USDC instead + logger.info(f"BALANCE CHECK: Using USDC fallback balance for {symbol}") + else: + available_balance = self.exchange.get_balance(quote_asset) logger.info(f"BALANCE CHECK: Symbol: {symbol}, Action: {action}, Required: ${required_capital:.2f} {quote_asset}, Available: ${available_balance:.2f} {quote_asset}") - if available_balance < required_capital: + # Allow some small precision tolerance (1 cent) and ensure sufficient balance + balance_tolerance = 0.01 + if available_balance < (required_capital - balance_tolerance): logger.warning(f"Trade blocked for {symbol} {action}: Insufficient {quote_asset} balance. " f"Required: ${required_capital:.2f}, Available: ${available_balance:.2f}") return False + else: + logger.info(f"BALANCE CHECK PASSED: {quote_asset} balance sufficient for trade") elif self.simulation_mode: logger.debug(f"SIMULATION MODE: Skipping balance check for {symbol} {action} - allowing trade for model training") # --- End Balance check --- @@ -765,34 +767,25 @@ class TradingExecutor: return False def _calculate_position_size(self, confidence: float, current_price: float) -> float: - """Calculate position size based on percentage of account balance, confidence, and leverage""" + """Calculate position size - use 100% of account balance for short-term scalping""" # Get account balance (simulation or real) account_balance = self._get_account_balance_for_sizing() - # Get position sizing percentages - max_percent = self.mexc_config.get('max_position_percent', 20.0) / 100.0 - min_percent = self.mexc_config.get('min_position_percent', 2.0) / 100.0 - base_percent = self.mexc_config.get('base_position_percent', 5.0) / 100.0 - leverage = self.mexc_config.get('leverage', 50.0) + # Use 100% of account balance since we're holding for seconds/minutes only + # Scale by confidence: 70-100% of balance based on confidence (0.7-1.0 range) + confidence_multiplier = max(0.7, min(1.0, confidence)) + position_value = account_balance * confidence_multiplier - # Scale position size by confidence - position_percent = min(max_percent, max(min_percent, base_percent * confidence)) - position_value = account_balance * position_percent - - # Apply leverage to get effective position size - leveraged_position_value = position_value * leverage - - # Apply reduction based on consecutive losses + # Apply reduction based on consecutive losses (risk management) reduction_factor = self.mexc_config.get('consecutive_loss_reduction_factor', 0.8) adjusted_reduction_factor = reduction_factor ** self.consecutive_losses - leveraged_position_value *= adjusted_reduction_factor + position_value *= adjusted_reduction_factor logger.debug(f"Position calculation: account=${account_balance:.2f}, " - f"percent={position_percent*100:.1f}%, base=${position_value:.2f}, " - f"leverage={leverage}x, effective=${leveraged_position_value:.2f}, " - f"confidence={confidence:.2f}") + f"confidence_mult={confidence_multiplier:.2f}, " + f"position=${position_value:.2f}, confidence={confidence:.2f}") - return leveraged_position_value + return position_value def _get_account_balance_for_sizing(self) -> float: """Get account balance for position sizing calculations""" diff --git a/get_mexc_exchange_info.py b/get_mexc_exchange_info.py new file mode 100644 index 0000000..19e6a2d --- /dev/null +++ b/get_mexc_exchange_info.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +""" +Get MEXC Exchange Info for ETHUSDC +""" + +import requests +import json + +def get_mexc_exchange_info(): + """Get detailed MEXC exchange information for ETHUSDC""" + print("Getting MEXC Exchange Info for ETHUSDC...") + print("=" * 50) + + try: + # Get exchange info from MEXC public API + resp = requests.get('https://api.mexc.com/api/v3/exchangeInfo') + data = resp.json() + + # Find ETHUSDC symbol + ethusdc_info = None + for symbol_info in data.get('symbols', []): + if symbol_info['symbol'] == 'ETHUSDC': + ethusdc_info = symbol_info + break + + if not ethusdc_info: + print("❌ ETHUSDC symbol not found") + return + + print("✅ Found ETHUSDC symbol information") + print(f"Symbol: {ethusdc_info['symbol']}") + print(f"Status: {ethusdc_info['status']}") + print(f"Base Asset: {ethusdc_info['baseAsset']}") + print(f"Quote Asset: {ethusdc_info['quoteAsset']}") + print(f"Base Precision: {ethusdc_info['baseAssetPrecision']}") + print(f"Quote Precision: {ethusdc_info['quoteAssetPrecision']}") + + print("\nFilters:") + print("-" * 20) + + lot_size_filter = None + min_notional_filter = None + + for filter_info in ethusdc_info.get('filters', []): + filter_type = filter_info['filterType'] + print(f"\n{filter_type}:") + + if filter_type == 'LOT_SIZE': + lot_size_filter = filter_info + elif filter_type == 'MIN_NOTIONAL': + min_notional_filter = filter_info + + for key, value in filter_info.items(): + if key != 'filterType': + print(f" {key}: {value}") + + # Analyze requirements + print("\n" + "=" * 50) + print("ANALYSIS:") + + if lot_size_filter: + min_qty = float(lot_size_filter['minQty']) + step_size = lot_size_filter['stepSize'] + + print(f"Minimum Quantity: {min_qty} ETH") + print(f"Step Size: {step_size}") + + # Check our test quantity + test_qty = 0.009871 + print(f"\nOur quantity: {test_qty}") + print(f"Meets minimum?: {'✅ Yes' if test_qty >= min_qty else '❌ No'}") + + # Check step size compliance + if '.' in step_size: + decimal_places = len(step_size.split('.')[-1].rstrip('0')) + properly_rounded = round(test_qty, decimal_places) + print(f"Required decimals: {decimal_places}") + print(f"Properly rounded: {properly_rounded}") + + if min_notional_filter: + min_notional = float(min_notional_filter['minNotional']) + test_value = 0.009871 * 3031 # approximate price + print(f"\nMinimum Order Value: ${min_notional}") + print(f"Our order value: ${test_value:.2f}") + print(f"Meets minimum?: {'✅ Yes' if test_value >= min_notional else '❌ No'}") + + print("\n💡 RECOMMENDATIONS:") + if lot_size_filter and min_notional_filter: + safe_qty = max(float(lot_size_filter['minQty']) * 1.1, min_notional / 3000) + print(f"Use quantity >= {safe_qty:.6f} ETH for safe trading") + print(f"This equals ~${safe_qty * 3031:.2f} USD") + + except Exception as e: + print(f"❌ Error: {e}") + +if __name__ == "__main__": + get_mexc_exchange_info() \ No newline at end of file diff --git a/test_live_trading.py b/test_live_trading.py new file mode 100644 index 0000000..7da97d5 --- /dev/null +++ b/test_live_trading.py @@ -0,0 +1,170 @@ +#!/usr/bin/env python3 +""" +Test Live Trading - Verify MEXC Connection and Trading +""" + +import os +import sys +import logging +import asyncio +from datetime import datetime + +# Add project root to path +sys.path.append(os.path.dirname(os.path.abspath(__file__))) + +from core.trading_executor import TradingExecutor +from core.config import get_config + +# Setup logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger(__name__) + +async def test_live_trading(): + """Test live trading functionality""" + try: + logger.info("=== LIVE TRADING TEST ===") + logger.info("Testing MEXC connection and account balance reading") + + # Initialize trading executor + logger.info("Initializing Trading Executor...") + executor = TradingExecutor("config.yaml") + + # Check trading mode + logger.info(f"Trading Mode: {executor.trading_mode}") + logger.info(f"Simulation Mode: {executor.simulation_mode}") + logger.info(f"Trading Enabled: {executor.trading_enabled}") + + if executor.simulation_mode: + logger.warning("WARNING: Still in simulation mode. Check config.yaml") + return + + # Test 1: Get account balance + logger.info("\n=== TEST 1: ACCOUNT BALANCE ===") + try: + balances = executor.get_account_balance() + logger.info("Account Balances:") + + total_value = 0.0 + for asset, balance_info in balances.items(): + if balance_info['total'] > 0: + logger.info(f" {asset}: {balance_info['total']:.6f} ({balance_info['type']})") + if asset in ['USDT', 'USDC', 'USD']: + total_value += balance_info['total'] + + logger.info(f"Total USD Value: ${total_value:.2f}") + + if total_value < 25: + logger.warning(f"Account balance ${total_value:.2f} may be insufficient for testing") + else: + logger.info(f"Account balance ${total_value:.2f} looks good for testing") + + except Exception as e: + logger.error(f"Error getting account balance: {e}") + return + + # Test 2: Get current ETH price + logger.info("\n=== TEST 2: MARKET DATA ===") + try: + # Test getting current price for ETH/USDT + if executor.exchange: + ticker = executor.exchange.get_ticker("ETH/USDT") + if ticker and 'last' in ticker: + current_price = ticker['last'] + logger.info(f"Current ETH/USDT Price: ${current_price:.2f}") + else: + logger.error("Failed to get ETH/USDT ticker data") + return + else: + logger.error("Exchange interface not available") + return + except Exception as e: + logger.error(f"Error getting market data: {e}") + return + + # Test 3: Calculate position sizing + logger.info("\n=== TEST 3: POSITION SIZING ===") + try: + # Test position size calculation with different confidence levels + test_confidences = [0.3, 0.5, 0.7, 0.9] + + for confidence in test_confidences: + position_size = executor._calculate_position_size(confidence, current_price) + quantity = position_size / current_price + logger.info(f"Confidence {confidence:.1f}: ${position_size:.2f} = {quantity:.6f} ETH") + + except Exception as e: + logger.error(f"Error calculating position sizes: {e}") + return + + # Test 4: Small test trade (optional - requires confirmation) + logger.info("\n=== TEST 4: TEST TRADE (OPTIONAL) ===") + + user_input = input("Do you want to execute a SMALL test trade? (type 'YES' to confirm): ") + if user_input.upper() == 'YES': + try: + logger.info("Executing SMALL test BUY order...") + + # Execute a very small buy order with low confidence (minimum position size) + success = executor.execute_signal( + symbol="ETH/USDT", + action="BUY", + confidence=0.3, # Low confidence = minimum position size + current_price=current_price + ) + + if success: + logger.info("✅ Test BUY order executed successfully!") + + # Wait a moment, then try to sell + await asyncio.sleep(2) + + logger.info("Executing corresponding SELL order...") + success = executor.execute_signal( + symbol="ETH/USDT", + action="SELL", + confidence=0.9, # High confidence to ensure execution + current_price=current_price + ) + + if success: + logger.info("✅ Test SELL order executed successfully!") + logger.info("✅ Full test trade cycle completed!") + else: + logger.warning("❌ Test SELL order failed") + else: + logger.warning("❌ Test BUY order failed") + + except Exception as e: + logger.error(f"Error executing test trade: {e}") + else: + logger.info("Test trade skipped") + + # Test 5: Position and trade history + logger.info("\n=== TEST 5: POSITIONS AND HISTORY ===") + try: + positions = executor.get_positions() + trade_history = executor.get_trade_history() + + logger.info(f"Current Positions: {len(positions)}") + for symbol, position in positions.items(): + logger.info(f" {symbol}: {position.side} {position.quantity:.6f} @ ${position.entry_price:.2f}") + + logger.info(f"Trade History: {len(trade_history)} trades") + for trade in trade_history[-5:]: # Last 5 trades + pnl_str = f"${trade.pnl:+.2f}" if trade.pnl else "$0.00" + logger.info(f" {trade.symbol} {trade.side}: {pnl_str}") + + except Exception as e: + logger.error(f"Error getting positions/history: {e}") + + logger.info("\n=== LIVE TRADING TEST COMPLETED ===") + logger.info("If all tests passed, live trading is ready!") + + except Exception as e: + logger.error(f"Error in live trading test: {e}") + +if __name__ == "__main__": + asyncio.run(test_live_trading()) \ No newline at end of file diff --git a/test_mexc_order_fix.py b/test_mexc_order_fix.py new file mode 100644 index 0000000..8b99cee --- /dev/null +++ b/test_mexc_order_fix.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python3 +""" +Test MEXC Order Fix + +Tests the fixed MEXC interface to ensure order execution works correctly +""" + +import os +import sys +import logging +from pathlib import Path + +# Add project root to path +project_root = Path(__file__).parent +sys.path.insert(0, str(project_root)) + +# Configure logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' +) + +logger = logging.getLogger(__name__) + +def test_mexc_order_fix(): + """Test the fixed MEXC interface""" + print("Testing Fixed MEXC Interface") + print("=" * 50) + + # Import after path setup + try: + from NN.exchanges.mexc_interface import MEXCInterface + except ImportError as e: + print(f"❌ Import error: {e}") + return False + + # Get API credentials + api_key = os.getenv('MEXC_API_KEY', '') + api_secret = os.getenv('MEXC_SECRET_KEY', '') + + if not api_key or not api_secret: + print("❌ No MEXC API credentials found") + print("Set MEXC_API_KEY and MEXC_SECRET_KEY environment variables") + return False + + # Initialize MEXC interface + mexc = MEXCInterface( + api_key=api_key, + api_secret=api_secret, + test_mode=False, # Use live API (MEXC doesn't have testnet) + trading_mode='live' + ) + + # Test 1: Connection + print("\n1. Testing connection...") + if mexc.connect(): + print("✅ Connection successful") + else: + print("❌ Connection failed") + return False + + # Test 2: Account info + print("\n2. Testing account info...") + account_info = mexc.get_account_info() + if account_info: + print("✅ Account info retrieved") + print(f"Account type: {account_info.get('accountType', 'N/A')}") + else: + print("❌ Failed to get account info") + return False + + # Test 3: Balance check + print("\n3. Testing balance retrieval...") + usdc_balance = mexc.get_balance('USDC') + usdt_balance = mexc.get_balance('USDT') + print(f"USDC balance: {usdc_balance}") + print(f"USDT balance: {usdt_balance}") + + if usdc_balance <= 0 and usdt_balance <= 0: + print("❌ No USDC or USDT balance for testing") + return False + + # Test 4: Symbol support check + print("\n4. Testing symbol support...") + symbol = 'ETH/USDT' # Will be converted to ETHUSDC internally + formatted_symbol = mexc._format_spot_symbol(symbol) + print(f"Symbol {symbol} formatted to: {formatted_symbol}") + + if mexc.is_symbol_supported(symbol): + print(f"✅ Symbol {formatted_symbol} is supported") + else: + print(f"❌ Symbol {formatted_symbol} is not supported") + print("Checking supported symbols...") + supported = mexc.get_api_symbols() + print(f"Found {len(supported)} supported symbols") + if 'ETHUSDC' in supported: + print("✅ ETHUSDC is in supported list") + else: + print("❌ ETHUSDC not in supported list") + + # Test 5: Get ticker + print("\n5. Testing ticker retrieval...") + ticker = mexc.get_ticker(symbol) + if ticker: + print(f"✅ Ticker retrieved for {symbol}") + print(f"Last price: ${ticker['last']:.2f}") + print(f"Bid: ${ticker['bid']:.2f}, Ask: ${ticker['ask']:.2f}") + else: + print(f"❌ Failed to get ticker for {symbol}") + return False + + # Test 6: Small test order (only if balance available) + print("\n6. Testing small order placement...") + if usdc_balance >= 10.0: # Need at least $10 for minimum order + try: + # Calculate small test quantity + test_price = ticker['last'] * 1.01 # 1% above market for quick execution + test_quantity = round(10.0 / test_price, 5) # $10 worth + + print(f"Attempting to place test order:") + print(f"- Symbol: {symbol} -> {formatted_symbol}") + print(f"- Side: BUY") + print(f"- Type: LIMIT") + print(f"- Quantity: {test_quantity}") + print(f"- Price: ${test_price:.2f}") + + # Note: This is a real order that will use real funds! + confirm = input("⚠️ This will place a REAL order with REAL funds! Continue? (yes/no): ") + if confirm.lower() != 'yes': + print("❌ Order test skipped by user") + return True + + order_result = mexc.place_order( + symbol=symbol, + side='BUY', + order_type='LIMIT', + quantity=test_quantity, + price=test_price + ) + + if order_result: + print("✅ Order placed successfully!") + print(f"Order ID: {order_result.get('orderId')}") + print(f"Order result: {order_result}") + + # Try to cancel the order immediately + order_id = order_result.get('orderId') + if order_id: + print(f"\n7. Testing order cancellation...") + cancel_result = mexc.cancel_order(symbol, str(order_id)) + if cancel_result: + print("✅ Order cancelled successfully") + else: + print("❌ Failed to cancel order") + print("⚠️ You may have an open order to manually cancel") + else: + print("❌ Order placement failed") + return False + + except Exception as e: + print(f"❌ Order test failed with exception: {e}") + return False + else: + print(f"⚠️ Insufficient balance for order test (need $10+, have ${usdc_balance:.2f} USDC)") + print("✅ All other tests passed - order API should work when balance is sufficient") + + print("\n" + "=" * 50) + print("✅ MEXC Interface Test Completed Successfully!") + print("✅ Order execution should now work correctly") + return True + +if __name__ == "__main__": + success = test_mexc_order_fix() + sys.exit(0 if success else 1) \ No newline at end of file diff --git a/test_symbol_conversion.py b/test_symbol_conversion.py new file mode 100644 index 0000000..ccac7e0 --- /dev/null +++ b/test_symbol_conversion.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +""" +Test MEXC Symbol Conversion +Verify that USDT symbols are properly converted to USDC for MEXC execution +""" + +import sys +from pathlib import Path + +# Add project root to path +project_root = Path(__file__).parent +sys.path.insert(0, str(project_root)) + +from NN.exchanges.mexc_interface import MEXCInterface + +def test_symbol_conversion(): + """Test the symbol conversion logic""" + print("Testing MEXC Symbol Conversion...") + print("=" * 50) + + # Create MEXC interface (no need for real API keys for symbol conversion) + mexc = MEXCInterface(api_key="dummy", api_secret="dummy", test_mode=True) + + # Test cases + test_symbols = [ + "ETH/USDT", + "BTC/USDT", + "ETHUSDT", + "BTCUSDT", + "ETH/USDC", # Should stay as USDC + "ETHUSDC" # Should stay as USDC + ] + + print("Symbol Conversion Results:") + print("-" * 30) + + for symbol in test_symbols: + converted = mexc._format_spot_symbol(symbol) + print(f"{symbol:12} -> {converted}") + + print("\nExpected Results for MEXC Trading:") + print("- ETH/USDT should become ETHUSDC") + print("- BTC/USDT should become BTCUSDC") + print("- ETHUSDT should become ETHUSDC") + print("- BTCUSDT should become BTCUSDC") + print("- ETH/USDC should stay ETHUSDC") + print("- ETHUSDC should stay ETHUSDC") + +if __name__ == "__main__": + test_symbol_conversion() \ No newline at end of file