Merge with develop

This commit is contained in:
Anton
2018-06-23 16:50:27 +03:00
36 changed files with 1336 additions and 987 deletions

View File

@@ -3,33 +3,20 @@
import logging
from copy import deepcopy
from random import randint
from datetime import datetime
from unittest.mock import MagicMock, PropertyMock
import ccxt
import pytest
import freqtrade.exchange as exchange
from freqtrade import OperationalException, DependencyException, TemporaryError
from freqtrade.exchange import (init, validate_pairs, buy, sell, get_balance, get_balances,
get_ticker, get_ticker_history, cancel_order, get_name, get_fee,
get_id, get_pair_detail_url, get_amount_lots)
from freqtrade.tests.conftest import log_has
API_INIT = False
def maybe_init_api(conf, mocker, force=False):
global API_INIT
if force or not API_INIT:
mocker.patch('freqtrade.exchange.validate_pairs',
side_effect=lambda s: True)
init(config=conf)
API_INIT = True
from freqtrade.exchange import Exchange, API_RETRY_COUNT
from freqtrade.tests.conftest import log_has, get_patched_exchange
def test_init(default_conf, mocker, caplog):
caplog.set_level(logging.INFO)
maybe_init_api(default_conf, mocker, True)
get_patched_exchange(mocker, default_conf)
assert log_has('Instance is running with dry_run enabled', caplog.record_tuples)
@@ -39,7 +26,7 @@ def test_init_exception(default_conf):
with pytest.raises(
OperationalException,
match='Exchange {} is not supported'.format(default_conf['exchange']['name'])):
init(config=default_conf)
Exchange(default_conf)
def test_validate_pairs(default_conf, mocker):
@@ -50,18 +37,17 @@ def test_validate_pairs(default_conf, mocker):
id_mock = PropertyMock(return_value='test_exchange')
type(api_mock).id = id_mock
mocker.patch('freqtrade.exchange._API', api_mock)
mocker.patch.dict('freqtrade.exchange._CONF', default_conf)
validate_pairs(default_conf['exchange']['pair_whitelist'])
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
Exchange(default_conf)
def test_validate_pairs_not_available(default_conf, mocker):
api_mock = MagicMock()
api_mock.load_markets = MagicMock(return_value={})
mocker.patch('freqtrade.exchange._API', api_mock)
mocker.patch.dict('freqtrade.exchange._CONF', default_conf)
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
with pytest.raises(OperationalException, match=r'not available'):
validate_pairs(default_conf['exchange']['pair_whitelist'])
Exchange(default_conf)
def test_validate_pairs_not_compatible(default_conf, mocker):
@@ -71,25 +57,27 @@ def test_validate_pairs_not_compatible(default_conf, mocker):
})
conf = deepcopy(default_conf)
conf['stake_currency'] = 'ETH'
mocker.patch('freqtrade.exchange._API', api_mock)
mocker.patch.dict('freqtrade.exchange._CONF', conf)
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
with pytest.raises(OperationalException, match=r'not compatible'):
validate_pairs(conf['exchange']['pair_whitelist'])
Exchange(conf)
def test_validate_pairs_exception(default_conf, mocker, caplog):
caplog.set_level(logging.INFO)
api_mock = MagicMock()
api_mock.name = 'Binance'
mocker.patch('freqtrade.exchange._API', api_mock)
mocker.patch.dict('freqtrade.exchange._CONF', default_conf)
mocker.patch('freqtrade.exchange.Exchange.name', PropertyMock(return_value='Binance'))
api_mock.load_markets = MagicMock(return_value={})
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', api_mock)
with pytest.raises(OperationalException, match=r'Pair ETH/BTC is not available at Binance'):
validate_pairs(default_conf['exchange']['pair_whitelist'])
Exchange(default_conf)
api_mock.load_markets = MagicMock(side_effect=ccxt.BaseError())
validate_pairs(default_conf['exchange']['pair_whitelist'])
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
Exchange(default_conf)
assert log_has('Unable to validate pairs (assuming they are correct). Reason: ',
caplog.record_tuples)
@@ -99,22 +87,21 @@ def test_validate_pairs_stake_exception(default_conf, mocker, caplog):
conf = deepcopy(default_conf)
conf['stake_currency'] = 'ETH'
api_mock = MagicMock()
api_mock.name = 'binance'
mocker.patch('freqtrade.exchange._API', api_mock)
mocker.patch.dict('freqtrade.exchange._CONF', conf)
api_mock.name = MagicMock(return_value='binance')
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', api_mock)
with pytest.raises(
OperationalException,
match=r'Pair ETH/BTC not compatible with stake_currency: ETH'
):
validate_pairs(default_conf['exchange']['pair_whitelist'])
Exchange(conf)
def test_buy_dry_run(default_conf, mocker):
default_conf['dry_run'] = True
mocker.patch.dict('freqtrade.exchange._CONF', default_conf)
exchange = get_patched_exchange(mocker, default_conf)
order = buy(pair='ETH/BTC', rate=200, amount=1)
order = exchange.buy(pair='ETH/BTC', rate=200, amount=1)
assert 'id' in order
assert 'dry_run_buy_' in order['id']
@@ -128,12 +115,10 @@ def test_buy_prod(default_conf, mocker):
'foo': 'bar'
}
})
mocker.patch('freqtrade.exchange._API', api_mock)
default_conf['dry_run'] = False
mocker.patch.dict('freqtrade.exchange._CONF', default_conf)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
order = buy(pair='ETH/BTC', rate=200, amount=1)
order = exchange.buy(pair='ETH/BTC', rate=200, amount=1)
assert 'id' in order
assert 'info' in order
assert order['id'] == order_id
@@ -141,30 +126,30 @@ def test_buy_prod(default_conf, mocker):
# test exception handling
with pytest.raises(DependencyException):
api_mock.create_limit_buy_order = MagicMock(side_effect=ccxt.InsufficientFunds)
mocker.patch('freqtrade.exchange._API', api_mock)
buy(pair='ETH/BTC', rate=200, amount=1)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.buy(pair='ETH/BTC', rate=200, amount=1)
with pytest.raises(DependencyException):
api_mock.create_limit_buy_order = MagicMock(side_effect=ccxt.InvalidOrder)
mocker.patch('freqtrade.exchange._API', api_mock)
buy(pair='ETH/BTC', rate=200, amount=1)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.buy(pair='ETH/BTC', rate=200, amount=1)
with pytest.raises(TemporaryError):
api_mock.create_limit_buy_order = MagicMock(side_effect=ccxt.NetworkError)
mocker.patch('freqtrade.exchange._API', api_mock)
buy(pair='ETH/BTC', rate=200, amount=1)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.buy(pair='ETH/BTC', rate=200, amount=1)
with pytest.raises(OperationalException):
api_mock.create_limit_buy_order = MagicMock(side_effect=ccxt.BaseError)
mocker.patch('freqtrade.exchange._API', api_mock)
buy(pair='ETH/BTC', rate=200, amount=1)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.buy(pair='ETH/BTC', rate=200, amount=1)
def test_sell_dry_run(default_conf, mocker):
default_conf['dry_run'] = True
mocker.patch.dict('freqtrade.exchange._CONF', default_conf)
exchange = get_patched_exchange(mocker, default_conf)
order = sell(pair='ETH/BTC', rate=200, amount=1)
order = exchange.sell(pair='ETH/BTC', rate=200, amount=1)
assert 'id' in order
assert 'dry_run_sell_' in order['id']
@@ -178,12 +163,11 @@ def test_sell_prod(default_conf, mocker):
'foo': 'bar'
}
})
mocker.patch('freqtrade.exchange._API', api_mock)
default_conf['dry_run'] = False
mocker.patch.dict('freqtrade.exchange._CONF', default_conf)
order = sell(pair='ETH/BTC', rate=200, amount=1)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
order = exchange.sell(pair='ETH/BTC', rate=200, amount=1)
assert 'id' in order
assert 'info' in order
assert order['id'] == order_id
@@ -191,53 +175,52 @@ def test_sell_prod(default_conf, mocker):
# test exception handling
with pytest.raises(DependencyException):
api_mock.create_limit_sell_order = MagicMock(side_effect=ccxt.InsufficientFunds)
mocker.patch('freqtrade.exchange._API', api_mock)
sell(pair='ETH/BTC', rate=200, amount=1)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.sell(pair='ETH/BTC', rate=200, amount=1)
with pytest.raises(DependencyException):
api_mock.create_limit_sell_order = MagicMock(side_effect=ccxt.InvalidOrder)
mocker.patch('freqtrade.exchange._API', api_mock)
sell(pair='ETH/BTC', rate=200, amount=1)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.sell(pair='ETH/BTC', rate=200, amount=1)
with pytest.raises(TemporaryError):
api_mock.create_limit_sell_order = MagicMock(side_effect=ccxt.NetworkError)
mocker.patch('freqtrade.exchange._API', api_mock)
sell(pair='ETH/BTC', rate=200, amount=1)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.sell(pair='ETH/BTC', rate=200, amount=1)
with pytest.raises(OperationalException):
api_mock.create_limit_sell_order = MagicMock(side_effect=ccxt.BaseError)
mocker.patch('freqtrade.exchange._API', api_mock)
sell(pair='ETH/BTC', rate=200, amount=1)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.sell(pair='ETH/BTC', rate=200, amount=1)
def test_get_balance_dry_run(default_conf, mocker):
default_conf['dry_run'] = True
mocker.patch.dict('freqtrade.exchange._CONF', default_conf)
assert get_balance(currency='BTC') == 999.9
exchange = get_patched_exchange(mocker, default_conf)
assert exchange.get_balance(currency='BTC') == 999.9
def test_get_balance_prod(default_conf, mocker):
api_mock = MagicMock()
api_mock.fetch_balance = MagicMock(return_value={'BTC': {'free': 123.4}})
mocker.patch('freqtrade.exchange._API', api_mock)
default_conf['dry_run'] = False
mocker.patch.dict('freqtrade.exchange._CONF', default_conf)
assert get_balance(currency='BTC') == 123.4
exchange = get_patched_exchange(mocker, default_conf, api_mock)
assert exchange.get_balance(currency='BTC') == 123.4
with pytest.raises(OperationalException):
api_mock.fetch_balance = MagicMock(side_effect=ccxt.BaseError)
mocker.patch('freqtrade.exchange._API', api_mock)
get_balance(currency='BTC')
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.get_balance(currency='BTC')
def test_get_balances_dry_run(default_conf, mocker):
default_conf['dry_run'] = True
mocker.patch.dict('freqtrade.exchange._CONF', default_conf)
assert get_balances() == {}
exchange = get_patched_exchange(mocker, default_conf)
assert exchange.get_balances() == {}
def test_get_balances_prod(default_conf, mocker):
@@ -253,33 +236,73 @@ def test_get_balances_prod(default_conf, mocker):
'2ST': balance_item,
'3ST': balance_item
})
mocker.patch('freqtrade.exchange._API', api_mock)
default_conf['dry_run'] = False
mocker.patch.dict('freqtrade.exchange._CONF', default_conf)
assert len(get_balances()) == 3
assert get_balances()['1ST']['free'] == 10.0
assert get_balances()['1ST']['total'] == 10.0
assert get_balances()['1ST']['used'] == 0.0
exchange = get_patched_exchange(mocker, default_conf, api_mock)
assert len(exchange.get_balances()) == 3
assert exchange.get_balances()['1ST']['free'] == 10.0
assert exchange.get_balances()['1ST']['total'] == 10.0
assert exchange.get_balances()['1ST']['used'] == 0.0
with pytest.raises(TemporaryError):
api_mock.fetch_balance = MagicMock(side_effect=ccxt.NetworkError)
mocker.patch('freqtrade.exchange._API', api_mock)
get_balances()
assert api_mock.fetch_balance.call_count == exchange.API_RETRY_COUNT + 1
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.get_balances()
assert api_mock.fetch_balance.call_count == API_RETRY_COUNT + 1
with pytest.raises(OperationalException):
api_mock.fetch_balance = MagicMock(side_effect=ccxt.BaseError)
mocker.patch('freqtrade.exchange._API', api_mock)
get_balances()
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.get_balances()
assert api_mock.fetch_balance.call_count == 1
# This test is somewhat redundant with
# test_exchange_bittrex.py::test_exchange_bittrex_get_ticker
def test_get_tickers(default_conf, mocker):
api_mock = MagicMock()
tick = {'ETH/BTC': {
'symbol': 'ETH/BTC',
'bid': 0.5,
'ask': 1,
'last': 42,
}, 'BCH/BTC': {
'symbol': 'BCH/BTC',
'bid': 0.6,
'ask': 0.5,
'last': 41,
}
}
api_mock.fetch_tickers = MagicMock(return_value=tick)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
# retrieve original ticker
tickers = exchange.get_tickers()
assert 'ETH/BTC' in tickers
assert 'BCH/BTC' in tickers
assert tickers['ETH/BTC']['bid'] == 0.5
assert tickers['ETH/BTC']['ask'] == 1
assert tickers['BCH/BTC']['bid'] == 0.6
assert tickers['BCH/BTC']['ask'] == 0.5
with pytest.raises(TemporaryError): # test retrier
api_mock.fetch_tickers = MagicMock(side_effect=ccxt.NetworkError)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.get_tickers()
with pytest.raises(OperationalException):
api_mock.fetch_tickers = MagicMock(side_effect=ccxt.BaseError)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.get_tickers()
with pytest.raises(OperationalException):
api_mock.fetch_tickers = MagicMock(side_effect=ccxt.NotSupported)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.get_tickers()
api_mock.fetch_tickers = MagicMock(return_value={})
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.get_tickers()
def test_get_ticker(default_conf, mocker):
maybe_init_api(default_conf, mocker)
api_mock = MagicMock()
tick = {
'symbol': 'ETH/BTC',
@@ -288,10 +311,9 @@ def test_get_ticker(default_conf, mocker):
'last': 0.0001,
}
api_mock.fetch_ticker = MagicMock(return_value=tick)
mocker.patch('freqtrade.exchange._API', api_mock)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
# retrieve original ticker
ticker = get_ticker(pair='ETH/BTC')
ticker = exchange.get_ticker(pair='ETH/BTC')
assert ticker['bid'] == 0.00001098
assert ticker['ask'] == 0.00001099
@@ -304,38 +326,38 @@ def test_get_ticker(default_conf, mocker):
'last': 42,
}
api_mock.fetch_ticker = MagicMock(return_value=tick)
mocker.patch('freqtrade.exchange._API', api_mock)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
# if not caching the result we should get the same ticker
# if not fetching a new result we should get the cached ticker
ticker = get_ticker(pair='ETH/BTC')
ticker = exchange.get_ticker(pair='ETH/BTC')
assert api_mock.fetch_ticker.call_count == 1
assert ticker['bid'] == 0.5
assert ticker['ask'] == 1
assert 'ETH/BTC' in exchange._CACHED_TICKER
assert exchange._CACHED_TICKER['ETH/BTC']['bid'] == 0.5
assert exchange._CACHED_TICKER['ETH/BTC']['ask'] == 1
assert 'ETH/BTC' in exchange._cached_ticker
assert exchange._cached_ticker['ETH/BTC']['bid'] == 0.5
assert exchange._cached_ticker['ETH/BTC']['ask'] == 1
# Test caching
api_mock.fetch_ticker = MagicMock()
get_ticker(pair='ETH/BTC', refresh=False)
exchange.get_ticker(pair='ETH/BTC', refresh=False)
assert api_mock.fetch_ticker.call_count == 0
with pytest.raises(TemporaryError): # test retrier
api_mock.fetch_ticker = MagicMock(side_effect=ccxt.NetworkError)
mocker.patch('freqtrade.exchange._API', api_mock)
get_ticker(pair='ETH/BTC', refresh=True)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.get_ticker(pair='ETH/BTC', refresh=True)
with pytest.raises(OperationalException):
api_mock.fetch_ticker = MagicMock(side_effect=ccxt.BaseError)
mocker.patch('freqtrade.exchange._API', api_mock)
get_ticker(pair='ETH/BTC', refresh=True)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.get_ticker(pair='ETH/BTC', refresh=True)
api_mock.fetch_ticker = MagicMock(return_value={})
mocker.patch('freqtrade.exchange._API', api_mock)
get_ticker(pair='ETH/BTC', refresh=True)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.get_ticker(pair='ETH/BTC', refresh=True)
def make_fetch_ohlcv_mock(data):
@@ -361,10 +383,10 @@ def test_get_ticker_history(default_conf, mocker):
]
type(api_mock).has = PropertyMock(return_value={'fetchOHLCV': True})
api_mock.fetch_ohlcv = MagicMock(side_effect=make_fetch_ohlcv_mock(tick))
mocker.patch('freqtrade.exchange._API', api_mock)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
# retrieve original ticker
ticks = get_ticker_history('ETH/BTC', default_conf['ticker_interval'])
ticks = exchange.get_ticker_history('ETH/BTC', default_conf['ticker_interval'])
assert ticks[0][0] == 1511686200000
assert ticks[0][1] == 1
assert ticks[0][2] == 2
@@ -384,9 +406,9 @@ def test_get_ticker_history(default_conf, mocker):
]
]
api_mock.fetch_ohlcv = MagicMock(side_effect=make_fetch_ohlcv_mock(new_tick))
mocker.patch('freqtrade.exchange._API', api_mock)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
ticks = get_ticker_history('ETH/BTC', default_conf['ticker_interval'])
ticks = exchange.get_ticker_history('ETH/BTC', default_conf['ticker_interval'])
assert ticks[0][0] == 1511686210000
assert ticks[0][1] == 6
assert ticks[0][2] == 7
@@ -396,15 +418,15 @@ def test_get_ticker_history(default_conf, mocker):
with pytest.raises(TemporaryError): # test retrier
api_mock.fetch_ohlcv = MagicMock(side_effect=ccxt.NetworkError)
mocker.patch('freqtrade.exchange._API', api_mock)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
# new symbol to get around cache
get_ticker_history('ABCD/BTC', default_conf['ticker_interval'])
exchange.get_ticker_history('ABCD/BTC', default_conf['ticker_interval'])
with pytest.raises(OperationalException):
api_mock.fetch_ohlcv = MagicMock(side_effect=ccxt.BaseError)
mocker.patch('freqtrade.exchange._API', api_mock)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
# new symbol to get around cache
get_ticker_history('EFGH/BTC', default_conf['ticker_interval'])
exchange.get_ticker_history('EFGH/BTC', default_conf['ticker_interval'])
def test_get_ticker_history_sort(default_conf, mocker):
@@ -426,10 +448,11 @@ def test_get_ticker_history_sort(default_conf, mocker):
]
type(api_mock).has = PropertyMock(return_value={'fetchOHLCV': True})
api_mock.fetch_ohlcv = MagicMock(side_effect=make_fetch_ohlcv_mock(tick))
mocker.patch('freqtrade.exchange._API', api_mock)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
# Test the ticker history sort
ticks = get_ticker_history('ETH/BTC', default_conf['ticker_interval'])
ticks = exchange.get_ticker_history('ETH/BTC', default_conf['ticker_interval'])
assert ticks[0][0] == 1527830400000
assert ticks[0][1] == 0.07649
assert ticks[0][2] == 0.07651
@@ -460,10 +483,9 @@ def test_get_ticker_history_sort(default_conf, mocker):
]
type(api_mock).has = PropertyMock(return_value={'fetchOHLCV': True})
api_mock.fetch_ohlcv = MagicMock(side_effect=make_fetch_ohlcv_mock(tick))
mocker.patch('freqtrade.exchange._API', api_mock)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
# Test the ticker history sort
ticks = get_ticker_history('ETH/BTC', default_conf['ticker_interval'])
ticks = exchange.get_ticker_history('ETH/BTC', default_conf['ticker_interval'])
assert ticks[0][0] == 1527827700000
assert ticks[0][1] == 0.07659999
assert ticks[0][2] == 0.0766
@@ -481,117 +503,194 @@ def test_get_ticker_history_sort(default_conf, mocker):
def test_cancel_order_dry_run(default_conf, mocker):
default_conf['dry_run'] = True
mocker.patch.dict('freqtrade.exchange._CONF', default_conf)
assert cancel_order(order_id='123', pair='TKN/BTC') is None
exchange = get_patched_exchange(mocker, default_conf)
assert exchange.cancel_order(order_id='123', pair='TKN/BTC') is None
# Ensure that if not dry_run, we should call API
def test_cancel_order(default_conf, mocker):
default_conf['dry_run'] = False
mocker.patch.dict('freqtrade.exchange._CONF', default_conf)
api_mock = MagicMock()
api_mock.cancel_order = MagicMock(return_value=123)
mocker.patch('freqtrade.exchange._API', api_mock)
assert cancel_order(order_id='_', pair='TKN/BTC') == 123
exchange = get_patched_exchange(mocker, default_conf, api_mock)
assert exchange.cancel_order(order_id='_', pair='TKN/BTC') == 123
with pytest.raises(TemporaryError):
api_mock.cancel_order = MagicMock(side_effect=ccxt.NetworkError)
mocker.patch('freqtrade.exchange._API', api_mock)
cancel_order(order_id='_', pair='TKN/BTC')
assert api_mock.cancel_order.call_count == exchange.API_RETRY_COUNT + 1
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.cancel_order(order_id='_', pair='TKN/BTC')
assert api_mock.cancel_order.call_count == API_RETRY_COUNT + 1
with pytest.raises(DependencyException):
api_mock.cancel_order = MagicMock(side_effect=ccxt.InvalidOrder)
mocker.patch('freqtrade.exchange._API', api_mock)
cancel_order(order_id='_', pair='TKN/BTC')
assert api_mock.cancel_order.call_count == exchange.API_RETRY_COUNT + 1
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.cancel_order(order_id='_', pair='TKN/BTC')
assert api_mock.cancel_order.call_count == API_RETRY_COUNT + 1
with pytest.raises(OperationalException):
api_mock.cancel_order = MagicMock(side_effect=ccxt.BaseError)
mocker.patch('freqtrade.exchange._API', api_mock)
cancel_order(order_id='_', pair='TKN/BTC')
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.cancel_order(order_id='_', pair='TKN/BTC')
assert api_mock.cancel_order.call_count == 1
def test_get_order(default_conf, mocker):
default_conf['dry_run'] = True
mocker.patch.dict('freqtrade.exchange._CONF', default_conf)
order = MagicMock()
order.myid = 123
exchange._DRY_RUN_OPEN_ORDERS['X'] = order
exchange = get_patched_exchange(mocker, default_conf)
exchange._dry_run_open_orders['X'] = order
print(exchange.get_order('X', 'TKN/BTC'))
assert exchange.get_order('X', 'TKN/BTC').myid == 123
default_conf['dry_run'] = False
mocker.patch.dict('freqtrade.exchange._CONF', default_conf)
api_mock = MagicMock()
api_mock.fetch_order = MagicMock(return_value=456)
mocker.patch('freqtrade.exchange._API', api_mock)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
assert exchange.get_order('X', 'TKN/BTC') == 456
with pytest.raises(TemporaryError):
api_mock.fetch_order = MagicMock(side_effect=ccxt.NetworkError)
mocker.patch('freqtrade.exchange._API', api_mock)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.get_order(order_id='_', pair='TKN/BTC')
assert api_mock.fetch_order.call_count == exchange.API_RETRY_COUNT + 1
assert api_mock.fetch_order.call_count == API_RETRY_COUNT + 1
with pytest.raises(DependencyException):
api_mock.fetch_order = MagicMock(side_effect=ccxt.InvalidOrder)
mocker.patch('freqtrade.exchange._API', api_mock)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.get_order(order_id='_', pair='TKN/BTC')
assert api_mock.fetch_order.call_count == exchange.API_RETRY_COUNT + 1
assert api_mock.fetch_order.call_count == API_RETRY_COUNT + 1
with pytest.raises(OperationalException):
api_mock.fetch_order = MagicMock(side_effect=ccxt.BaseError)
mocker.patch('freqtrade.exchange._API', api_mock)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.get_order(order_id='_', pair='TKN/BTC')
assert api_mock.fetch_order.call_count == 1
def test_get_name(default_conf, mocker):
mocker.patch('freqtrade.exchange.validate_pairs',
def test_name(default_conf, mocker):
mocker.patch('freqtrade.exchange.Exchange.validate_pairs',
side_effect=lambda s: True)
default_conf['exchange']['name'] = 'binance'
init(default_conf)
exchange = Exchange(default_conf)
assert get_name() == 'Binance'
assert exchange.name == 'Binance'
def test_get_id(default_conf, mocker):
mocker.patch('freqtrade.exchange.validate_pairs',
def test_id(default_conf, mocker):
mocker.patch('freqtrade.exchange.Exchange.validate_pairs',
side_effect=lambda s: True)
default_conf['exchange']['name'] = 'binance'
init(default_conf)
assert get_id() == 'binance'
exchange = Exchange(default_conf)
assert exchange.id == 'binance'
def test_get_pair_detail_url(default_conf, mocker):
mocker.patch('freqtrade.exchange.validate_pairs',
def test_get_pair_detail_url(default_conf, mocker, caplog):
mocker.patch('freqtrade.exchange.Exchange.validate_pairs',
side_effect=lambda s: True)
default_conf['exchange']['name'] = 'binance'
init(default_conf)
exchange = Exchange(default_conf)
url = get_pair_detail_url('TKN/ETH')
url = exchange.get_pair_detail_url('TKN/ETH')
assert 'TKN' in url
assert 'ETH' in url
url = get_pair_detail_url('LOOONG/BTC')
url = exchange.get_pair_detail_url('LOOONG/BTC')
assert 'LOOONG' in url
assert 'BTC' in url
default_conf['exchange']['name'] = 'bittrex'
init(default_conf)
exchange = Exchange(default_conf)
url = get_pair_detail_url('TKN/ETH')
url = exchange.get_pair_detail_url('TKN/ETH')
assert 'TKN' in url
assert 'ETH' in url
url = get_pair_detail_url('LOOONG/BTC')
url = exchange.get_pair_detail_url('LOOONG/BTC')
assert 'LOOONG' in url
assert 'BTC' in url
default_conf['exchange']['name'] = 'poloniex'
exchange = Exchange(default_conf)
url = exchange.get_pair_detail_url('LOOONG/BTC')
assert '' == url
assert log_has('Could not get exchange url for Poloniex', caplog.record_tuples)
def test_get_trades_for_order(default_conf, mocker):
order_id = 'ABCD-ABCD'
since = datetime(2018, 5, 5)
default_conf["dry_run"] = False
mocker.patch('freqtrade.exchange.Exchange.exchange_has', return_value=True)
api_mock = MagicMock()
api_mock.fetch_my_trades = MagicMock(return_value=[{'id': 'TTR67E-3PFBD-76IISV',
'order': 'ABCD-ABCD',
'info': {'pair': 'XLTCZBTC',
'time': 1519860024.4388,
'type': 'buy',
'ordertype': 'limit',
'price': '20.00000',
'cost': '38.62000',
'fee': '0.06179',
'vol': '5',
'id': 'ABCD-ABCD'},
'timestamp': 1519860024438,
'datetime': '2018-02-28T23:20:24.438Z',
'symbol': 'LTC/BTC',
'type': 'limit',
'side': 'buy',
'price': 165.0,
'amount': 0.2340606,
'fee': {'cost': 0.06179, 'currency': 'BTC'}
}])
exchange = get_patched_exchange(mocker, default_conf, api_mock)
orders = exchange.get_trades_for_order(order_id, 'LTC/BTC', since)
assert len(orders) == 1
assert orders[0]['price'] == 165
# test Exceptions
with pytest.raises(OperationalException):
api_mock = MagicMock()
api_mock.fetch_my_trades = MagicMock(side_effect=ccxt.BaseError)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.get_trades_for_order(order_id, 'LTC/BTC', since)
with pytest.raises(TemporaryError):
api_mock = MagicMock()
api_mock.fetch_my_trades = MagicMock(side_effect=ccxt.NetworkError)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.get_trades_for_order(order_id, 'LTC/BTC', since)
assert api_mock.fetch_my_trades.call_count == API_RETRY_COUNT + 1
def test_get_markets(default_conf, mocker, markets):
api_mock = MagicMock()
api_mock.fetch_markets = markets
exchange = get_patched_exchange(mocker, default_conf, api_mock)
ret = exchange.get_markets()
assert isinstance(ret, list)
assert len(ret) == 6
assert ret[0]["id"] == "ethbtc"
assert ret[0]["symbol"] == "ETH/BTC"
# test Exceptions
with pytest.raises(OperationalException):
api_mock = MagicMock()
api_mock.fetch_markets = MagicMock(side_effect=ccxt.BaseError)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.get_markets()
with pytest.raises(TemporaryError):
api_mock = MagicMock()
api_mock.fetch_markets = MagicMock(side_effect=ccxt.NetworkError)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.get_markets()
assert api_mock.fetch_markets.call_count == API_RETRY_COUNT + 1
def test_get_fee(default_conf, mocker):
api_mock = MagicMock()
@@ -601,12 +700,32 @@ def test_get_fee(default_conf, mocker):
'rate': 0.025,
'cost': 0.05
})
mocker.patch('freqtrade.exchange._API', api_mock)
assert get_fee() == 0.025
exchange = get_patched_exchange(mocker, default_conf, api_mock)
assert exchange.get_fee() == 0.025
# test Exceptions
with pytest.raises(OperationalException):
api_mock = MagicMock()
api_mock.calculate_fee = MagicMock(side_effect=ccxt.BaseError)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.get_fee()
with pytest.raises(TemporaryError):
api_mock = MagicMock()
api_mock.calculate_fee = MagicMock(side_effect=ccxt.NetworkError)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
exchange.get_fee()
assert api_mock.calculate_fee.call_count == API_RETRY_COUNT + 1
def test_get_amount_lots(default_conf, mocker):
api_mock = MagicMock()
api_mock.amount_to_lots = MagicMock(return_value=1.0)
mocker.patch('freqtrade.exchange._API', api_mock)
assert get_amount_lots('LTC/BTC', 1.54) == 1
api_mock.markets = None
marketmock = MagicMock()
api_mock.load_markets = marketmock
exchange = get_patched_exchange(mocker, default_conf, api_mock)
assert exchange.get_amount_lots('LTC/BTC', 1.54) == 1
assert marketmock.call_count == 1