Merge pull request #2973 from freqtrade/support_non_pairs

Support non pairs
This commit is contained in:
hroff-1902
2020-02-26 12:20:45 +03:00
committed by GitHub
14 changed files with 150 additions and 67 deletions

View File

@@ -217,8 +217,9 @@ def test_list_markets(mocker, markets, capsys):
]
start_list_markets(get_args(args), False)
captured = capsys.readouterr()
assert ("Exchange Bittrex has 9 active markets: "
"BLK/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/USD, NEO/BTC, TKN/BTC, XLTCUSDT, XRP/BTC.\n"
assert ("Exchange Bittrex has 10 active markets: "
"BLK/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/ETH, LTC/USD, NEO/BTC, "
"TKN/BTC, XLTCUSDT, XRP/BTC.\n"
in captured.out)
patch_exchange(mocker, api_mock=api_mock, id="binance")
@@ -231,7 +232,7 @@ def test_list_markets(mocker, markets, capsys):
pargs['config'] = None
start_list_markets(pargs, False)
captured = capsys.readouterr()
assert re.match("\nExchange Binance has 9 active markets:\n",
assert re.match("\nExchange Binance has 10 active markets:\n",
captured.out)
patch_exchange(mocker, api_mock=api_mock, id="bittrex")
@@ -243,8 +244,8 @@ def test_list_markets(mocker, markets, capsys):
]
start_list_markets(get_args(args), False)
captured = capsys.readouterr()
assert ("Exchange Bittrex has 11 markets: "
"BLK/BTC, BTT/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/USD, LTC/USDT, NEO/BTC, "
assert ("Exchange Bittrex has 12 markets: "
"BLK/BTC, BTT/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/ETH, LTC/USD, LTC/USDT, NEO/BTC, "
"TKN/BTC, XLTCUSDT, XRP/BTC.\n"
in captured.out)
@@ -256,8 +257,8 @@ def test_list_markets(mocker, markets, capsys):
]
start_list_markets(get_args(args), True)
captured = capsys.readouterr()
assert ("Exchange Bittrex has 8 active pairs: "
"BLK/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/USD, NEO/BTC, TKN/BTC, XRP/BTC.\n"
assert ("Exchange Bittrex has 9 active pairs: "
"BLK/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/ETH, LTC/USD, NEO/BTC, TKN/BTC, XRP/BTC.\n"
in captured.out)
# Test list-pairs subcommand with --all: all pairs
@@ -268,8 +269,8 @@ def test_list_markets(mocker, markets, capsys):
]
start_list_markets(get_args(args), True)
captured = capsys.readouterr()
assert ("Exchange Bittrex has 10 pairs: "
"BLK/BTC, BTT/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/USD, LTC/USDT, NEO/BTC, "
assert ("Exchange Bittrex has 11 pairs: "
"BLK/BTC, BTT/BTC, ETH/BTC, ETH/USDT, LTC/BTC, LTC/ETH, LTC/USD, LTC/USDT, NEO/BTC, "
"TKN/BTC, XRP/BTC.\n"
in captured.out)
@@ -282,8 +283,8 @@ def test_list_markets(mocker, markets, capsys):
]
start_list_markets(get_args(args), False)
captured = capsys.readouterr()
assert ("Exchange Bittrex has 5 active markets with ETH, LTC as base currencies: "
"ETH/BTC, ETH/USDT, LTC/BTC, LTC/USD, XLTCUSDT.\n"
assert ("Exchange Bittrex has 6 active markets with ETH, LTC as base currencies: "
"ETH/BTC, ETH/USDT, LTC/BTC, LTC/ETH, LTC/USD, XLTCUSDT.\n"
in captured.out)
# active markets, base=LTC
@@ -295,8 +296,8 @@ def test_list_markets(mocker, markets, capsys):
]
start_list_markets(get_args(args), False)
captured = capsys.readouterr()
assert ("Exchange Bittrex has 3 active markets with LTC as base currency: "
"LTC/BTC, LTC/USD, XLTCUSDT.\n"
assert ("Exchange Bittrex has 4 active markets with LTC as base currency: "
"LTC/BTC, LTC/ETH, LTC/USD, XLTCUSDT.\n"
in captured.out)
# active markets, quote=USDT, USD
@@ -384,7 +385,7 @@ def test_list_markets(mocker, markets, capsys):
]
start_list_markets(get_args(args), False)
captured = capsys.readouterr()
assert ("Exchange Bittrex has 9 active markets:\n"
assert ("Exchange Bittrex has 10 active markets:\n"
in captured.out)
# Test tabular output, no markets found
@@ -407,7 +408,7 @@ def test_list_markets(mocker, markets, capsys):
]
start_list_markets(get_args(args), False)
captured = capsys.readouterr()
assert ('["BLK/BTC","ETH/BTC","ETH/USDT","LTC/BTC","LTC/USD","NEO/BTC",'
assert ('["BLK/BTC","ETH/BTC","ETH/USDT","LTC/BTC","LTC/ETH","LTC/USD","NEO/BTC",'
'"TKN/BTC","XLTCUSDT","XRP/BTC"]'
in captured.out)

View File

@@ -575,7 +575,34 @@ def get_markets():
}
},
'info': {},
}
},
'LTC/ETH': {
'id': 'LTCETH',
'symbol': 'LTC/ETH',
'base': 'LTC',
'quote': 'ETH',
'active': True,
'precision': {
'base': 8,
'quote': 8,
'amount': 3,
'price': 5
},
'limits': {
'amount': {
'min': 0.001,
'max': 10000000.0
},
'price': {
'min': 1e-05,
'max': 1000.0
},
'cost': {
'min': 0.01,
'max': None
}
},
},
}

