197 lines
7.2 KiB
Python
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()
|