enhancements
This commit is contained in:
162
NN/exchanges/README.md
Normal file
162
NN/exchanges/README.md
Normal 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
|
@ -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]:
|
||||
|
254
NN/exchanges/trading_agent_test.py
Normal file
254
NN/exchanges/trading_agent_test.py
Normal 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())
|
Reference in New Issue
Block a user