View File

@@ -400,13 +400,40 @@ def test_validate_stake_currency_error(default_conf, mocker, caplog):
def test_get_quote_currencies(default_conf, mocker):
ex = get_patched_exchange(mocker, default_conf)
assert set(ex.get_quote_currencies()) == set(['USD', 'BTC', 'USDT'])
assert set(ex.get_quote_currencies()) == set(['USD', 'ETH', 'BTC', 'USDT'])
@pytest.mark.parametrize('pair,expected', [
('XRP/BTC', 'BTC'),
('LTC/USD', 'USD'),
('ETH/USDT', 'USDT'),
('XLTCUSDT', 'USDT'),
('XRP/NOCURRENCY', ''),
])
def test_get_pair_quote_currency(default_conf, mocker, pair, expected):
ex = get_patched_exchange(mocker, default_conf)
assert ex.get_pair_quote_currency(pair) == expected
@pytest.mark.parametrize('pair,expected', [
('XRP/BTC', 'XRP'),
('LTC/USD', 'LTC'),
('ETH/USDT', 'ETH'),
('XLTCUSDT', 'LTC'),
('XRP/NOCURRENCY', ''),
])
def test_get_pair_base_currency(default_conf, mocker, pair, expected):
ex = get_patched_exchange(mocker, default_conf)
assert ex.get_pair_base_currency(pair) == expected
def test_validate_pairs(default_conf, mocker): # test exchange.validate_pairs directly
api_mock = MagicMock()
type(api_mock).markets = PropertyMock(return_value={
'ETH/BTC': {}, 'LTC/BTC': {}, 'XRP/BTC': {}, 'NEO/BTC': {}
'ETH/BTC': {'quote': 'BTC'},
'LTC/BTC': {'quote': 'BTC'},
'XRP/BTC': {'quote': 'BTC'},
'NEO/BTC': {'quote': 'BTC'},
})
id_mock = PropertyMock(return_value='test_exchange')
type(api_mock).id = id_mock
@@ -454,9 +481,9 @@ def test_validate_pairs_exception(default_conf, mocker, caplog):
def test_validate_pairs_restricted(default_conf, mocker, caplog):
api_mock = MagicMock()
type(api_mock).markets = PropertyMock(return_value={
'ETH/BTC': {}, 'LTC/BTC': {},
'XRP/BTC': {'info': {'IsRestricted': True}},
'NEO/BTC': {'info': 'TestString'}, # info can also be a string ...
'ETH/BTC': {'quote': 'BTC'}, 'LTC/BTC': {'quote': 'BTC'},
'XRP/BTC': {'quote': 'BTC', 'info': {'IsRestricted': True}},
'NEO/BTC': {'quote': 'BTC', 'info': 'TestString'}, # info can also be a string ...
})
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
@@ -469,6 +496,38 @@ def test_validate_pairs_restricted(default_conf, mocker, caplog):
f"on the exchange and eventually remove XRP/BTC from your whitelist.", caplog)
def test_validate_pairs_stakecompatibility(default_conf, mocker, caplog):
api_mock = MagicMock()
type(api_mock).markets = PropertyMock(return_value={
'ETH/BTC': {'quote': 'BTC'}, 'LTC/BTC': {'quote': 'BTC'},
'XRP/BTC': {'quote': 'BTC'}, 'NEO/BTC': {'quote': 'BTC'},
'HELLO-WORLD': {'quote': 'BTC'},
})
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
mocker.patch('freqtrade.exchange.Exchange._load_async_markets')
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
Exchange(default_conf)
def test_validate_pairs_stakecompatibility_fail(default_conf, mocker, caplog):
default_conf['exchange']['pair_whitelist'].append('HELLO-WORLD')
api_mock = MagicMock()
type(api_mock).markets = PropertyMock(return_value={
'ETH/BTC': {'quote': 'BTC'}, 'LTC/BTC': {'quote': 'BTC'},
'XRP/BTC': {'quote': 'BTC'}, 'NEO/BTC': {'quote': 'BTC'},
'HELLO-WORLD': {'quote': 'USDT'},
})
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes')
mocker.patch('freqtrade.exchange.Exchange._load_async_markets')
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
with pytest.raises(OperationalException, match=r"Stake-currency 'BTC' not compatible with.*"):
Exchange(default_conf)
@pytest.mark.parametrize("timeframe", [
('5m'), ("1m"), ("15m"), ("1h")
])
@@ -1819,6 +1878,7 @@ def test_get_valid_pair_combination(default_conf, mocker, markets):
# 'ETH/BTC': 'active': True
# 'ETH/USDT': 'active': True
# 'LTC/BTC': 'active': False
# 'LTC/ETH': 'active': True
# 'LTC/USD': 'active': True
# 'LTC/USDT': 'active': True
# 'NEO/BTC': 'active': False
@@ -1827,26 +1887,26 @@ def test_get_valid_pair_combination(default_conf, mocker, markets):
# 'XRP/BTC': 'active': False
# all markets
([], [], False, False,
['BLK/BTC', 'BTT/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/USD',
['BLK/BTC', 'BTT/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/ETH', 'LTC/USD',
'LTC/USDT', 'NEO/BTC', 'TKN/BTC', 'XLTCUSDT', 'XRP/BTC']),
# active markets
([], [], False, True,
['BLK/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/USD', 'NEO/BTC',
['BLK/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/ETH', 'LTC/USD', 'NEO/BTC',
'TKN/BTC', 'XLTCUSDT', 'XRP/BTC']),
# all pairs
([], [], True, False,
['BLK/BTC', 'BTT/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/USD',
['BLK/BTC', 'BTT/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/ETH', 'LTC/USD',
'LTC/USDT', 'NEO/BTC', 'TKN/BTC', 'XRP/BTC']),
# active pairs
([], [], True, True,
['BLK/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/USD', 'NEO/BTC',
['BLK/BTC', 'ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/ETH', 'LTC/USD', 'NEO/BTC',
'TKN/BTC', 'XRP/BTC']),
# all markets, base=ETH, LTC
(['ETH', 'LTC'], [], False, False,
['ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/USD', 'LTC/USDT', 'XLTCUSDT']),
['ETH/BTC', 'ETH/USDT', 'LTC/BTC', 'LTC/ETH', 'LTC/USD', 'LTC/USDT', 'XLTCUSDT']),
# all markets, base=LTC
(['LTC'], [], False, False,
['LTC/BTC', 'LTC/USD', 'LTC/USDT', 'XLTCUSDT']),
['LTC/BTC', 'LTC/ETH', 'LTC/USD', 'LTC/USDT', 'XLTCUSDT']),
# all markets, quote=USDT
([], ['USDT'], False, False,
['ETH/USDT', 'LTC/USDT', 'XLTCUSDT']),

View File

@@ -681,7 +681,7 @@ def test_rpcforcebuy(mocker, default_conf, ticker, fee, limit_buy_order) -> None
# Test buy pair not with stakes
with pytest.raises(RPCException, match=r'Wrong pair selected. Please pairs with stake.*'):
rpc._rpc_forcebuy('XRP/ETH', 0.0001)
rpc._rpc_forcebuy('LTC/ETH', 0.0001)
pair = 'XRP/BTC'
# Test not buying

View File

@@ -34,13 +34,6 @@ def all_conf():
return conf
def test_load_config_invalid_pair(default_conf) -> None:
default_conf['exchange']['pair_whitelist'].append('ETH-BTC')
with pytest.raises(ValidationError, match=r'.*does not match.*'):
validate_config_schema(default_conf)
def test_load_config_missing_attributes(default_conf) -> None:
conf = deepcopy(default_conf)
conf.pop('exchange')
@@ -810,12 +803,6 @@ def test_validate_whitelist(default_conf):
validate_config_consistency(conf)
conf = deepcopy(default_conf)
conf['stake_currency'] = 'USDT'
with pytest.raises(OperationalException,
match=r"Stake-currency 'USDT' not compatible with pair-whitelist.*"):
validate_config_consistency(conf)
def test_load_config_test_comments() -> None:
"""

View File

@@ -2200,6 +2200,7 @@ def test_handle_timedout_limit_buy(mocker, default_conf, limit_buy_order) -> Non
Trade.session = MagicMock()
trade = MagicMock()
trade.pair = 'LTC/ETH'
limit_buy_order['remaining'] = limit_buy_order['amount']
assert freqtrade.handle_timedout_limit_buy(trade, limit_buy_order)
assert cancel_order_mock.call_count == 1
@@ -2223,6 +2224,7 @@ def test_handle_timedout_limit_buy_corder_empty(mocker, default_conf, limit_buy_
Trade.session = MagicMock()
trade = MagicMock()
trade.pair = 'LTC/ETH'
limit_buy_order['remaining'] = limit_buy_order['amount']
assert freqtrade.handle_timedout_limit_buy(trade, limit_buy_order)
assert cancel_order_mock.call_count == 1