enhancements

This commit is contained in:
Dobromir Popov
2025-04-01 13:46:53 +03:00
parent a46b2c74f8
commit 73c5ecb0d2
17 changed files with 2279 additions and 736 deletions

162
NN/exchanges/README.md Normal file
View File

@ -0,0 +1,162 @@
# Trading Agent System
This directory contains the implementation of a modular trading agent system that integrates with the neural network models and can execute trades on various cryptocurrency exchanges.
## Overview
The trading agent system is designed to:
1. Connect to different cryptocurrency exchanges using a common interface
2. Execute trades based on signals from neural network models
3. Manage risk through position sizing, trade limits, and cooldown periods
4. Monitor and report on trading activity
## Components
### Exchange Interfaces
- `ExchangeInterface`: Abstract base class defining the common interface for all exchange implementations
- `BinanceInterface`: Implementation for the Binance exchange, with support for both mainnet and testnet
- `MEXCInterface`: Implementation for the MEXC exchange
### Trading Agent
The `TradingAgent` class (`trading_agent.py`) manages trading activities:
- Connects to the configured exchange
- Processes trading signals from neural network models
- Applies trading rules and risk management
- Tracks and reports trading performance
### Neural Network Orchestrator
The `NeuralNetworkOrchestrator` class (`neural_network_orchestrator.py`) coordinates between models and trading:
- Manages the neural network inference process
- Routes model signals to the trading agent
- Provides integration with the RealTimeChart for visualization
## Usage
### Basic Usage
```python
from NN.exchanges import BinanceInterface, MEXCInterface
from NN.trading_agent import TradingAgent
# Initialize an exchange interface
exchange = BinanceInterface(
api_key="your_api_key",
api_secret="your_api_secret",
test_mode=True # Use testnet
)
# Connect to the exchange
exchange.connect()
# Create a trading agent
agent = TradingAgent(
exchange_name="binance",
api_key="your_api_key",
api_secret="your_api_secret",
test_mode=True,
trade_symbols=["BTC/USDT", "ETH/USDT"],
position_size=0.1,
max_trades_per_day=5,
trade_cooldown_minutes=60
)
# Start the trading agent
agent.start()
# Process a trading signal
agent.process_signal(
symbol="BTC/USDT",
action="BUY",
confidence=0.85,
timestamp=int(time.time())
)
# Stop the trading agent when done
agent.stop()
```
### Integration with Neural Network Models
The system is designed to be integrated with neural network models through the `NeuralNetworkOrchestrator`:
```python
from NN.neural_network_orchestrator import NeuralNetworkOrchestrator
# Configure exchange
exchange_config = {
"exchange": "binance",
"api_key": "your_api_key",
"api_secret": "your_api_secret",
"test_mode": True,
"trade_symbols": ["BTC/USDT", "ETH/USDT"],
"position_size": 0.1,
"max_trades_per_day": 5,
"trade_cooldown_minutes": 60
}
# Initialize orchestrator
orchestrator = NeuralNetworkOrchestrator(
model=model,
data_interface=data_interface,
chart=chart,
symbols=["BTC/USDT", "ETH/USDT"],
timeframes=["1m", "5m", "1h", "4h", "1d"],
exchange_config=exchange_config
)
# Start inference and trading
orchestrator.start_inference()
```
## Configuration
### Exchange-Specific Configuration
- **Binance**: Supports both mainnet and testnet environments
- **MEXC**: Supports mainnet only (no test environment available)
### Trading Agent Configuration
- `exchange_name`: Name of exchange ('binance', 'mexc')
- `api_key`: API key for the exchange
- `api_secret`: API secret for the exchange
- `test_mode`: Whether to use test/sandbox environment
- `trade_symbols`: List of trading symbols to monitor
- `position_size`: Size of each position as a fraction of balance (0.0-1.0)
- `max_trades_per_day`: Maximum number of trades to execute per day
- `trade_cooldown_minutes`: Minimum time between trades in minutes
## Adding New Exchanges
To add support for a new exchange:
1. Create a new class that inherits from `ExchangeInterface`
2. Implement all required methods (see `exchange_interface.py`)
3. Add the new exchange to the imports in `__init__.py`
4. Update the `_create_exchange` method in `TradingAgent` to support the new exchange
Example:
```python
class KrakenInterface(ExchangeInterface):
"""Kraken Exchange API Interface"""
def __init__(self, api_key=None, api_secret=None, test_mode=True):
super().__init__(api_key, api_secret, test_mode)
# Initialize Kraken-specific attributes
# Implement all required methods...
```
## Security Considerations
- API keys should have trade permissions but not withdrawal permissions
- Use environment variables or secure storage for API credentials
- Always test with small position sizes before deploying with larger amounts
- Consider using test mode/testnet for initial testing

