brighter-trading/tests/test_Exchange.py

197 lines
7.2 KiB
Python

import unittest
from unittest.mock import MagicMock, patch
import ccxt
from datetime import datetime
import pandas as pd
from Exchange import Exchange
class TestExchange(unittest.TestCase):
@patch('ccxt.binance')
def setUp(self, mock_exchange):
self.mock_client = MagicMock()
mock_exchange.return_value = self.mock_client
self.api_keys = {'key': 'test_key', 'secret': 'test_secret'}
self.mock_client.fetch_markets.return_value = [
{'symbol': 'BTC/USDT', 'active': True},
{'symbol': 'ETH/USDT', 'active': True},
]
self.mock_client.load_markets.return_value = {
'BTC/USDT': {
'limits': {
'amount': {'min': 0.001},
'cost': {'min': 10.0} # Ensure the cost limit is included
},
'precision': {
'amount': 8,
'price': 8
},
'active': True,
'symbol': 'BTC/USDT'
},
'ETH/USDT': {
'limits': {
'amount': {'min': 0.01},
'cost': {'min': 20.0} # Ensure the cost limit is included
},
'precision': {
'amount': 8,
'price': 8
},
'active': True,
'symbol': 'ETH/USDT'
}
}
self.mock_client.fetch_ticker.return_value = {'last': 30000.0}
self.mock_client.fetch_ohlcv.return_value = [
[1609459200000, 29000.0, 29500.0, 28800.0, 29400.0, 1000]
]
self.mock_client.fetch_balance.return_value = {
'total': {'BTC': 1.0, 'USDT': 1000.0}
}
self.mock_client.create_order.return_value = {
'id': 'test_order_id',
'symbol': 'BTC/USDT',
'type': 'limit',
'side': 'buy',
'price': 30000.0,
'amount': 1.0,
'status': 'open'
}
self.mock_client.fetch_open_orders.return_value = [
{'id': 'test_order_id', 'clientOrderId': None, 'symbol': 'BTC/USDT',
'side': 'buy', 'type': 'limit', 'amount': 1.0, 'price': 30000.0,
'status': 'open', 'filled': 0, 'remaining': 1.0, 'timestamp': None}
]
self.mock_client.fetch_positions.return_value = [
{'symbol': 'BTC/USDT', 'quantity': 1.0, 'entry_price': 29000.0}
]
self.mock_client.fetch_order.return_value = {
'id': 'test_order_id',
'symbol': 'BTC/USDT',
'side': 'buy',
'amount': 1.0,
'price': 30000.0,
'status': 'open'
}
self.mock_client.timeframes = {
'1m': '1m',
'5m': '5m',
'1h': '1h',
'1d': '1d',
}
self.exchange = Exchange(name='Binance', api_keys=self.api_keys, exchange_id='binance')
def test_connect_exchange(self):
self.assertIsInstance(self.exchange.client, MagicMock)
self.mock_client.load_markets.assert_called_once()
self.assertEqual(self.exchange.symbols, ['BTC/USDT', 'ETH/USDT'])
self.assertIn('BTC/USDT', self.exchange.exchange_info)
self.assertIn('ETH/USDT', self.exchange.exchange_info)
self.assertEqual(self.exchange.balances, [
{'asset': 'BTC', 'balance': 1.0, 'pnl': 0},
{'asset': 'USDT', 'balance': 1000.0, 'pnl': 0}
])
def test_get_symbols(self):
symbols = self.exchange.get_symbols()
self.assertEqual(symbols, ['BTC/USDT', 'ETH/USDT'])
def test_get_price(self):
price = self.exchange.get_price('BTC/USDT')
self.assertEqual(price, 30000.0)
self.mock_client.fetch_ticker.assert_called_with('BTC/USDT')
def test_get_balances(self):
balances = self.exchange.get_balances()
self.assertEqual(balances, [
{'asset': 'BTC', 'balance': 1.0, 'pnl': 0},
{'asset': 'USDT', 'balance': 1000.0, 'pnl': 0}
])
self.mock_client.fetch_balance.assert_called_once()
def test_get_min_qty(self):
min_qty = self.exchange.get_min_qty('BTC/USDT')
self.assertEqual(min_qty, 0.001)
def test_get_min_notional_qty(self):
min_notional_qty = self.exchange.get_min_notional_qty('BTC/USDT')
self.assertEqual(min_notional_qty, 10.0)
def test_get_order(self):
order = self.exchange.get_order('BTC/USDT', 'test_order_id')
self.assertIsInstance(order, dict)
self.assertEqual(order['id'], 'test_order_id')
self.mock_client.fetch_order.assert_called_with('test_order_id', 'BTC/USDT')
def test_place_order(self):
result, order = self.exchange.place_order(
symbol='BTC/USDT',
side='buy',
type='limit',
timeInForce='GTC',
quantity=1.0,
price=30000.0
)
self.assertEqual(result, 'Success')
self.assertIsInstance(order, dict)
self.assertEqual(order.get('id'), 'test_order_id')
self.mock_client.create_order.assert_called_once()
def test_get_open_orders(self):
open_orders = self.exchange.get_open_orders()
# Check that orders are returned and contain expected fields
self.assertEqual(len(open_orders), 1)
order = open_orders[0]
self.assertEqual(order['id'], 'test_order_id')
self.assertEqual(order['symbol'], 'BTC/USDT')
self.assertEqual(order['side'], 'buy')
self.assertEqual(order['quantity'], 1.0)
self.assertEqual(order['price'], 30000.0)
self.mock_client.fetch_open_orders.assert_called()
def test_get_active_trades(self):
active_trades = self.exchange.get_active_trades()
self.assertEqual(active_trades, [
{'symbol': 'BTC/USDT', 'side': 'buy', 'quantity': 1.0, 'price': 29000.0}
])
self.mock_client.fetch_positions.assert_called_once()
@patch('ccxt.binance')
def test_fetch_ticker_invalid_response(self, mock_exchange):
self.mock_client.fetch_ticker.side_effect = ccxt.ExchangeError('Invalid response')
price = self.exchange.get_price('BTC/USDT')
self.assertEqual(price, 0.0)
self.mock_client.fetch_ticker.assert_called_with('BTC/USDT')
@patch('ccxt.kucoin')
def test_connect_exchange_uses_password_for_passphrase(self, mock_kucoin):
mock_client = MagicMock()
mock_kucoin.return_value = mock_client
mock_client.fetch_open_orders.return_value = []
mock_client.load_markets.return_value = {}
mock_client.fetch_markets.return_value = []
mock_client.fetch_balance.return_value = {'total': {}}
mock_client.timeframes = {}
api_keys = {
'key': 'kucoin_key',
'secret': 'kucoin_secret',
'passphrase': 'kucoin_passphrase'
}
Exchange(name='KuCoin', api_keys=api_keys, exchange_id='kucoin')
self.assertTrue(mock_kucoin.called)
config = mock_kucoin.call_args.args[0]
self.assertEqual(config.get('apiKey'), 'kucoin_key')
self.assertEqual(config.get('secret'), 'kucoin_secret')
self.assertEqual(config.get('password'), 'kucoin_passphrase')
if __name__ == '__main__':
unittest.main()