8 Commits

26 changed files with 87064 additions and 1006 deletions

3
.env
View File

@ -1,6 +1,7 @@
# MEXC API Configuration (Spot Trading)
MEXC_API_KEY=mx0vglhVPZeIJ32Qw1
MEXC_SECRET_KEY=3bfe4bd99d5541e4a1bca87ab257cc7e
MEXC_SECRET_KEY=3bfe4bd99d5541e4a1bca87ab257cc7e
#3bfe4bd99d5541e4a1bca87ab257cc7e 45d0b3c26f2644f19bfb98b07741b2f5
# BASE ENDPOINTS: https://api.mexc.com wss://wbs-api.mexc.com/ws !!! DO NOT CHANGE THIS

1
.gitignore vendored
View File

@ -41,3 +41,4 @@ closed_trades_history.json
data/cnn_training/cnn_training_data*
testcases/*
testcases/negative/case_index.json
chrome_user_data/*

File diff suppressed because it is too large Load Diff

View File

@ -154,7 +154,7 @@ trading:
# MEXC Trading API Configuration
mexc_trading:
enabled: true
trading_mode: simulation # simulation, testnet, live
trading_mode: live # simulation, testnet, live
# FIXED: Meaningful position sizes for learning
base_position_usd: 25.0 # $25 base position (was $1)

View File

@ -0,0 +1,292 @@
# Enhanced Multi-Modal Trading System Configuration
# System Settings
system:
timezone: "Europe/Sofia" # Configurable timezone for all timestamps
log_level: "INFO" # DEBUG, INFO, WARNING, ERROR
session_timeout: 3600 # Session timeout in seconds
# Trading Symbols Configuration
# Primary trading pair: ETH/USDT (main signals generation)
# Reference pair: BTC/USDT (correlation analysis only, no trading signals)
symbols:
- "ETH/USDT" # MAIN TRADING PAIR - Generate signals and execute trades
- "BTC/USDT" # REFERENCE ONLY - For correlation analysis, no direct trading
# Timeframes for ultra-fast scalping (500x leverage)
timeframes:
- "1s" # Primary scalping timeframe
- "1m" # Short-term confirmation
- "1h" # Medium-term trend
- "1d" # Long-term direction
# Data Provider Settings
data:
provider: "binance"
cache_enabled: true
cache_dir: "cache"
historical_limit: 1000
real_time_enabled: true
websocket_reconnect: true
feature_engineering:
technical_indicators: true
market_regime_detection: true
volatility_analysis: true
# Enhanced CNN Configuration
cnn:
window_size: 20
features: ["open", "high", "low", "close", "volume"]
timeframes: ["1m", "5m", "15m", "1h", "4h", "1d"]
hidden_layers: [64, 128, 256]
dropout: 0.2
learning_rate: 0.001
batch_size: 32
epochs: 100
confidence_threshold: 0.6
early_stopping_patience: 10
model_dir: "models/enhanced_cnn" # Ultra-fast scalping weights (500x leverage)
timeframe_importance:
"1s": 0.60 # Primary scalping signal
"1m": 0.20 # Short-term confirmation
"1h": 0.15 # Medium-term trend
"1d": 0.05 # Long-term direction (minimal)
# Enhanced RL Agent Configuration
rl:
state_size: 100 # Will be calculated dynamically based on features
action_space: 3 # BUY, HOLD, SELL
hidden_size: 256
epsilon: 1.0
epsilon_decay: 0.995
epsilon_min: 0.01
learning_rate: 0.0001
gamma: 0.99
memory_size: 10000
batch_size: 64
target_update_freq: 1000
buffer_size: 10000
model_dir: "models/enhanced_rl"
# Market regime adaptation
market_regime_weights:
trending: 1.2 # Higher confidence in trending markets
ranging: 0.8 # Lower confidence in ranging markets
volatile: 0.6 # Much lower confidence in volatile markets
# Prioritized experience replay
replay_alpha: 0.6 # Priority exponent
replay_beta: 0.4 # Importance sampling exponent
# Enhanced Orchestrator Settings
orchestrator:
# Model weights for decision combination
cnn_weight: 0.7 # Weight for CNN predictions
rl_weight: 0.3 # Weight for RL decisions
confidence_threshold: 0.20 # Lowered from 0.35 for low-volatility markets
confidence_threshold_close: 0.10 # Lowered from 0.15 for easier exits
decision_frequency: 30 # Seconds between decisions (faster)
# Multi-symbol coordination
symbol_correlation_matrix:
"ETH/USDT-BTC/USDT": 0.85 # ETH-BTC correlation
# Perfect move marking
perfect_move_threshold: 0.02 # 2% price change to mark as significant
perfect_move_buffer_size: 10000
# RL evaluation settings
evaluation_delay: 3600 # Evaluate actions after 1 hour
reward_calculation:
success_multiplier: 10 # Reward for correct predictions
failure_penalty: 5 # Penalty for wrong predictions
confidence_scaling: true # Scale rewards by confidence
# Training Configuration
training:
learning_rate: 0.001
batch_size: 32
epochs: 100
validation_split: 0.2
early_stopping_patience: 10
# CNN specific training
cnn_training_interval: 3600 # Train CNN every hour (was 6 hours)
min_perfect_moves: 50 # Reduced from 200 for faster learning
# RL specific training
rl_training_interval: 300 # Train RL every 5 minutes (was 1 hour)
min_experiences: 50 # Reduced from 100 for faster learning
training_steps_per_cycle: 20 # Increased from 10 for more learning
model_type: "optimized_short_term"
use_realtime: true
use_ticks: true
checkpoint_dir: "NN/models/saved/realtime_ticks_checkpoints"
save_best_model: true
save_final_model: false # We only want to keep the best performing model
# Continuous learning settings
continuous_learning: true
learning_from_trades: true
pattern_recognition: true
retrospective_learning: true
# Trading Execution
trading:
max_position_size: 0.05 # Maximum position size (5% of balance)
stop_loss: 0.02 # 2% stop loss
take_profit: 0.05 # 5% take profit
trading_fee: 0.0005 # 0.05% trading fee (MEXC taker fee - fallback)
# MEXC Fee Structure (asymmetrical) - Updated 2025-05-28
trading_fees:
maker: 0.0000 # 0.00% maker fee (adds liquidity)
taker: 0.0005 # 0.05% taker fee (takes liquidity)
default: 0.0005 # Default fallback fee (taker rate)
# Risk management
max_daily_trades: 20 # Maximum trades per day
max_concurrent_positions: 2 # Max positions across symbols
position_sizing:
confidence_scaling: true # Scale position by confidence
base_size: 0.02 # 2% base position
max_size: 0.05 # 5% maximum position
# MEXC Trading API Configuration
mexc_trading:
enabled: true
trading_mode: simulation # simulation, testnet, live
# FIXED: Meaningful position sizes for learning
base_position_usd: 25.0 # $25 base position (was $1)
max_position_value_usd: 50.0 # $50 max position (was $1)
min_position_value_usd: 10.0 # $10 min position (was $0.10)
# Risk management
max_daily_trades: 100
max_daily_loss_usd: 200.0
max_concurrent_positions: 3
min_trade_interval_seconds: 30
# Order configuration
order_type: market # market or limit
# Enhanced fee structure for better calculation
trading_fees:
maker_fee: 0.0002 # 0.02% maker fee
taker_fee: 0.0006 # 0.06% taker fee
default_fee: 0.0006 # Default to taker fee
# Memory Management
memory:
total_limit_gb: 28.0 # Total system memory limit
model_limit_gb: 4.0 # Per-model memory limit
cleanup_interval: 1800 # Memory cleanup every 30 minutes
# Real-time RL COB Trader Configuration
realtime_rl:
# Model parameters for 400M parameter network (faster startup)
model:
input_size: 2000 # COB feature dimensions
hidden_size: 2048 # Optimized hidden layer size for 400M params
num_layers: 8 # Efficient transformer layers for faster training
learning_rate: 0.0001 # Higher learning rate for faster convergence
weight_decay: 0.00001 # Balanced L2 regularization
# Inference configuration
inference_interval_ms: 200 # Inference every 200ms
min_confidence_threshold: 0.7 # Minimum confidence for signal accumulation
required_confident_predictions: 3 # Need 3 confident predictions for trade
# Training configuration
training_interval_s: 1.0 # Train every second
batch_size: 32 # Training batch size
replay_buffer_size: 1000 # Store last 1000 predictions for training
# Signal accumulation
signal_buffer_size: 10 # Buffer size for signal accumulation
consensus_threshold: 3 # Need 3 signals in same direction
# Model checkpointing
model_checkpoint_dir: "models/realtime_rl_cob"
save_interval_s: 300 # Save models every 5 minutes
# COB integration
symbols: ["BTC/USDT", "ETH/USDT"] # Symbols to trade
cob_feature_normalization: "robust" # Feature normalization method
# Reward engineering for RL
reward_structure:
correct_direction_base: 1.0 # Base reward for correct prediction
confidence_scaling: true # Scale reward by confidence
magnitude_bonus: 0.5 # Bonus for predicting magnitude accurately
overconfidence_penalty: 1.5 # Penalty multiplier for wrong high-confidence predictions
trade_execution_multiplier: 10.0 # Higher weight for actual trade outcomes
# Performance monitoring
statistics_interval_s: 60 # Print stats every minute
detailed_logging: true # Enable detailed performance logging
# Web Dashboard
web:
host: "127.0.0.1"
port: 8050
debug: false
update_interval: 500 # Milliseconds
chart_history: 200 # Number of candles to show
# Enhanced dashboard features
show_timeframe_analysis: true
show_confidence_scores: true
show_perfect_moves: true
show_rl_metrics: true
# Logging
logging:
level: "INFO"
format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
file: "logs/enhanced_trading.log"
max_size: 10485760 # 10MB
backup_count: 5
# Component-specific logging
orchestrator_level: "INFO"
cnn_level: "INFO"
rl_level: "INFO"
training_level: "INFO"
# Model Directories
model_dir: "models"
data_dir: "data"
cache_dir: "cache"
logs_dir: "logs"
# GPU/Performance
gpu:
enabled: true
memory_fraction: 0.8 # Use 80% of GPU memory
allow_growth: true # Allow dynamic memory allocation
# Monitoring and Alerting
monitoring:
tensorboard_enabled: true
tensorboard_log_dir: "logs/tensorboard"
metrics_interval: 300 # Log metrics every 5 minutes
performance_alerts: true
# Performance thresholds
min_confidence_threshold: 0.3
max_memory_usage: 0.9 # 90% of available memory
max_decision_latency: 10 # 10 seconds max per decision
# Backtesting (for future implementation)
backtesting:
start_date: "2024-01-01"
end_date: "2024-12-31"
initial_balance: 10000
commission: 0.0002
slippage: 0.0001
model_paths:
realtime_model: "NN/models/saved/optimized_short_term_model_realtime_best.pt"
ticks_model: "NN/models/saved/optimized_short_term_model_ticks_best.pt"
backup_model: "NN/models/saved/realtime_ticks_checkpoints/checkpoint_epoch_50449_backup/model.pt"

View File

@ -27,7 +27,6 @@ try:
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, WebDriverException
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
except ImportError:
print("Please install selenium and webdriver-manager:")
print("pip install selenium webdriver-manager")
@ -67,73 +66,74 @@ class MEXCRequestInterceptor:
self.requests_file = f"mexc_requests_{self.timestamp}.json"
self.cookies_file = f"mexc_cookies_{self.timestamp}.json"
def setup_chrome_with_logging(self) -> webdriver.Chrome:
"""Setup Chrome with performance logging enabled"""
logger.info("Setting up ChromeDriver with request interception...")
# Chrome options
chrome_options = Options()
def setup_browser(self):
"""Setup Chrome browser with necessary options"""
chrome_options = webdriver.ChromeOptions()
# Enable headless mode if needed
if self.headless:
chrome_options.add_argument("--headless")
logger.info("Running in headless mode")
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--window-size=1920,1080')
chrome_options.add_argument('--disable-extensions')
# Essential options for automation
chrome_options.add_argument("--no-sandbox")
chrome_options.add_argument("--disable-dev-shm-usage")
chrome_options.add_argument("--disable-blink-features=AutomationControlled")
chrome_options.add_argument("--disable-web-security")
chrome_options.add_argument("--allow-running-insecure-content")
chrome_options.add_argument("--disable-features=VizDisplayCompositor")
# Set up Chrome options with a user data directory to persist session
user_data_base_dir = os.path.join(os.getcwd(), 'chrome_user_data')
os.makedirs(user_data_base_dir, exist_ok=True)
# User agent to avoid detection
user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36"
chrome_options.add_argument(f"--user-agent={user_agent}")
# Check for existing session directories
session_dirs = [d for d in os.listdir(user_data_base_dir) if d.startswith('session_')]
session_dirs.sort(reverse=True) # Sort descending to get the most recent first
# Disable automation flags
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
chrome_options.add_experimental_option('useAutomationExtension', False)
user_data_dir = None
if session_dirs:
use_existing = input(f"Found {len(session_dirs)} existing sessions. Use an existing session? (y/n): ").lower().strip() == 'y'
if use_existing:
print("Available sessions:")
for i, session in enumerate(session_dirs[:5], 1): # Show up to 5 most recent
print(f"{i}. {session}")
choice = input("Enter session number (default 1) or any other key for most recent: ")
if choice.isdigit() and 1 <= int(choice) <= len(session_dirs):
selected_session = session_dirs[int(choice) - 1]
else:
selected_session = session_dirs[0]
user_data_dir = os.path.join(user_data_base_dir, selected_session)
print(f"Using session: {selected_session}")
# Enable performance logging for network requests
chrome_options.add_argument("--enable-logging")
chrome_options.add_argument("--log-level=0")
chrome_options.add_argument("--v=1")
if user_data_dir is None:
user_data_dir = os.path.join(user_data_base_dir, f'session_{self.timestamp}')
os.makedirs(user_data_dir, exist_ok=True)
print(f"Creating new session: session_{self.timestamp}")
# Set capabilities for performance logging
caps = DesiredCapabilities.CHROME
caps['goog:loggingPrefs'] = {
'performance': 'ALL',
'browser': 'ALL'
}
chrome_options.add_argument(f'--user-data-dir={user_data_dir}')
# Enable logging to capture JS console output and network activity
chrome_options.set_capability('goog:loggingPrefs', {
'browser': 'ALL',
'performance': 'ALL'
})
try:
# Automatically download and install ChromeDriver
logger.info("Downloading/updating ChromeDriver...")
service = Service(ChromeDriverManager().install())
# Create driver
driver = webdriver.Chrome(
service=service,
options=chrome_options,
desired_capabilities=caps
)
# Hide automation indicators
driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")
driver.execute_cdp_cmd('Network.setUserAgentOverride', {
"userAgent": user_agent
})
# Enable network domain for CDP
driver.execute_cdp_cmd('Network.enable', {})
driver.execute_cdp_cmd('Runtime.enable', {})
logger.info("ChromeDriver setup complete!")
return driver
self.driver = webdriver.Chrome(options=chrome_options)
except Exception as e:
logger.error(f"Failed to setup ChromeDriver: {e}")
raise
print(f"Failed to start browser with session: {e}")
print("Falling back to a new session...")
user_data_dir = os.path.join(user_data_base_dir, f'session_{self.timestamp}_fallback')
os.makedirs(user_data_dir, exist_ok=True)
print(f"Creating fallback session: session_{self.timestamp}_fallback")
chrome_options = webdriver.ChromeOptions()
if self.headless:
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
chrome_options.add_argument('--window-size=1920,1080')
chrome_options.add_argument('--disable-extensions')
chrome_options.add_argument(f'--user-data-dir={user_data_dir}')
chrome_options.set_capability('goog:loggingPrefs', {
'browser': 'ALL',
'performance': 'ALL'
})
self.driver = webdriver.Chrome(options=chrome_options)
return self.driver
def start_monitoring(self):
"""Start the browser and begin monitoring"""
@ -141,7 +141,7 @@ class MEXCRequestInterceptor:
try:
# Setup ChromeDriver
self.driver = self.setup_chrome_with_logging()
self.driver = self.setup_browser()
# Navigate to MEXC futures
mexc_url = "https://www.mexc.com/en-GB/futures/ETH_USDT?type=linear_swap"
@ -322,6 +322,27 @@ class MEXCRequestInterceptor:
print(f"\n🚀 CAPTURED REQUEST: {request_info['method']} {url}")
if request_info['postData']:
print(f" 📄 POST Data: {request_info['postData'][:100]}...")
# Enhanced captcha detection and detailed logging
if 'captcha' in url.lower() or 'robot' in url.lower():
logger.info(f"CAPTCHA REQUEST DETECTED: {request_data.get('request', {}).get('method', 'UNKNOWN')} {url}")
logger.info(f" Headers: {request_data.get('request', {}).get('headers', {})}")
if request_data.get('request', {}).get('postData', ''):
logger.info(f" Data: {request_data.get('request', {}).get('postData', '')}")
# Attempt to capture related JavaScript or DOM elements (if possible)
if self.driver is not None:
try:
js_snippet = self.driver.execute_script("return document.querySelector('script[src*=\"captcha\"]') ? document.querySelector('script[src*=\"captcha\"]').outerHTML : 'No captcha script found';")
logger.info(f" Related JS Snippet: {js_snippet}")
except Exception as e:
logger.warning(f" Could not capture JS snippet: {e}")
try:
dom_element = self.driver.execute_script("return document.querySelector('div[id*=\"captcha\"]') ? document.querySelector('div[id*=\"captcha\"]').outerHTML : 'No captcha element found';")
logger.info(f" Related DOM Element: {dom_element}")
except Exception as e:
logger.warning(f" Could not capture DOM element: {e}")
else:
logger.warning(" Driver not initialized, cannot capture JS or DOM elements")
except Exception as e:
logger.debug(f"Error processing request: {e}")
@ -417,6 +438,16 @@ class MEXCRequestInterceptor:
if self.session_cookies:
print(f" 🍪 Cookies: {self.cookies_file}")
# Extract and save CAPTCHA tokens from captured requests
captcha_tokens = self.extract_captcha_tokens()
if captcha_tokens:
captcha_file = f"mexc_captcha_tokens_{self.timestamp}.json"
with open(captcha_file, 'w') as f:
json.dump(captcha_tokens, f, indent=2)
logger.info(f"Saved CAPTCHA tokens to {captcha_file}")
else:
logger.warning("No CAPTCHA tokens found in captured requests")
except Exception as e:
print(f"❌ Error saving data: {e}")
@ -466,6 +497,28 @@ class MEXCRequestInterceptor:
if self.save_to_file and (self.captured_requests or self.captured_responses):
self._save_all_data()
logger.info("Final data save complete")
def extract_captcha_tokens(self):
"""Extract CAPTCHA tokens from captured requests"""
captcha_tokens = []
for request in self.captured_requests:
if 'captcha-token' in request.get('headers', {}):
token = request['headers']['captcha-token']
captcha_tokens.append({
'token': token,
'url': request.get('url', ''),
'timestamp': request.get('timestamp', '')
})
elif 'captcha' in request.get('url', '').lower():
response = request.get('response', {})
if response and 'captcha-token' in response.get('headers', {}):
token = response['headers']['captcha-token']
captcha_tokens.append({
'token': token,
'url': request.get('url', ''),
'timestamp': request.get('timestamp', '')
})
return captcha_tokens
def main():
"""Main function to run the interceptor"""

View File

@ -0,0 +1,37 @@
{
"note": "No CAPTCHA tokens were found in the latest run. Manual extraction of cookies may be required from mexc_requests_20250703_024032.json.",
"credentials": {
"cookies": {
"bm_sv": "D92603BBC020E9C2CD11B2EBC8F22050~YAAQJKVf1NW5K7CXAQAAwtMVzRzHARcY60jrPVzy9G79fN3SY4z988SWHHxQlbPpyZHOj76c20AjCnS0QwveqzB08zcRoauoIe/sP3svlaIso9PIdWay0KIIVUe1XsiTJRfTm/DmS+QdrOuJb09rbfWLcEJF4/0QK7VY0UTzPTI2V3CMtxnmYjd1+tjfYsvt1R6O+Mw9mYjb7SjhRmiP/exY2UgZdLTJiqd+iWkc5Wejy5m6g5duOfRGtiA9mfs=~1",
"bm_sz": "98D80FE4B23FE6352AE5194DA699FDDB~YAAQJKVf1GK4K7CXAQAAeQ0UzRw+aXiY5/Ujp+sZm0a4j+XAJFn6fKT4oph8YqIKF6uHSgXkFY3mBt8WWY98Y2w1QzOEFRkje8HTUYQgJsV59y5DIOTZKC6wutPD/bKdVi9ZKtk4CWbHIIRuCrnU1Nw2jqj5E0hsorhKGh8GeVsAeoao8FWovgdYD6u8Qpbr9aL5YZgVEIqJx6WmWLmcIg+wA8UFj8751Fl0B3/AGxY2pACUPjonPKNuX/UDYA5e98plOYUnYLyQMEGIapSrWKo1VXhKBDPLNedJ/Q2gOCGEGlj/u1Fs407QxxXwCvRSegL91y6modtL5JGoFucV1pYc4pgTwEAEdJfcLCEBaButTbaHI9T3SneqgCoGeatMMaqz0GHbvMD7fBQofARBqzN1L6aGlmmAISMzI3wx/SnsfXBl~3228228~3294529",
"_abck": "0288E759712AF333A6EE15F66BC2A662~-1~YAAQJKVf1GC4K7CXAQAAeQ0UzQ77TfyX5SOWTgdW3DVqNFrTLz2fhLo2OC4I6ZHnW9qB0vwTjFDfOB65BwLSeFZoyVypVCGTtY/uL6f4zX0AxEGAU8tLg/jeO0acO4JpGrjYZSW1F56vEd9JbPU2HQPNERorgCDLQMSubMeLCfpqMp3VCW4w0Ssnk6Y4pBSs4mh0PH95v56XXDvat9k20/JPoK3Ip5kK2oKh5Vpk5rtNTVea66P0NBjVUw/EddRUuDDJpc8T4DtTLDXnD5SNDxEq8WDkrYd5kP4dNe0PtKcSOPYs2QLUbvAzfBuMvnhoSBaCjsqD15EZ3eDAoioli/LzsWSxaxetYfm0pA/s5HBXMdOEDi4V0E9b79N28rXcC8IJEHXtfdZdhJjwh1FW14lqF9iuOwER81wDEnIVtgwTwpd3ffrc35aNjb+kGiQ8W0FArFhUI/ZY2NDvPVngRjNrmRm0CsCm+6mdxxVNsGNMPKYG29mcGDi2P9HGDk45iOm0vzoaYUl1PlOh4VGq/V3QGbPYpkBsBtQUjrf/SQJe5IAbjCICTYlgxTo+/FAEjec+QdUsagTgV8YNycQfTK64A2bs1L1n+RO5tapLThU6NkxnUbqHOm6168RnT8ZRoAUpkJ5m3QpqSsuslnPRUPyxUr73v514jTBIUGsq4pUeRpXXd9FAh8Xkn4VZ9Bh3q4jP7eZ9Sv58mgnEVltNBFkeG3zsuIp5Hu69MSBU+8FD4gVlncbBinrTLNWRB8F00Gyvc03unrAznsTEyLiDq9guQf9tQNcGjxfggfnGq/Z1Gy/A7WMjiYw7pwGRVzAYnRgtcZoww9gQ/FdGkbp2Xl+oVZpaqFsHVvafWyOFr4pqQsmd353ddgKLjsEnpy/jcdUsIR/Ph3pYv++XlypXehXj0/GHL+WsosujJrYk4TuEsPKUcyHNr+r844mYUIhCYsI6XVKrq3fimdfdhmlkW8J1kZSTmFwP8QcwGlTK/mZDTJPyf8K5ugXcqOU8oIQzt5B2zfRwRYKHdhb8IUw=~-1~-1~-1",
"RT": "\"z=1&dm=www.mexc.com&si=f5d53b58-7845-4db4-99f1-444e43d35199&ss=mcmh857q&sl=3&tt=90n&bcn=%2F%2F684dd311.akstat.io%2F&ld=1c9o\"",
"mexc_fingerprint_visitorId": "tv1xchuZQbx9N0aBztUG",
"_ga_L6XJCQTK75": "GS2.1.s1751492192$o1$g1$t1751492248$j4$l0$h0",
"uc_token": "WEB66f893ede865e5d927efdea4a82e655ad5190239c247997d744ef9cd075f6f1e",
"u_id": "WEB66f893ede865e5d927efdea4a82e655ad5190239c247997d744ef9cd075f6f1e",
"_fbp": "fb.1.1751492193579.314807866777158389",
"mxc_exchange_layout": "BA",
"sensorsdata2015jssdkcross": "%7B%22distinct_id%22%3A%2221a8728990b84f4fa3ae64c8004b4aaa%22%2C%22first_id%22%3A%22197cd11dc751be-0dd66c04c69e96-26011f51-3686400-197cd11dc76189d%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_referrer%22%3A%22%22%2C%22%24latest_landing_page%22%3A%22https%3A%2F%2Fwww.mexc.com%2Fen-GB%2Flogin%3Fprevious%3D%252Ffutures%252FETH_USDT%253Ftype%253Dlinear_swap%22%7D%2C%22identities%22%3A%22eyIkaWRlbnRpdHlfY29va2llX2lkIjoiMTk3Y2QxMWRjNzUxYmUtMGRkNjZjMDRjNjllOTYtMjYwMTFmNTEtMzY4NjQwMC0xOTdjZDExZGM3NjE4OWQiLCIkaWRlbnRpdHlfbG9naW5faWQiOiIyMWE4NzI4OTkwYjg0ZjRmYTNhZTY0YzgwMDRiNGFhYSJ9%22%2C%22history_login_id%22%3A%7B%22name%22%3A%22%24identity_login_id%22%2C%22value%22%3A%2221a8728990b84f4fa3ae64c8004b4aaa%22%7D%2C%22%24device_id%22%3A%22197cd11dc751be-0dd66c04c69e96-26011f51-3686400-197cd11dc76189d%22%7D",
"mxc_theme_main": "dark",
"mexc_fingerprint_requestId": "1751492199306.WMvKJd",
"_ym_visorc": "b",
"mexc_clearance_modal_show_date": "2025-07-03-undefined",
"ak_bmsc": "35C21AA65F819E0BF9BEBDD10DCF7B70~000000000000000000000000000000~YAAQJKVf1BK2K7CXAQAAPAISzRwQdUOUs1H3HPAdl4COMFQAl+aEPzppLbdgrwA7wXbP/LZpxsYCFflUHDppYKUjzXyTZ9tIojSF3/6CW3OCiPhQo/qhf6XPbC4oQHpCNWaC9GJWEs/CGesQdfeBbhkXdfh+JpgmgCF788+x8IveDE9+9qaL/3QZRy+E7zlKjjvmMxBpahRy+ktY9/KMrCY2etyvtm91KUclr4k8HjkhtNJOlthWgUyiANXJtfbNUMgt+Hqgqa7QzSUfAEpxIXQ1CuROoY9LbU292LRN5TbtBy/uNv6qORT38rKsnpi7TGmyFSB9pj3YsoSzIuAUxYXSh4hXRgAoUQm3Yh5WdLp4ONeyZC1LIb8VCY5xXRy/VbfaHH1w7FodY1HpfHGKSiGHSNwqoiUmMPx13Rgjsgki4mE7bwFmG2H5WAilRIOZA5OkndEqGrOuiNTON7l6+g6mH0MzZ+/+3AjnfF2sXxFuV9itcs9x",
"mxc_theme_upcolor": "upgreen",
"_vid_t": "mQUFl49q1yLZhrL4tvOtFF38e+hGW5QoMS+eXKVD9Q4vQau6icnyipsdyGLW/FBukiO2ItK7EtzPIPMFrE5SbIeLSm1NKc/j+ZmobhX063QAlskf1x1J",
"_ym_isad": "2",
"_ym_d": "1751492196",
"_ym_uid": "1751492196843266888",
"bm_mi": "02862693F007017AEFD6639269A60D08~YAAQJKVf1Am2K7CXAQAAIf4RzRzNGqZ7Q3BC0kAAp/0sCOhHxxvEWTb7mBl8p7LUz0W6RZbw5Etz03Tvqu3H6+sb+yu1o0duU+bDflt7WLVSOfG5cA3im8Jeo6wZhqmxTu6gGXuBgxhrHw/RGCgcknxuZQiRM9cbM6LlZIAYiugFm2xzmO/1QcpjDhs4S8d880rv6TkMedlkYGwdgccAmvbaRVSmX9d5Yukm+hY+5GWuyKMeOjpatAhcgjShjpSDwYSpyQE7vVZLBp7TECIjI9uoWzR8A87YHScKYEuE08tb8YtGdG3O6g70NzasSX0JF3XTCjrVZA==~1",
"_ga": "GA1.1.626437359.1751492192",
"NEXT_LOCALE": "en-GB",
"x-mxc-fingerprint": "tv1xchuZQbx9N0aBztUG",
"CLIENT_LANG": "en-GB",
"sajssdk_2015_cross_new_user": "1"
},
"captcha_token_open": "geetest eyJsb3ROdW1iZXIiOiI4NWFhM2Q3YjJkYmE0Mjk3YTQwODY0YmFhODZiMzA5NyIsImNhcHRjaGFPdXRwdXQiOiJaVkwzS3FWaWxnbEZjQWdXOENIQVgxMUVBLVVPUnE1aURQSldzcmlubDFqelBhRTNiUGlEc0VrVTJUR0xuUzRHV2k0N2JDa1hyREMwSktPWmwxX1dERkQwNWdSN1NkbFJ1Z2NDY0JmTGdLVlNBTEI0OUNrR200enZZcnZ3MUlkdnQ5RThRZURYQ2E0empLczdZMHByS3JEWV9SQW93S0d4OXltS0MxMlY0SHRzNFNYMUV1YnI1ZV9yUXZCcTZJZTZsNFVJMS1DTnc5RUhBaXRXOGU2TVZ6OFFqaGlUMndRM1F3eGxEWkpmZnF6M3VucUl5RTZXUnFSUEx1T0RQQUZkVlB3S3AzcWJTQ3JXcG5CTUFKOXFuXzV2UDlXNm1pR3FaRHZvSTY2cWRzcHlDWUMyWTV1RzJ0ZjZfRHRJaXhTTnhLWUU3cTlfcU1WR2ZJUzlHUXh6ZWg2Mkp2eG02SHZLdjFmXzJMa3FlcVkwRk94S2RxaVpyN2NkNjAxMHE5UlFJVDZLdmNZdU1Hcm04M2d4SnY1bXp4VkZCZWZFWXZfRjZGWGpnWXRMMmhWSDlQME42bHFXQkpCTUVicE1nRm0zbm1iZVBkaDYxeW12T0FUb2wyNlQ0Z2ZET2dFTVFhZTkxQlFNR2FVSFRSa2c3RGJIX2xMYXlBTHQ0TTdyYnpHSCIsInBhc3NUb2tlbiI6IjA0NmFkMGQ5ZjNiZGFmYzJhNDgwYzFiMjcyMmIzZDUzOTk5NTRmYWVlNTM1MTI1ZTQ1MjkzNzJjYWZjOGI5N2EiLCJnZW5UaW1lIjoiMTc1MTQ5ODY4NCJ9",
"captcha_token_close": "geetest eyJsb3ROdW1iZXIiOiI5ZWVlMDQ2YTg1MmQ0MTU3YTNiYjdhM2M5MzJiNzJiYSIsImNhcHRjaGFPdXRwdXQiOiJaVkwzS3FWaWxnbEZjQWdXOENIQVgxMUVBLVVPUnE1aURQSldzcmlubDFqelBhRTNiUGlEc0VrVTJUR0xuUzRHZk9hVUhKRW1ZOS1FN0h3Q3NNV3hvbVZsNnIwZXRYZzIyWHBGdUVUdDdNS19Ud1J6NnotX2pCXzRkVDJqTnJRN0J3cExjQ25DNGZQUXQ5V040TWxrZ0NMU3p6MERNd09SeHJCZVRkVE5pSU5BdmdFRDZOMkU4a19XRmJ6SFZsYUtieElnM3dLSGVTMG9URU5DLUNaNElnMDJlS2x3UWFZY3liRnhKU2ZrWG1vekZNMDVJSHVDYUpwT0d2WXhhYS1YTWlDeGE0TnZlcVFqN2JwNk04Q09PSnNxNFlfa0pkX0Ruc2w0UW1memZCUTZseF9tenFCMnFweThxd3hKTFVYX0g3TGUyMXZ2bGtubG1KS0RSUEJtTWpUcGFiZ2F4M3Q1YzJmbHJhRjk2elhHQzVBdVVQY1FrbDIyOW0xSmlnMV83cXNfTjdpZFozd0hRcWZFZGxSYVRKQTR2U18yYnFlcGdkLblJ3Y3oxaWtOOW1RaWNOSnpSNFNhdm1Pdi1BSzhwSEF0V2lkVjhrTkVYc3dGbUdSazFKQXBEX1hVUjlEdl9sNWJJNEFnbVJhcVlGdjhfRUNvN1g2cmt2UGZuOElTcCIsInBhc3NUb2tlbiI6IjRmZDFhZmU5NzI3MTk0ZGI3MDNlMDg2NWQ0ZDZjZTIyYWzMwMzUyNzQ5NzVjMDIwNDFiNTY3Y2Y3MDdhYjM1OTMiLCJnZW5UaW1lIjoiMTc1MTQ5ODY5MiJ9"
}
}

View File

@ -19,9 +19,22 @@ from typing import Dict, List, Optional, Any
from datetime import datetime
import uuid
from urllib.parse import urlencode
import glob
import os
logger = logging.getLogger(__name__)
class MEXCSessionManager:
def __init__(self):
self.captcha_token = None
def get_captcha_token(self) -> str:
return self.captcha_token if self.captcha_token else ""
def save_captcha_token(self, token: str):
self.captcha_token = token
logger.info("MEXC: Captcha token saved in session manager")
class MEXCFuturesWebClient:
"""
MEXC Futures Web Client that mimics browser behavior for futures trading.
@ -30,30 +43,27 @@ class MEXCFuturesWebClient:
the exact HTTP requests made by their web interface.
"""
def __init__(self, session_cookies: Dict[str, str] = None):
def __init__(self, api_key: str, api_secret: str, user_id: str, base_url: str = 'https://www.mexc.com', headless: bool = True):
"""
Initialize the MEXC Futures Web Client
Args:
session_cookies: Dictionary of cookies from an authenticated browser session
api_key: API key for authentication
api_secret: API secret for authentication
user_id: User ID for authentication
base_url: Base URL for the MEXC website
headless: Whether to run the browser in headless mode
"""
self.session = requests.Session()
# Base URLs for different endpoints
self.base_url = "https://www.mexc.com"
self.futures_api_url = "https://futures.mexc.com/api/v1"
self.captcha_url = f"{self.base_url}/ucgateway/captcha_api/captcha/robot"
# Session state
self.api_key = api_key
self.api_secret = api_secret
self.user_id = user_id
self.base_url = base_url
self.is_authenticated = False
self.user_id = None
self.auth_token = None
self.fingerprint = None
self.visitor_id = None
# Load session cookies if provided
if session_cookies:
self.load_session_cookies(session_cookies)
self.headless = headless
self.session = requests.Session()
self.session_manager = MEXCSessionManager() # Adding session_manager attribute
self.captcha_url = f'{base_url}/ucgateway/captcha_api'
self.futures_api_url = "https://futures.mexc.com/api/v1"
# Setup default headers that mimic a real browser
self.setup_browser_headers()
@ -72,7 +82,12 @@ class MEXCFuturesWebClient:
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-origin',
'Cache-Control': 'no-cache',
'Pragma': 'no-cache'
'Pragma': 'no-cache',
'Referer': f'{self.base_url}/en-GB/futures/ETH_USDT?type=linear_swap',
'Language': 'English',
'X-Language': 'en-GB',
'trochilus-trace-id': f"{uuid.uuid4()}-{int(time.time() * 1000) % 10000:04d}",
'trochilus-uid': str(self.user_id) if self.user_id is not None else ''
})
def load_session_cookies(self, cookies: Dict[str, str]):
@ -137,37 +152,73 @@ class MEXCFuturesWebClient:
endpoint = f"robot.future.{side}.{symbol}.{leverage}"
url = f"{self.captcha_url}/{endpoint}"
# Setup headers for captcha request
# Attempt to get captcha token from session manager
captcha_token = self.session_manager.get_captcha_token()
if not captcha_token:
logger.warning("MEXC: No captcha token available, attempting to fetch from browser")
captcha_token = self._extract_captcha_token_from_browser()
if captcha_token:
self.session_manager.save_captcha_token(captcha_token)
else:
logger.error("MEXC: Failed to extract captcha token from browser")
return False
headers = {
'Content-Type': 'application/json',
'Language': 'en-GB',
'Referer': f'{self.base_url}/en-GB/futures/{symbol}?type=linear_swap',
'trochilus-uid': self.user_id,
'trochilus-trace-id': f"{uuid.uuid4()}-{int(time.time() * 1000) % 10000:04d}"
'trochilus-uid': self.user_id if self.user_id else '',
'trochilus-trace-id': f"{uuid.uuid4()}-{int(time.time() * 1000) % 10000:04d}",
'captcha-token': captcha_token
}
# Add captcha token if available (this would need to be extracted from browser)
# For now, we'll make the request without it and see what happens
logger.info(f"MEXC: Verifying captcha for {endpoint}")
try:
response = self.session.get(url, headers=headers, timeout=10)
if response.status_code == 200:
data = response.json()
if data.get('success') and data.get('code') == 0:
logger.info(f"MEXC: Captcha verification successful for {side} {symbol}")
if data.get('success'):
logger.info(f"MEXC: Captcha verified successfully for {endpoint}")
return True
else:
logger.warning(f"MEXC: Captcha verification failed: {data}")
logger.error(f"MEXC: Captcha verification failed for {endpoint}: {data}")
return False
else:
logger.error(f"MEXC: Captcha request failed with status {response.status_code}")
logger.error(f"MEXC: Captcha verification request failed with status {response.status_code}: {response.text}")
return False
except Exception as e:
logger.error(f"MEXC: Captcha verification error: {e}")
logger.error(f"MEXC: Captcha verification error for {endpoint}: {str(e)}")
return False
def _extract_captcha_token_from_browser(self) -> str:
"""
Extract captcha token from browser session using stored cookies or requests.
This method looks for the most recent mexc_captcha_tokens JSON file to retrieve a token.
"""
try:
# Look for the most recent mexc_captcha_tokens file
captcha_files = glob.glob("mexc_captcha_tokens_*.json")
if not captcha_files:
logger.error("MEXC: No CAPTCHA token files found")
return ""
# Sort files by timestamp (most recent first)
latest_file = max(captcha_files, key=os.path.getctime)
logger.info(f"MEXC: Using CAPTCHA token file {latest_file}")
with open(latest_file, 'r') as f:
captcha_data = json.load(f)
if captcha_data and isinstance(captcha_data, list) and len(captcha_data) > 0:
# Return the most recent token
return captcha_data[0].get('token', '')
else:
logger.error("MEXC: No valid CAPTCHA tokens found in file")
return ""
except Exception as e:
logger.error(f"MEXC: Error extracting captcha token from browser data: {str(e)}")
return ""
def generate_signature(self, method: str, path: str, params: Dict[str, Any],
timestamp: int, nonce: int) -> str:
"""

View File

@ -0,0 +1,346 @@
#!/usr/bin/env python3
"""
Test MEXC Futures Web Client
This script demonstrates how to use the MEXC Futures Web Client
for futures trading that isn't supported by their official API.
IMPORTANT: This requires extracting cookies from your browser session.
"""
import logging
import sys
import os
import time
import json
import uuid
# Add the project root to path
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from mexc_futures_client import MEXCFuturesWebClient
from session_manager import MEXCSessionManager
# Setup logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
# Constants
SYMBOL = "ETH_USDT"
LEVERAGE = 300
CREDENTIALS_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'mexc_credentials.json')
# Read credentials from mexc_credentials.json in JSON format
def load_credentials():
credentials_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'mexc_credentials.json')
cookies = {}
captcha_token_open = ''
captcha_token_close = ''
try:
with open(credentials_file, 'r') as f:
data = json.load(f)
cookies = data.get('credentials', {}).get('cookies', {})
captcha_token_open = data.get('credentials', {}).get('captcha_token_open', '')
captcha_token_close = data.get('credentials', {}).get('captcha_token_close', '')
logger.info(f"Loaded credentials from {credentials_file}")
except Exception as e:
logger.error(f"Error loading credentials: {e}")
return cookies, captcha_token_open, captcha_token_close
def test_basic_connection():
"""Test basic connection and authentication"""
logger.info("Testing MEXC Futures Web Client")
# Initialize session manager
session_manager = MEXCSessionManager()
# Try to load saved session first
cookies = session_manager.load_session()
if not cookies:
# Explicitly load the cookies from the file we have
cookies_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'mexc_cookies_20250703_003625.json')
if os.path.exists(cookies_file):
try:
with open(cookies_file, 'r') as f:
cookies = json.load(f)
logger.info(f"Loaded cookies from {cookies_file}")
except Exception as e:
logger.error(f"Failed to load cookies from {cookies_file}: {e}")
cookies = None
else:
logger.error(f"Cookies file not found at {cookies_file}")
cookies = None
if not cookies:
print("\nNo saved session found. You need to extract cookies from your browser.")
session_manager.print_cookie_extraction_guide()
print("\nPaste your cookie header or cURL command (or press Enter to exit):")
user_input = input().strip()
if not user_input:
print("No input provided. Exiting.")
return False
# Extract cookies from user input
if user_input.startswith('curl'):
cookies = session_manager.extract_from_curl_command(user_input)
else:
cookies = session_manager.extract_cookies_from_network_tab(user_input)
if not cookies:
logger.error("Failed to extract cookies from input")
return False
# Validate and save session
if session_manager.validate_session_cookies(cookies):
session_manager.save_session(cookies)
logger.info("Session saved for future use")
else:
logger.warning("Extracted cookies may be incomplete")
# Initialize the web client
client = MEXCFuturesWebClient(api_key='', api_secret='', user_id='', base_url='https://www.mexc.com', headless=True)
# Load cookies into the client's session
for name, value in cookies.items():
client.session.cookies.set(name, value)
# Update headers to include additional parameters from captured requests
client.session.headers.update({
'trochilus-trace-id': f"{uuid.uuid4()}-{int(time.time() * 1000) % 10000:04d}",
'trochilus-uid': cookies.get('u_id', ''),
'Referer': 'https://www.mexc.com/en-GB/futures/ETH_USDT?type=linear_swap',
'Language': 'English',
'X-Language': 'en-GB'
})
if not client.is_authenticated:
logger.error("Failed to authenticate with extracted cookies")
return False
logger.info("Successfully authenticated with MEXC")
logger.info(f"User ID: {client.user_id}")
logger.info(f"Auth Token: {client.auth_token[:20]}..." if client.auth_token else "No auth token")
return True
def test_captcha_verification(client: MEXCFuturesWebClient):
"""Test captcha verification system"""
logger.info("Testing captcha verification...")
# Test captcha for ETH_USDT long position with 200x leverage
success = client.verify_captcha('ETH_USDT', 'openlong', '200X')
if success:
logger.info("Captcha verification successful")
else:
logger.warning("Captcha verification failed - this may be normal if no position is being opened")
return success
def test_position_opening(client: MEXCFuturesWebClient, dry_run: bool = True):
"""Test opening a position (dry run by default)"""
if dry_run:
logger.info("DRY RUN: Testing position opening (no actual trade)")
else:
logger.warning("LIVE TRADING: Opening actual position!")
symbol = 'ETH_USDT'
volume = 1 # Small test position
leverage = 200
logger.info(f"Attempting to open long position: {symbol}, Volume: {volume}, Leverage: {leverage}x")
if not dry_run:
result = client.open_long_position(symbol, volume, leverage)
if result['success']:
logger.info(f"Position opened successfully!")
logger.info(f"Order ID: {result['order_id']}")
logger.info(f"Timestamp: {result['timestamp']}")
return True
else:
logger.error(f"Failed to open position: {result['error']}")
return False
else:
logger.info("DRY RUN: Would attempt to open position here")
# Test just the captcha verification part
return client.verify_captcha(symbol, 'openlong', f'{leverage}X')
def test_position_opening_live(client):
symbol = "ETH_USDT"
volume = 1 # Small volume for testing
leverage = 200
logger.info(f"LIVE TRADING: Opening actual position!")
logger.info(f"Attempting to open long position: {symbol}, Volume: {volume}, Leverage: {leverage}x")
result = client.open_long_position(symbol, volume, leverage)
if result.get('success'):
logger.info(f"Successfully opened position: {result}")
else:
logger.error(f"Failed to open position: {result.get('error', 'Unknown error')}")
def interactive_menu(client: MEXCFuturesWebClient):
"""Interactive menu for testing different functions"""
while True:
print("\n" + "="*50)
print("MEXC Futures Web Client Test Menu")
print("="*50)
print("1. Test captcha verification")
print("2. Test position opening (DRY RUN)")
print("3. Test position opening (LIVE - BE CAREFUL!)")
print("4. Test position closing (DRY RUN)")
print("5. Show session info")
print("6. Refresh session")
print("0. Exit")
choice = input("\nEnter choice (0-6): ").strip()
if choice == "1":
test_captcha_verification(client)
elif choice == "2":
test_position_opening(client, dry_run=True)
elif choice == "3":
test_position_opening_live(client)
elif choice == "4":
logger.info("DRY RUN: Position closing test")
success = client.verify_captcha('ETH_USDT', 'closelong', '200X')
if success:
logger.info("DRY RUN: Would close position here")
else:
logger.warning("Captcha verification failed for position closing")
elif choice == "5":
print(f"\nSession Information:")
print(f"Authenticated: {client.is_authenticated}")
print(f"User ID: {client.user_id}")
print(f"Auth Token: {client.auth_token[:20]}..." if client.auth_token else "None")
print(f"Fingerprint: {client.fingerprint}")
print(f"Visitor ID: {client.visitor_id}")
elif choice == "6":
session_manager = MEXCSessionManager()
session_manager.print_cookie_extraction_guide()
elif choice == "0":
print("Goodbye!")
break
else:
print("Invalid choice. Please try again.")
def main():
"""Main test function"""
print("MEXC Futures Web Client Test")
print("WARNING: This is experimental software for futures trading")
print("Use at your own risk and test with small amounts first!")
# Load cookies and tokens
cookies, captcha_token_open, captcha_token_close = load_credentials()
if not cookies:
logger.error("Failed to load cookies from credentials file")
sys.exit(1)
# Initialize client with loaded cookies and tokens
client = MEXCFuturesWebClient(api_key='', api_secret='', user_id='')
# Load cookies into the client's session
for name, value in cookies.items():
client.session.cookies.set(name, value)
# Set captcha tokens
client.captcha_token_open = captcha_token_open
client.captcha_token_close = captcha_token_close
# Try to load credentials from the new JSON file
try:
with open(CREDENTIALS_FILE, 'r') as f:
credentials_data = json.load(f)
cookies = credentials_data['credentials']['cookies']
captcha_token_open = credentials_data['credentials']['captcha_token_open']
captcha_token_close = credentials_data['credentials']['captcha_token_close']
client.load_session_cookies(cookies)
client.session_manager.save_captcha_token(captcha_token_open) # Assuming this is for opening
except FileNotFoundError:
logger.error(f"Credentials file not found at {CREDENTIALS_FILE}")
return False
except json.JSONDecodeError as e:
logger.error(f"Error loading credentials: {e}")
return False
except KeyError as e:
logger.error(f"Missing key in credentials file: {e}")
return False
if not client.is_authenticated:
logger.error("Client not authenticated. Please ensure valid cookies and tokens are in mexc_credentials.json")
return False
# Test connection and authentication
logger.info("Successfully authenticated with MEXC")
# Set leverage
leverage_response = client.update_leverage(symbol=SYMBOL, leverage=LEVERAGE)
if leverage_response and leverage_response.get('code') == 200:
logger.info(f"Leverage set to {LEVERAGE}x for {SYMBOL}")
else:
logger.error(f"Failed to set leverage: {leverage_response}")
sys.exit(1)
# Get current price
ticker = client.get_ticker_data(symbol=SYMBOL)
if ticker and ticker.get('code') == 200:
current_price = float(ticker['data']['last'])
logger.info(f"Current {SYMBOL} price: {current_price}")
else:
logger.error(f"Failed to get ticker data: {ticker}")
sys.exit(1)
# Calculate order size for a small test trade (e.g., $10 worth)
trade_usdt = 10.0
order_qty = round((trade_usdt / current_price) * LEVERAGE, 3)
logger.info(f"Calculated order quantity: {order_qty} {SYMBOL} for ~${trade_usdt} at {LEVERAGE}x")
# Test 1: Open LONG position
logger.info(f"Opening LONG position for {SYMBOL} at {current_price} with qty {order_qty}")
open_long_order = client.create_order(
symbol=SYMBOL,
side=1, # 1 for BUY
position_side=1, # 1 for LONG
order_type=1, # 1 for LIMIT
price=current_price,
vol=order_qty
)
if open_long_order and open_long_order.get('code') == 200:
logger.info(f"✅ Successfully opened LONG position: {open_long_order['data']}")
else:
logger.error(f"❌ Failed to open LONG position: {open_long_order}")
sys.exit(1)
# Test 2: Close LONG position
logger.info(f"Closing LONG position for {SYMBOL}")
close_long_order = client.create_order(
symbol=SYMBOL,
side=2, # 2 for SELL
position_side=1, # 1 for LONG
order_type=1, # 1 for LIMIT
price=current_price,
vol=order_qty,
reduce_only=True
)
if close_long_order and close_long_order.get('code') == 200:
logger.info(f"✅ Successfully closed LONG position: {close_long_order['data']}")
else:
logger.error(f"❌ Failed to close LONG position: {close_long_order}")
sys.exit(1)
logger.info("All tests completed successfully!")
if __name__ == "__main__":
main()

View File

@ -3,6 +3,9 @@ Trading Executor for MEXC API Integration
This module handles the execution of trading signals through the MEXC exchange API.
It includes position management, risk controls, and safety features.
https://github.com/mexcdevelop/mexc-api-postman/blob/main/MEXC%20V3.postman_collection.json
MEXC V3.postman_collection.json
"""
import logging
@ -89,7 +92,8 @@ class TradingExecutor:
self.exchange = MEXCInterface(
api_key=api_key,
api_secret=api_secret,
test_mode=exchange_test_mode
test_mode=exchange_test_mode,
trading_mode=trading_mode
)
# Trading state
@ -101,6 +105,8 @@ class TradingExecutor:
self.trading_enabled = self.mexc_config.get('enabled', False)
self.trading_mode = trading_mode
logger.debug(f"TRADING EXECUTOR: Initial trading_enabled state from config: {self.trading_enabled}")
# Legacy compatibility (deprecated)
self.dry_run = self.simulation_mode
@ -109,7 +115,12 @@ class TradingExecutor:
# Connect to exchange
if self.trading_enabled:
self._connect_exchange()
logger.info("TRADING EXECUTOR: Attempting to connect to exchange...")
if not self._connect_exchange():
logger.error("TRADING EXECUTOR: Failed initial exchange connection. Trading will be disabled.")
self.trading_enabled = False
else:
logger.info("TRADING EXECUTOR: Trading is explicitly disabled in config.")
logger.info(f"Trading Executor initialized - Mode: {self.trading_mode}, Enabled: {self.trading_enabled}")
@ -143,17 +154,20 @@ class TradingExecutor:
def _connect_exchange(self) -> bool:
"""Connect to the MEXC exchange"""
try:
logger.debug("TRADING EXECUTOR: Calling self.exchange.connect()...")
connected = self.exchange.connect()
logger.debug(f"TRADING EXECUTOR: self.exchange.connect() returned: {connected}")
if connected:
logger.info("Successfully connected to MEXC exchange")
return True
else:
logger.error("Failed to connect to MEXC exchange")
logger.error("Failed to connect to MEXC exchange: Connection returned False.")
if not self.dry_run:
logger.info("TRADING EXECUTOR: Setting trading_enabled to False due to connection failure.")
self.trading_enabled = False
return False
except Exception as e:
logger.error(f"Error connecting to MEXC exchange: {e}")
logger.error(f"Error connecting to MEXC exchange: {e}. Setting trading_enabled to False.")
self.trading_enabled = False
return False
@ -170,8 +184,9 @@ class TradingExecutor:
Returns:
bool: True if trade executed successfully
"""
logger.debug(f"TRADING EXECUTOR: execute_signal called. trading_enabled: {self.trading_enabled}")
if not self.trading_enabled:
logger.info(f"Trading disabled - Signal: {action} {symbol} (confidence: {confidence:.2f})")
logger.info(f"Trading disabled - Signal: {action} {symbol} (confidence: {confidence:.2f}) - Reason: Trading executor is not enabled.")
return False
if action == 'HOLD':
@ -181,23 +196,51 @@ class TradingExecutor:
if not self._check_safety_conditions(symbol, action):
return False
# Get current price if not provided
# Get current price if not provided
if current_price is None:
ticker = self.exchange.get_ticker(symbol)
if not ticker:
logger.error(f"Failed to get current price for {symbol}")
if not ticker or 'last' not in ticker:
logger.error(f"Failed to get current price for {symbol} or ticker is malformed.")
return False
current_price = ticker['last']
# Assert that current_price is not None for type checking
assert current_price is not None, "current_price should not be None at this point"
# --- Balance check before executing trade ---
# Only perform balance check for BUY actions or SHORT (initial sell) actions
if action == 'BUY' or (action == 'SELL' and symbol not in self.positions) or (action == 'SHORT'):
# 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
else:
# Fallback for symbols like ETHUSDT (assuming last 4 chars are quote)
quote_asset = symbol[-4:].upper()
# 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)
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:
logger.warning(f"Trade blocked for {symbol} {action}: Insufficient {quote_asset} balance. "
f"Required: ${required_capital:.2f}, Available: ${available_balance:.2f}")
return False
# --- End Balance check ---
with self.lock:
try:
if action == 'BUY':
return self._execute_buy(symbol, confidence, current_price)
elif action == 'SELL':
return self._execute_sell(symbol, confidence, current_price)
elif action == 'SHORT': # Explicitly handle SHORT if it's a direct signal
return self._execute_short(symbol, confidence, current_price)
else:
logger.warning(f"Unknown action: {action}")
return False

View File

@ -0,0 +1,45 @@
# MEXC CAPTCHA Handling Documentation
## Overview
This document outlines the mechanism implemented in the `gogo2` trading dashboard project to handle CAPTCHA challenges encountered during automated trading on the MEXC platform. The goal is to enable seamless trading operations without manual intervention by capturing and integrating CAPTCHA tokens.
## CAPTCHA Handling Mechanism
### 1. Browser Automation with `MEXCBrowserAutomation`
- The `MEXCBrowserAutomation` class in `core/mexc_webclient/auto_browser.py` is responsible for launching a browser session using Selenium WebDriver.
- It navigates to the MEXC futures trading page and captures HTTP requests and responses, including those related to CAPTCHA challenges.
- When a CAPTCHA request is detected (e.g., requests to `gcaptcha4.geetest.com` or specific MEXC CAPTCHA endpoints), the relevant token is extracted from the request headers or response data.
- These tokens are saved to JSON files named `mexc_captcha_tokens_YYYYMMDD_HHMMSS.json` in the project root directory for later use.
### 2. Integration with `MEXCFuturesWebClient`
- The `MEXCFuturesWebClient` class in `core/mexc_webclient/mexc_futures_client.py` is updated to handle CAPTCHA challenges during API requests.
- A `MEXCSessionManager` class manages session data, including cookies and CAPTCHA tokens, by reading the latest token from the saved JSON files.
- When a request fails due to a CAPTCHA challenge, the client retrieves the latest token and includes it in the request headers under `captcha-token`.
### 3. Manual Testing and Data Capture
- The script `run_mexc_browser.py` provides an interactive way to test the `MEXCFuturesWebClient` and capture CAPTCHA tokens.
- Users can run this script to perform test trades, monitor requests, and save captured data, including tokens, to files.
- The captured tokens are used in subsequent API calls to authenticate trading actions like opening or closing positions.
## Usage Instructions
### Running Browser Automation
1. Execute `python run_mexc_browser.py` to start the browser automation.
2. Choose options like 'Perform test trade (manual)' to simulate trading actions and capture CAPTCHA tokens.
3. The script saves tokens to a JSON file, which can be used by `MEXCFuturesWebClient` for automated trading.
### Automated Trading with CAPTCHA Tokens
- Ensure that the `MEXCFuturesWebClient` is configured to use the latest CAPTCHA token file. This is handled automatically by the `MEXCSessionManager` class, which looks for the most recent file matching the pattern `mexc_captcha_tokens_*.json`.
- If a CAPTCHA challenge is encountered during trading, the client will attempt to use the saved token to proceed with the request.
## Limitations and Notes
- **Token Validity**: CAPTCHA tokens have a limited validity period. If the saved token is outdated, a new browser session may be required to capture fresh tokens.
- **Automation**: Currently, token capture requires manual initiation via `run_mexc_browser.py`. Future enhancements may include background automation for continuous token updates.
- **Windows Compatibility**: All scripts and file operations are designed to work on Windows systems, adhering to project rules for compatibility.
## Troubleshooting
- If trades fail due to CAPTCHA issues, check if a recent token file exists and contains valid tokens.
- Run `run_mexc_browser.py` to capture new tokens if necessary.
- Verify that file paths and permissions are correct for reading/writing token files on Windows.
For further assistance or to report issues, refer to the project's main documentation or contact the development team.

View File

@ -0,0 +1,12 @@
[
{
"token": "geetest eyJsb3ROdW1iZXIiOiI4NWFhM2Q3YjJkYmE0Mjk3YTQwODY0YmFhODZiMzA5NyIsImNhcHRjaGFPdXRwdXQiOiJaVkwzS3FWaWxnbEZjQWdXOENIQVgxMUVBLVVPUnE1aURQSldzcmlubDFqelBhRTNiUGlEc0VrVTJUR0xuUzRHV2k0N2JDa1hyREMwSktPWmwxX1dERkQwNWdSN1NkbFJ1Z2NDY0JmTGdLVlNBTEI0OUNrR200enZZcnZ3MUlkdnQ5RThRZURYQ2E0empLczdZMHByS3JEWV9SQW93S0d4OXltS0MxMlY0SHRzNFNYMUV1YnI1ZV9yUXZCcTZJZTZsNFVJMS1DTnc5RUhBaXRXOGU2TVZ6OFFqaGlUMndRM1F3eGxEWkpmZnF6M3VucUl5RTZXUnFSUEx1T0RQQUZkVlB3S3AzcWJTQ3JXcG5CTUFKOXFuXzV2UDlXNm1pR3FaRHZvSTY2cWRzcHlDWUMyWTV1RzJ0ZjZfRHRJaXhTTnhLWUU3cTlfcU1WR2ZJUzlHUXh6ZWg2Mkp2eG02SHZLdjFmXzJMa3FlcVkwRk94S2RxaVpyN2NkNjAxMHE5UlFJVDZLdmNZdU1Hcm04M2d4SnY1bXp4VkZCZWZFWXZfRjZGWFpnWXRMMmhWSDlQME42bHFXQkpCTUVicE1nRm0zbm1iZVBkaDYxeW12T0FUb2wyNlQ0Z2ZET2dFTVFhZTkxQlFNR2FVSFRSa2c3RGJIX2xMYXlBTHQ0TTdyYnpHSCIsInBhc3NUb2tlbiI6IjA0NmFkMGQ5ZjNiZGFmYzJhNDgwYzFiMjcyMmIzZDUzOTk5NTRmYWVlNTM1MTI1ZTQ1MjkzNzJjYWZjOGI5N2EiLCJnZW5UaW1lIjoiMTc1MTQ5ODY4NCJ9",
"url": "https://www.mexc.com/ucgateway/captcha_api/captcha/robot/robot.future.openlong.ETH_USDT.300X",
"timestamp": "2025-07-03T02:24:51.150716"
},
{
"token": "geetest eyJsb3ROdW1iZXIiOiI5ZWVlMDQ2YTg1MmQ0MTU3YTNiYjdhM2M5MzJiNzJiYSIsImNhcHRjaGFPdXRwdXQiOiJaVkwzS3FWaWxnbEZjQWdXOENIQVgxMUVBLVVPUnE1aURQSldzcmlubDFqelBhRTNiUGlEc0VrVTJUR0xuUzRHZk9hVUhKRW1ZOS1FN0h3Q3NNV3hvbVZsNnIwZXRYZzIyWHBGdUVUdDdNS19Ud1J6NnotX2pCXzRkVDJqTnJRN0J3cExjQ25DNGZQUXQ5V040TWxrZ0NMU3p6MERNd09SeHJCZVRkVE5pSU5BdmdFRDZOMkU4a19XRmJ6SFZsYUtieElnM3dLSGVTMG9URU5DLUNaNElnMDJlS2x3UWFZY3liRnhKU2ZrWG1vekZNMDVJSHVDYUpwT0d2WXhhYS1YTWlDeGE0TnZlcVFqN2JwNk04Q09PSnNxNFlfa0pkX0Ruc2w0UW1memZCUTZseF9tenFCMnFweThxd3hKTFVYX0g3TGUyMXZ2bGtubG1KS0RSUEJtTWpUcGFiZ2F4M3Q1YzJmbHJhRjk2elhHQzVBdVVQY1FrbDIyOW0xSmlnMV83cXNfTjdpZFozd0hRcWZFZGxSYVRKQTR2U18yYnFlcGdLblJ3Y3oxaWtOOW1RaWNOSnpSNFNhdm1Pdi1BSzhwSEF0V2lkVjhrTkVYc3dGbUdSazFKQXBEX1hVUjlEdl9sNWJJNEFnbVJhcVlGdjhfRUNvN1g2cmt2UGZuOElTcCIsInBhc3NUb2tlbiI6IjRmZDFhZmU5NzI3MTk0ZGI3MDNlMDg2NWQ0ZDZjZTIyYzMwMzUyNzQ5NzVjMDIwNDFiNTY3Y2Y3MDdhYjM1OTMiLCJnZW5UaW1lIjoiMTc1MTQ5ODY5MiJ9",
"url": "https://www.mexc.com/ucgateway/captcha_api/captcha/robot/robot.future.closelong.ETH_USDT.300X",
"timestamp": "2025-07-03T02:24:57.885947"
}
]

View File

@ -0,0 +1,29 @@
{
"bm_sv": "D92603BBC020E9C2CD11B2EBC8F22050~YAAQJKVf1NW5K7CXAQAAwtMVzRzHARcY60jrPVzy9G79fN3SY4z988SWHHxQlbPpyZHOj76c20AjCnS0QwveqzB08zcRoauoIe/sP3svlaIso9PIdWay0KIIVUe1XsiTJRfTm/DmS+QdrOuJb09rbfWLcEJF4/0QK7VY0UTzPTI2V3CMtxnmYjd1+tjfYsvt1R6O+Mw9mYjb7SjhRmiP/exY2UgZdLTJiqd+iWkc5Wejy5m6g5duOfRGtiA9mfs=~1",
"bm_sz": "98D80FE4B23FE6352AE5194DA699FDDB~YAAQJKVf1GK4K7CXAQAAeQ0UzRw+aXiY5/Ujp+sZm0a4j+XAJFn6fKT4oph8YqIKF6uHSgXkFY3mBt8WWY98Y2w1QzOEFRkje8HTUYQgJsV59y5DIOTZKC6wutPD/bKdVi9ZKtk4CWbHIIRuCrnU1Nw2jqj5E0hsorhKGh8GeVsAeoao8FWovgdYD6u8Qpbr9aL5YZgVEIqJx6WmWLmcIg+wA8UFj8751Fl0B3/AGxY2pACUPjonPKNuX/UDYA5e98plOYUnYLyQMEGIapSrWKo1VXhKBDPLNedJ/Q2gOCGEGlj/u1Fs407QxxXwCvRSegL91y6modtL5JGoFucV1pYc4pgTwEAEdJfcLCEBaButTbaHI9T3SneqgCoGeatMMaqz0GHbvMD7fBQofARBqzN1L6aGlmmAISMzI3wx/SnsfXBl~3228228~3294529",
"_abck": "0288E759712AF333A6EE15F66BC2A662~-1~YAAQJKVf1GC4K7CXAQAAeQ0UzQ77TfyX5SOWTgdW3DVqNFrTLz2fhLo2OC4I6ZHnW9qB0vwTjFDfOB65BwLSeFZoyVypVCGTtY/uL6f4zX0AxEGAU8tLg/jeO0acO4JpGrjYZSW1F56vEd9JbPU2HQPNERorgCDLQMSubMeLCfpqMp3VCW4w0Ssnk6Y4pBSs4mh0PH95v56XXDvat9k20/JPoK3Ip5kK2oKh5Vpk5rtNTVea66P0NBjVUw/EddRUuDDJpc8T4DtTLDXnD5SNDxEq8WDkrYd5kP4dNe0PtKcSOPYs2QLUbvAzfBuMvnhoSBaCjsqD15EZ3eDAoioli/LzsWSxaxetYfm0pA/s5HBXMdOEDi4V0E9b79N28rXcC8IJEHXtfdZdhJjwh1FW14lqF9iuOwER81wDEnIVtgwTwpd3ffrc35aNjb+kGiQ8W0FArFhUI/ZY2NDvPVngRjNrmRm0CsCm+6mdxxVNsGNMPKYG29mcGDi2P9HGDk45iOm0vzoaYUl1PlOh4VGq/V3QGbPYpkBsBtQUjrf/SQJe5IAbjCICTYlgxTo+/FAEjec+QdUsagTgV8YNycQfTK64A2bs1L1n+RO5tapLThU6NkxnUbqHOm6168RnT8ZRoAUpkJ5m3QpqSsuslnPRUPyxUr73v514jTBIUGsq4pUeRpXXd9FAh8Xkn4VZ9Bh3q4jP7eZ9Sv58mgnEVltNBFkeG3zsuIp5Hu69MSBU+8FD4gVlncbBinrTLNWRB8F00Gyvc03unrAznsTEyLiDq9guQf9tQNcGjxfggfnGq/Z1Gy/A7WMjiYw7pwGRVzAYnRgtcZoww9gQ/FdGkbp2Xl+oVZpaqFsHVvafWyOFr4pqQsmd353ddgKLjsEnpy/jcdUsIR/Ph3pYv++XlypXehXj0/GHL+WsosujJrYk4TuEsPKUcyHNr+r844mYUIhCYsI6XVKrq3fimdfdhmlkW8J1kZSTmFwP8QcwGlTK/mZDTJPyf8K5ugXcqOU8oIQzt5B2zfRwRYKHdhb8IUw=~-1~-1~-1",
"RT": "\"z=1&dm=www.mexc.com&si=f5d53b58-7845-4db4-99f1-444e43d35199&ss=mcmh857q&sl=3&tt=90n&bcn=%2F%2F684dd311.akstat.io%2F&ld=1c9o\"",
"mexc_fingerprint_visitorId": "tv1xchuZQbx9N0aBztUG",
"_ga_L6XJCQTK75": "GS2.1.s1751492192$o1$g1$t1751492248$j4$l0$h0",
"uc_token": "WEB66f893ede865e5d927efdea4a82e655ad5190239c247997d744ef9cd075f6f1e",
"u_id": "WEB66f893ede865e5d927efdea4a82e655ad5190239c247997d744ef9cd075f6f1e",
"_fbp": "fb.1.1751492193579.314807866777158389",
"mxc_exchange_layout": "BA",
"sensorsdata2015jssdkcross": "%7B%22distinct_id%22%3A%2221a8728990b84f4fa3ae64c8004b4aaa%22%2C%22first_id%22%3A%22197cd11dc751be-0dd66c04c69e96-26011f51-3686400-197cd11dc76189d%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_referrer%22%3A%22%22%2C%22%24latest_landing_page%22%3A%22https%3A%2F%2Fwww.mexc.com%2Fen-GB%2Flogin%3Fprevious%3D%252Ffutures%252FETH_USDT%253Ftype%253Dlinear_swap%22%7D%2C%22identities%22%3A%22eyIkaWRlbnRpdHlfY29va2llX2lkIjoiMTk3Y2QxMWRjNzUxYmUtMGRkNjZjMDRjNjllOTYtMjYwMTFmNTEtMzY4NjQwMC0xOTdjZDExZGM3NjE4OWQiLCIkaWRlbnRpdHlfbG9naW5faWQiOiIyMWE4NzI4OTkwYjg0ZjRmYTNhZTY0YzgwMDRiNGFhYSJ9%22%2C%22history_login_id%22%3A%7B%22name%22%3A%22%24identity_login_id%22%2C%22value%22%3A%2221a8728990b84f4fa3ae64c8004b4aaa%22%7D%2C%22%24device_id%22%3A%22197cd11dc751be-0dd66c04c69e96-26011f51-3686400-197cd11dc76189d%22%7D",
"mxc_theme_main": "dark",
"mexc_fingerprint_requestId": "1751492199306.WMvKJd",
"_ym_visorc": "b",
"mexc_clearance_modal_show_date": "2025-07-03-undefined",
"ak_bmsc": "35C21AA65F819E0BF9BEBDD10DCF7B70~000000000000000000000000000000~YAAQJKVf1BK2K7CXAQAAPAISzRwQdUOUs1H3HPAdl4COMFQAl+aEPzppLbdgrwA7wXbP/LZpxsYCFflUHDppYKUjzXyTZ9tIojSF3/6CW3OCiPhQo/qhf6XPbC4oQHpCNWaC9GJWEs/CGesQdfeBbhkXdfh+JpgmgCF788+x8IveDE9+9qaL/3QZRy+E7zlKjjvmMxBpahRy+ktY9/KMrCY2etyvtm91KUclr4k8HjkhtNJOlthWgUyiANXJtfbNUMgt+Hqgqa7QzSUfAEpxIXQ1CuROoY9LbU292LRN5TbtBy/uNv6qORT38rKsnpi7TGmyFSB9pj3YsoSzIuAUxYXSh4hXRgAoUQm3Yh5WdLp4ONeyZC1LIb8VCY5xXRy/VbfaHH1w7FodY1HpfHGKSiGHSNwqoiUmMPx13Rgjsgki4mE7bwFmG2H5WAilRIOZA5OkndEqGrOuiNTON7l6+g6mH0MzZ+/+3AjnfF2sXxFuV9itcs9x",
"mxc_theme_upcolor": "upgreen",
"_vid_t": "mQUFl49q1yLZhrL4tvOtFF38e+hGW5QoMS+eXKVD9Q4vQau6icnyipsdyGLW/FBukiO2ItK7EtzPIPMFrE5SbIeLSm1NKc/j+ZmobhX063QAlskf1x1J",
"_ym_isad": "2",
"_ym_d": "1751492196",
"_ym_uid": "1751492196843266888",
"bm_mi": "02862693F007017AEFD6639269A60D08~YAAQJKVf1Am2K7CXAQAAIf4RzRzNGqZ7Q3BC0kAAp/0sCOhHxxvEWTb7mBl8p7LUz0W6RZbw5Etz03Tvqu3H6+sb+yu1o0duU+bDflt7WLVSOfG5cA3im8Jeo6wZhqmxTu6gGXuBgxhrHw/RGCgcknxuZQiRM9cbM6LlZIAYiugFm2xzmO/1QcpjDhs4S8d880rv6TkMedlkYGwdgccAmvbaRVSmX9d5Yukm+hY+5GWuyKMeOjpatAhcgjShjpSDwYSpyQE7vVZLBp7TECIjI9uoWzR8A87YHScKYEuE08tb8YtGdG3O6g70NzasSX0JF3XTCjrVZA==~1",
"_ga": "GA1.1.626437359.1751492192",
"NEXT_LOCALE": "en-GB",
"x-mxc-fingerprint": "tv1xchuZQbx9N0aBztUG",
"CLIENT_LANG": "en-GB",
"sajssdk_2015_cross_new_user": "1"
}

View File

@ -0,0 +1,28 @@
{
"bm_sv": "5C10B638DC36B596422995FAFA8535C5~YAAQJKVf1MfUK7CXAQAA8NktzRwthLouCzg1Sqsm2yBQhAdvw8KbTCYRe0bzUrYEsQEahTebrBcYQoRF3+HyIAggj7MIsbFBANUqLcKJ66lD3QbuA3iU3MhUts/ZhA2dLaSoH5IbgdwiAd98s4bjsb3MSaNwI3nCEzWkLH2CZDyGJK6mhwHlA5VU6OXRLTVz+dfeh2n2fD0SbtcppFL2j9jqopWyKLaxQxYAg+Rs5g3xAo2BTa6/zmQ2YoxZR/w=~1",
"bm_sz": "11FB853E475F9672ADEDFBC783F7487B~YAAQJKVf1G7UK7CXAQAAcY8tzRy3rXBghQVq4e094ZpjhvYRjSatbOxmR/iHhc0aV6NMJkhTwCOnCDsKjeU6sgcdpYgxkpgfhbvTgm5dQ7fEQ5cgmJtfNPmEisDQxZQIOXlI4yhgq7cks4jek9T9pxBx+iLtsZYy5LqIl7mqXc7R7MxMaWvDBfSVU1T0hY9DD0U3P4fxstSIVbGdRzcX2mvGNMcdTj3JMB1y9mXzKB44Prglw0zWa7BZT4imuh5OTQTY4OLNQM7gg5ERUHI7RTcxz+CAltGtBeMHTmWa+Jat/Cw9/DOP7Rud8fESZ7pmhmRE4Fe3Vp2/C+CW3qRnoptViXYOWr/sfKIKSlxIx+QF4Tw58tE5r2XbUVzAF0rQ2mLz9ASi5FnAgJi/DBRULeKhUMVPxsPhMWX5R25J3Gj5QnIED7PjttEt~3294770~3491121",
"_abck": "F5684DE447CDB1B381EABA9AB94E79B7~-1~YAAQJKVf1GzUK7CXAQAAcY8tzQ60GFr2A1gYL72t6F06CTbh+67guEB40t7OXrDJpLYousPo1UKwE9/z804ie8unZxI7iZhwZO/AJfavIw2JHsMnYOhg8S8U/P+hTMOu0KvFYhMfmbSVSHEMInpzJlFPnFHcbYX1GtPn0US/FI8NeDxamlefbV4vHAYxQCWXp1RUVflOukD/ix7BGIvVqNdTQJDMfDY3UmNyu9JC88T8gFDUBxpTJvHNAzafWV7HTpSzLUmYzkFMp0Py39ZVOkVKgEwI9M15xseSNIzVBm6hm6DHwN9Z6ogDuaNsMkY3iJhL9+h75OTq2If9wNMiehwa5XeLHGfSYizXzUFJhuHdcEI1EZAowl2JKq4iGynNIom1/0v3focwlDFi93wxzpCXhCZBKnIRiIYGgS47zjS6kCZpYvuoBRnNvFx7tdJHMMkQQvx6+pk5UzmT4n3jUjS2WUTRoDuwiEvs5NDiO/Z2r4zHlpZnskDdpsDXT2SxvtMo1J451PCPSzt0merJ8vHZD5eLYE0tDBJaLMPzpW9MPHgW/OqrRc5QjcsdhHxNBnMGfhV2U0aHxVsuSuguZRPz7hGDRQJJXepAU8UzDM/d9KSYdMxUvSfcIk+48e3HHyodrKrfXh/0yIaeamsLeYE2na321B0DUoWe28DKbAIY3WdeYfH3WsGJ/LNrM43HeAe8Ng5Bw+5M0rO8m6MqGbaROvdt4JwBheY8g1jMcyXmXJWBAN0in+5F/sXph1sFdPxiiCc2uKQbyuBA34glvFz1JsbPGATEbicRvW0w88JlY3Ki8yNkEYxyFDv3n2C6R3I7Z/ZjdSJLVmS47sWnow1K6YAa31a3A8eVVFItran2v7S2QJBVmS7zb89yVO7oUq16z9a7o+0K5setv8d/jPkPIn9jgWcFOfVh7osl2g0vB/ZTmLoMvES5VxkWZPP3Uo9oIEyIaFzGq7ppYJ24SLj9I6wo9m5Xq9pup33F0Cpn2GyRzoxLpMm7bV/2EJ5eLBjJ3YFQRZxYf2NU1k2CJifFCfSQYOlhu7qCBxNWryWjQQgz9uvGqoKs~-1~-1~-1",
"RT": "\"z=1&dm=www.mexc.com&si=5943fd2a-6403-43d4-87aa-b4ac4403c94f&ss=mcmi7gg2&sl=3&tt=6d5&bcn=%2F%2F02179916.akstat.io%2F&ld=2fhr\"",
"mexc_fingerprint_visitorId": "tv1xchuZQbx9N0aBztUG",
"_ga_L6XJCQTK75": "GS2.1.s1751493837$o1$g1$t1751493945$j59$l0$h0",
"uc_token": "WEB3756d4bd507f4dc9e5c6732b16d40aa668a2e3aea55107801a42f40389c39b9c",
"u_id": "WEB3756d4bd507f4dc9e5c6732b16d40aa668a2e3aea55107801a42f40389c39b9c",
"_fbp": "fb.1.1751493843684.307329583674408195",
"mxc_exchange_layout": "BA",
"sensorsdata2015jssdkcross": "%7B%22distinct_id%22%3A%2221a8728990b84f4fa3ae64c8004b4aaa%22%2C%22first_id%22%3A%22197cd2b02f56f6-08b72b0d8e14ee-26011f51-3686400-197cd2b02f6b59%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%2C%22%24latest_referrer%22%3A%22%22%2C%22%24latest_landing_page%22%3A%22https%3A%2F%2Fwww.mexc.com%2Fen-GB%2Flogin%3Fprevious%3D%252Ffutures%252FETH_USDT%253Ftype%253Dlinear_swap%22%7D%2C%22identities%22%3A%22eyIkaWRlbnRpdHlfY29va2llX2lkIjoiMTk3Y2QyYjAyZjU2ZjYtMDhiNzJiMGQ4ZTE0ZWUtMjYwMTFmNTEtMzY4NjQwMC0xOTdjZDJiMDJmNmI1OSIsIiRpZGVudGl0eV9sb2dpbl9pZCI6IjIxYTg3Mjg5OTBiODRmNGZhM2FlNjRjODAwNGI0YWFhIn0%3D%22%2C%22history_login_id%22%3A%7B%22name%22%3A%22%24identity_login_id%22%2C%22value%22%3A%2221a8728990b84f4fa3ae64c8004b4aaa%22%7D%2C%22%24device_id%22%3A%22197cd2b02f56f6-08b72b0d8e14ee-26011f51-3686400-197cd2b02f6b59%22%7D",
"mxc_theme_main": "dark",
"mexc_fingerprint_requestId": "1751493848491.aXJWxX",
"ak_bmsc": "10B7B90E8C6CA0B2242A59C6BE9D5D09~000000000000000000000000000000~YAAQJKVf1BnQK7CXAQAAJwsrzRyGc8OCIHU9sjkSsoX2E9ZroYaoxZCEToLh8uS5k28z0rzxl4Oi8eXg1oKxdWZslNQCj4/PExgD4O1++Wfi2KNovx4cUehcmbtiR3a28w+gNaiVpWAUPjPnUTaHLAr7cgVU/IOdoOC0cdvxaHThWtwIbVu+YsGazlnHiND1w3u7V0Yc1irC6ZONXqD2rIIZlntEOFiJGPTs8egY3xMLeSpI0tZYp8CASAKzxp/v96ugcPBMehwZ03ue6s6bi8qGYgF1IuOgVTFW9lPVzxCYjvH+ASlmppbLm/vrCUSPjtzJcTz/ySfvtMYaai8cv3CwCf/Ke51plRXJo0wIzGOpBzzJG5/GMA924kx1EQiBTgJptG0i7ZrgrfhqtBjjB2sU0ZBofFqmVu/VXLV6iOCQBHFtpZeI60oFARGoZFP2mYbfxeIKG8ERrQ==",
"mexc_clearance_modal_show_date": "2025-07-03-undefined",
"_ym_isad": "2",
"_vid_t": "hRsGoNygvD+rX1A4eY/XZLO5cGWlpbA3XIXKtYTjDPFdunb5ACYp5eKitX9KQSQj/YXpG2PcnbPZDIpAVQ0AGjaUpR058ahvxYptRHKSGwPghgfLZQ==",
"_ym_visorc": "b",
"_ym_d": "1751493846",
"_ym_uid": "1751493846425437427",
"mxc_theme_upcolor": "upgreen",
"NEXT_LOCALE": "en-GB",
"x-mxc-fingerprint": "tv1xchuZQbx9N0aBztUG",
"CLIENT_LANG": "en-GB",
"_ga": "GA1.1.1034661072.1751493838",
"sajssdk_2015_cross_new_user": "1"
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,64 @@
import os
import logging
import sys
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# Add project root to path
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from NN.exchanges.mexc_interface import MEXCInterface
from core.config import get_config
def test_mexc_private_api():
"""Test MEXC private API endpoints"""
# Load configuration
config = get_config('config.yaml')
mexc_config = config.get('mexc_trading', {})
# Get API credentials
api_key = os.getenv('MEXC_API_KEY', mexc_config.get('api_key', ''))
api_secret = os.getenv('MEXC_SECRET_KEY', mexc_config.get('api_secret', ''))
if not api_key or not api_secret:
logger.error("API key or secret not found. Please set MEXC_API_KEY and MEXC_SECRET_KEY environment variables.")
return
# Initialize MEXC interface in test mode
mexc = MEXCInterface(api_key=api_key, api_secret=api_secret, test_mode=True, trading_mode='simulation')
# Test connection
if not mexc.connect():
logger.error("Failed to connect to MEXC API")
return
# Test getting account information
logger.info("Testing account information retrieval...")
account_info = mexc.get_account_info()
if account_info:
logger.info(f"Account info retrieved: {account_info}")
else:
logger.error("Failed to retrieve account info")
# Test getting balance for a specific asset
asset = "USDT"
logger.info(f"Testing balance retrieval for {asset}...")
balance = mexc.get_balance(asset)
logger.info(f"Balance for {asset}: {balance}")
# Test placing a simulated order (in test mode)
symbol = "ETH/USDT"
side = "buy"
order_type = "market"
quantity = 0.01 # Small quantity for testing
logger.info(f"Testing order placement for {symbol} ({side}, {order_type}, qty: {quantity})...")
order_result = mexc.place_order(symbol=symbol, side=side, order_type=order_type, quantity=quantity)
if order_result:
logger.info(f"Order placed successfully: {order_result}")
else:
logger.error("Failed to place order")
if __name__ == "__main__":
test_mexc_private_api()

View File

@ -0,0 +1,59 @@
import logging
import os
from NN.exchanges.mexc_interface import MEXCInterface
# Set up logging to see debug info
logging.basicConfig(level=logging.INFO)
# Load API credentials from environment variables or a configuration file
# For testing, prioritize environment variables for CI/CD or sensitive data
# Fallback to a placeholder or configuration reading if env vars are not set
api_key = os.getenv('MEXC_API_KEY', '')
api_secret = os.getenv('MEXC_SECRET_KEY', '')
# If using a config file, you might do something like:
# from core.config import get_config
# config = get_config('config.yaml')
# mexc_config = config.get('mexc_trading', {})
# api_key = mexc_config.get('api_key', api_key)
# api_secret = mexc_config.get('api_secret', api_secret)
if not api_key or not api_secret:
logging.error("API keys are not set. Please set MEXC_API_KEY and MEXC_SECRET_KEY environment variables or configure config.yaml")
exit(1)
# Create interface with API credentials
mexc = MEXCInterface(
api_key=api_key,
api_secret=api_secret,
trading_mode='simulation'
)
print('MEXC Interface created successfully')
# Test signature generation
import time
timestamp = int(time.time() * 1000)
test_params = 'quantity=1&price=11&symbol=BTCUSDT&side=BUY&type=LIMIT&timestamp=' + str(timestamp)
signature = mexc._generate_signature(timestamp, test_params)
print(f'Generated signature: {signature}')
# Test account info
print('Testing account info...')
account_info = mexc.get_account_info()
print(f'Account info result: {account_info}')
# Test ticker data
print('Testing ticker data...')
ticker = mexc.get_ticker('ETH/USDT')
print(f'ETH/USDT ticker: {ticker}')
# Test balance retrieval
print('Testing balance retrieval...')
usdt_balance = mexc.get_balance('USDT')
print(f'USDT balance: {usdt_balance}')
# Test a small order placement (simulation mode)
print('Testing order placement in simulation mode...')
order_result = mexc.place_order('ETH/USDT', 'buy', 'market', 0.001)
print(f'Order result: {order_result}')

View File

@ -1,208 +0,0 @@
#!/usr/bin/env python3
"""
Test MEXC Futures Web Client
This script demonstrates how to use the MEXC Futures Web Client
for futures trading that isn't supported by their official API.
IMPORTANT: This requires extracting cookies from your browser session.
"""
import logging
import sys
import os
import time
# Add the project root to path
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
from core.mexc_webclient import MEXCFuturesWebClient
from core.mexc_webclient.session_manager import MEXCSessionManager
# Setup logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
def test_basic_connection():
"""Test basic connection and authentication"""
logger.info("Testing MEXC Futures Web Client")
# Initialize session manager
session_manager = MEXCSessionManager()
# Try to load saved session first
cookies = session_manager.load_session()
if not cookies:
print("\nNo saved session found. You need to extract cookies from your browser.")
session_manager.print_cookie_extraction_guide()
print("\nPaste your cookie header or cURL command (or press Enter to exit):")
user_input = input().strip()
if not user_input:
print("No input provided. Exiting.")
return False
# Extract cookies from user input
if user_input.startswith('curl'):
cookies = session_manager.extract_from_curl_command(user_input)
else:
cookies = session_manager.extract_cookies_from_network_tab(user_input)
if not cookies:
logger.error("Failed to extract cookies from input")
return False
# Validate and save session
if session_manager.validate_session_cookies(cookies):
session_manager.save_session(cookies)
logger.info("Session saved for future use")
else:
logger.warning("Extracted cookies may be incomplete")
# Initialize the web client
client = MEXCFuturesWebClient(cookies)
if not client.is_authenticated:
logger.error("Failed to authenticate with extracted cookies")
return False
logger.info("Successfully authenticated with MEXC")
logger.info(f"User ID: {client.user_id}")
logger.info(f"Auth Token: {client.auth_token[:20]}..." if client.auth_token else "No auth token")
return True
def test_captcha_verification(client: MEXCFuturesWebClient):
"""Test captcha verification system"""
logger.info("Testing captcha verification...")
# Test captcha for ETH_USDT long position with 200x leverage
success = client.verify_captcha('ETH_USDT', 'openlong', '200X')
if success:
logger.info("Captcha verification successful")
else:
logger.warning("Captcha verification failed - this may be normal if no position is being opened")
return success
def test_position_opening(client: MEXCFuturesWebClient, dry_run: bool = True):
"""Test opening a position (dry run by default)"""
if dry_run:
logger.info("DRY RUN: Testing position opening (no actual trade)")
else:
logger.warning("LIVE TRADING: Opening actual position!")
symbol = 'ETH_USDT'
volume = 1 # Small test position
leverage = 200
logger.info(f"Attempting to open long position: {symbol}, Volume: {volume}, Leverage: {leverage}x")
if not dry_run:
result = client.open_long_position(symbol, volume, leverage)
if result['success']:
logger.info(f"Position opened successfully!")
logger.info(f"Order ID: {result['order_id']}")
logger.info(f"Timestamp: {result['timestamp']}")
return True
else:
logger.error(f"Failed to open position: {result['error']}")
return False
else:
logger.info("DRY RUN: Would attempt to open position here")
# Test just the captcha verification part
return client.verify_captcha(symbol, 'openlong', f'{leverage}X')
def interactive_menu(client: MEXCFuturesWebClient):
"""Interactive menu for testing different functions"""
while True:
print("\n" + "="*50)
print("MEXC Futures Web Client Test Menu")
print("="*50)
print("1. Test captcha verification")
print("2. Test position opening (DRY RUN)")
print("3. Test position opening (LIVE - BE CAREFUL!)")
print("4. Test position closing (DRY RUN)")
print("5. Show session info")
print("6. Refresh session")
print("0. Exit")
choice = input("\nEnter choice (0-6): ").strip()
if choice == "1":
test_captcha_verification(client)
elif choice == "2":
test_position_opening(client, dry_run=True)
elif choice == "3":
confirm = input("Are you sure you want to open a LIVE position? (type 'YES' to confirm): ")
if confirm == "YES":
test_position_opening(client, dry_run=False)
else:
print("Cancelled live trading")
elif choice == "4":
logger.info("DRY RUN: Position closing test")
success = client.verify_captcha('ETH_USDT', 'closelong', '200X')
if success:
logger.info("DRY RUN: Would close position here")
else:
logger.warning("Captcha verification failed for position closing")
elif choice == "5":
print(f"\nSession Information:")
print(f"Authenticated: {client.is_authenticated}")
print(f"User ID: {client.user_id}")
print(f"Auth Token: {client.auth_token[:20]}..." if client.auth_token else "None")
print(f"Fingerprint: {client.fingerprint}")
print(f"Visitor ID: {client.visitor_id}")
elif choice == "6":
session_manager = MEXCSessionManager()
session_manager.print_cookie_extraction_guide()
elif choice == "0":
print("Goodbye!")
break
else:
print("Invalid choice. Please try again.")
def main():
"""Main test function"""
print("MEXC Futures Web Client Test")
print("WARNING: This is experimental software for futures trading")
print("Use at your own risk and test with small amounts first!")
# Test basic connection
if not test_basic_connection():
logger.error("Failed to establish connection. Exiting.")
return
# Create client with loaded session
session_manager = MEXCSessionManager()
cookies = session_manager.load_session()
if not cookies:
logger.error("No valid session available")
return
client = MEXCFuturesWebClient(cookies)
if not client.is_authenticated:
logger.error("Authentication failed")
return
# Show interactive menu
interactive_menu(client)
if __name__ == "__main__":
main()

View File

@ -87,7 +87,7 @@ class CheckpointManager:
performance_score = self._calculate_performance_score(performance_metrics)
if not force_save and not self._should_save_checkpoint(model_name, performance_score):
logger.info(f"Skipping checkpoint save for {model_name} - performance not improved")
logger.debug(f"Skipping checkpoint save for {model_name} - performance not improved")
return None
success = self._save_model_file(model, checkpoint_path, model_type)
@ -140,10 +140,11 @@ class CheckpointManager:
best_checkpoint = max(self.checkpoints[model_name], key=lambda x: x.performance_score)
if not Path(best_checkpoint.file_path).exists():
logger.error(f"Best checkpoint file not found: {best_checkpoint.file_path}")
# temporary disable logging to avoid spam
# logger.error(f"Best checkpoint file not found: {best_checkpoint.file_path}")
return None
logger.info(f"Loading best checkpoint for {model_name}: {best_checkpoint.checkpoint_id}")
logger.debug(f"Loading best checkpoint for {model_name}: {best_checkpoint.checkpoint_id}")
return best_checkpoint.file_path, best_checkpoint
except Exception as e:

View File

@ -5474,7 +5474,7 @@ class CleanTradingDashboard:
if training_samples > 0:
avg_loss_info = f", avg_loss={total_loss/loss_count:.6f}" if loss_count > 0 else ""
performance_score = 100 / (1 + (total_loss/loss_count)) if loss_count > 0 else 0.1
logger.info(f"DECISION TRAINING: Processed {training_samples} decision fusion samples{avg_loss_info}, perf_score={performance_score:.4f}")
logger.debug(f"DECISION TRAINING: Processed {training_samples} decision fusion samples{avg_loss_info}, perf_score={performance_score:.4f}")
except Exception as e:
logger.error(f"Error in real decision fusion training: {e}")