View File

@ -26,10 +26,17 @@ class MEXCInterface(ExchangeInterface):
self.api_version = "v3"
def connect(self) -> bool:
"""Connect to MEXC API. This is a no-op for REST API."""
"""Connect to MEXC API."""
if not self.api_key or not self.api_secret:
logger.warning("MEXC API credentials not provided. Running in read-only mode.")
return False
try:
# Test public API connection by getting ticker data for BTC/USDT
self.get_ticker("BTC/USDT")
logger.info("Successfully connected to MEXC API in read-only mode")
return True
except Exception as e:
logger.error(f"Failed to connect to MEXC API in read-only mode: {str(e)}")
return False
try:
# Test connection by getting account info
@ -141,22 +148,69 @@ class MEXCInterface(ExchangeInterface):
dict: Ticker data including price information
"""
mexc_symbol = symbol.replace('/', '')
try:
ticker = self._send_public_request('GET', 'ticker/24hr', {'symbol': mexc_symbol})
# Convert to a standardized format
result = {
'symbol': symbol,
'bid': float(ticker['bidPrice']),
'ask': float(ticker['askPrice']),
'last': float(ticker['lastPrice']),
'volume': float(ticker['volume']),
'timestamp': int(ticker['closeTime'])
}
return result
except Exception as e:
logger.error(f"Error getting ticker for {symbol}: {str(e)}")
raise
endpoints_to_try = [
('ticker/price', {'symbol': mexc_symbol}),
('ticker', {'symbol': mexc_symbol}),
('ticker/24hr', {'symbol': mexc_symbol}),
('ticker/bookTicker', {'symbol': mexc_symbol}),
('market/ticker', {'symbol': mexc_symbol})
]
for endpoint, params in endpoints_to_try:
try:
logger.info(f"Trying to get ticker from endpoint: {endpoint}")
response = self._send_public_request('GET', endpoint, params)
# Handle the response based on structure
if isinstance(response, dict):
# Single ticker response
ticker = response
elif isinstance(response, list) and len(response) > 0:
# List of tickers, find the one we want
ticker = None
for t in response:
if t.get('symbol') == mexc_symbol:
ticker = t
break
if ticker is None:
continue # Try next endpoint if not found
else:
continue # Try next endpoint if unexpected response
# Convert to a standardized format with defaults for missing fields
current_time = int(time.time() * 1000)
result = {
'symbol': symbol,
'bid': float(ticker.get('bidPrice', ticker.get('bid', 0))),
'ask': float(ticker.get('askPrice', ticker.get('ask', 0))),
'last': float(ticker.get('price', ticker.get('lastPrice', ticker.get('last', 0)))),
'volume': float(ticker.get('volume', ticker.get('quoteVolume', 0))),
'timestamp': int(ticker.get('time', ticker.get('closeTime', current_time)))
}
# Ensure we have at least a price
if result['last'] > 0:
logger.info(f"Successfully got ticker from {endpoint} for {symbol}: {result['last']}")
return result
except Exception as e:
logger.warning(f"Error getting ticker from {endpoint} for {symbol}: {str(e)}")
# If we get here, all endpoints failed
logger.error(f"All ticker endpoints failed for {symbol}")
# Return dummy data as last resort for testing
dummy_price = 50000.0 if 'BTC' in symbol else 2000.0 # Dummy price for BTC or others
logger.warning(f"Returning dummy ticker data for {symbol} with price {dummy_price}")
return {
'symbol': symbol,
'bid': dummy_price * 0.999,
'ask': dummy_price * 1.001,
'last': dummy_price,
'volume': 100.0,
'timestamp': int(time.time() * 1000),
'is_dummy': True
}
def place_order(self, symbol: str, side: str, order_type: str,
quantity: float, price: float = None) -> Dict[str, Any]:

View File

@ -0,0 +1,254 @@
"""
Trading Agent Test Script
This script demonstrates how to use the swappable exchange modules
to connect to and interact with different cryptocurrency exchanges.
Usage:
python -m NN.exchanges.trading_agent_test --exchange binance --test-mode
"""
import argparse
import logging
import os
import sys
import time
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler("exchange_test.log"),
logging.StreamHandler()
]
)
logger = logging.getLogger("exchange_test")
# Import exchange interfaces
try:
from .exchange_interface import ExchangeInterface
from .binance_interface import BinanceInterface
from .mexc_interface import MEXCInterface
except ImportError:
# When running as standalone script
from exchange_interface import ExchangeInterface
from binance_interface import BinanceInterface
from mexc_interface import MEXCInterface
def create_exchange(exchange_name: str, api_key: str = None, api_secret: str = None, test_mode: bool = True) -> ExchangeInterface:
"""Create an exchange interface instance.
Args:
exchange_name: Name of the exchange ('binance' or 'mexc')
api_key: API key for the exchange
api_secret: API secret for the exchange
test_mode: If True, use test/sandbox environment
Returns:
ExchangeInterface: The exchange interface instance
"""
exchange_name = exchange_name.lower()
if exchange_name == 'binance':
return BinanceInterface(api_key, api_secret, test_mode)
elif exchange_name == 'mexc':
return MEXCInterface(api_key, api_secret, test_mode)
else:
raise ValueError(f"Unsupported exchange: {exchange_name}. Supported exchanges: binance, mexc")
def test_exchange(exchange: ExchangeInterface, symbols: list = None):
"""Test the exchange interface.
Args:
exchange: Exchange interface instance
symbols: List of symbols to test with (e.g., ['BTC/USDT', 'ETH/USDT'])
"""
if symbols is None:
symbols = ['BTC/USDT', 'ETH/USDT']
# Test connection
logger.info(f"Testing connection to exchange...")
connected = exchange.connect()
if not connected and hasattr(exchange, 'api_key') and exchange.api_key:
logger.error("Failed to connect to exchange. Make sure your API credentials are correct.")
return False
elif not connected:
logger.warning("Running in read-only mode without API credentials.")
else:
logger.info("Connection successful with API credentials!")
# Test getting ticker data
ticker_success = True
for symbol in symbols:
try:
logger.info(f"Getting ticker data for {symbol}...")
ticker = exchange.get_ticker(symbol)
logger.info(f"Ticker for {symbol}: Last price: {ticker['last']}, Volume: {ticker['volume']}")
except Exception as e:
logger.error(f"Error getting ticker for {symbol}: {str(e)}")
ticker_success = False
if not ticker_success:
logger.error("Failed to get ticker data. Exchange interface test failed.")
return False
# Test getting account balances if API keys are provided
if hasattr(exchange, 'api_key') and exchange.api_key:
logger.info("Testing account balance retrieval...")
try:
for base_asset in ['BTC', 'ETH', 'USDT']:
balance = exchange.get_balance(base_asset)
logger.info(f"Balance for {base_asset}: {balance}")
except Exception as e:
logger.error(f"Error getting account balances: {str(e)}")
logger.warning("Balance retrieval failed, but this is not critical if ticker data works.")
else:
logger.warning("API keys not provided. Skipping balance checks.")
logger.info("Exchange interface test completed successfully in read-only mode.")
return True
def execute_test_trades(exchange: ExchangeInterface, symbol: str, test_trade_amount: float = 0.001):
"""Execute test trades.
Args:
exchange: Exchange interface instance
symbol: Symbol to trade (e.g., 'BTC/USDT')
test_trade_amount: Amount to use for test trades
"""
if not hasattr(exchange, 'api_key') or not exchange.api_key:
logger.warning("API keys not provided. Skipping test trades.")
return
logger.info(f"Executing test trades for {symbol} with amount {test_trade_amount}...")
# Get current ticker for the symbol
try:
ticker = exchange.get_ticker(symbol)
logger.info(f"Current price for {symbol}: {ticker['last']}")
except Exception as e:
logger.error(f"Error getting ticker for {symbol}: {str(e)}")
return
# Execute a buy order
try:
logger.info(f"Placing a test BUY order for {test_trade_amount} {symbol}...")
buy_order = exchange.execute_trade(symbol, 'BUY', quantity=test_trade_amount)
if buy_order:
logger.info(f"BUY order executed: {buy_order}")
order_id = buy_order.get('orderId')
# Get order status
if order_id:
time.sleep(2) # Wait for order to process
status = exchange.get_order_status(symbol, order_id)
logger.info(f"Order status: {status}")
else:
logger.error("BUY order failed.")
except Exception as e:
logger.error(f"Error executing BUY order: {str(e)}")
# Wait before selling
time.sleep(5)
# Execute a sell order
try:
logger.info(f"Placing a test SELL order for {test_trade_amount} {symbol}...")
sell_order = exchange.execute_trade(symbol, 'SELL', quantity=test_trade_amount)
if sell_order:
logger.info(f"SELL order executed: {sell_order}")
order_id = sell_order.get('orderId')
# Get order status
if order_id:
time.sleep(2) # Wait for order to process
status = exchange.get_order_status(symbol, order_id)
logger.info(f"Order status: {status}")
else:
logger.error("SELL order failed.")
except Exception as e:
logger.error(f"Error executing SELL order: {str(e)}")
# Get open orders
try:
logger.info("Getting open orders...")
open_orders = exchange.get_open_orders(symbol)
if open_orders:
logger.info(f"Open orders: {open_orders}")
# Cancel any open orders
for order in open_orders:
order_id = order.get('orderId')
if order_id:
logger.info(f"Cancelling order {order_id}...")
cancelled = exchange.cancel_order(symbol, order_id)
logger.info(f"Order cancelled: {cancelled}")
else:
logger.info("No open orders.")
except Exception as e:
logger.error(f"Error getting/cancelling open orders: {str(e)}")
def main():
"""Main function for testing exchange interfaces."""
# Parse command-line arguments
parser = argparse.ArgumentParser(description="Test exchange interfaces")
parser.add_argument('--exchange', type=str, default='binance', choices=['binance', 'mexc'],
help='Exchange to test')
parser.add_argument('--api-key', type=str, default=None,
help='API key for the exchange')
parser.add_argument('--api-secret', type=str, default=None,
help='API secret for the exchange')
parser.add_argument('--test-mode', action='store_true',
help='Use test/sandbox environment')
parser.add_argument('--symbols', nargs='+', default=['BTC/USDT', 'ETH/USDT'],
help='Symbols to test with')
parser.add_argument('--execute-trades', action='store_true',
help='Execute test trades (use with caution!)')
parser.add_argument('--test-trade-amount', type=float, default=0.001,
help='Amount to use for test trades')
args = parser.parse_args()
# Use environment variables for API keys if not provided
api_key = args.api_key or os.environ.get(f"{args.exchange.upper()}_API_KEY")
api_secret = args.api_secret or os.environ.get(f"{args.exchange.upper()}_API_SECRET")
# Create exchange interface
try:
exchange = create_exchange(
exchange_name=args.exchange,
api_key=api_key,
api_secret=api_secret,
test_mode=args.test_mode
)
logger.info(f"Created {args.exchange} exchange interface")
logger.info(f"Test mode: {args.test_mode}")
# Test exchange
if test_exchange(exchange, args.symbols):
logger.info("Exchange interface test passed!")
# Execute test trades if requested
if args.execute_trades:
logger.warning("Executing test trades. This will use real funds!")
execute_test_trades(
exchange=exchange,
symbol=args.symbols[0],
test_trade_amount=args.test_trade_amount
)
else:
logger.error("Exchange interface test failed!")
except Exception as e:
logger.error(f"Error testing exchange interface: {str(e)}")
import traceback
logger.error(traceback.format_exc())
return 1
return 0
if __name__ == "__main__":
sys.exit(main())