conflict with develop resolved

This commit is contained in:
misagh 2019-03-14 07:56:21 +01:00
commit 9a226ec7e6
18 changed files with 299 additions and 278 deletions

View File

@ -78,7 +78,8 @@
"pair_blacklist": [ "pair_blacklist": [
"DOGE/BTC" "DOGE/BTC"
], ],
"outdated_offset": 5 "outdated_offset": 5,
"markets_refresh_interval": 60
}, },
"edge": { "edge": {
"enabled": false, "enabled": false,

View File

@ -48,6 +48,7 @@ Mandatory Parameters are marked as **Required**.
| `exchange.ccxt_rate_limit` | True | DEPRECATED!! Have CCXT handle Exchange rate limits. Depending on the exchange, having this to false can lead to temporary bans from the exchange. | `exchange.ccxt_rate_limit` | True | DEPRECATED!! Have CCXT handle Exchange rate limits. Depending on the exchange, having this to false can lead to temporary bans from the exchange.
| `exchange.ccxt_config` | None | Additional CCXT parameters passed to the regular ccxt instance. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation) | `exchange.ccxt_config` | None | Additional CCXT parameters passed to the regular ccxt instance. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation)
| `exchange.ccxt_async_config` | None | Additional CCXT parameters passed to the async ccxt instance. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation) | `exchange.ccxt_async_config` | None | Additional CCXT parameters passed to the async ccxt instance. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation)
| `exchange.markets_refresh_interval` | 60 | The interval in minutes in which markets are reloaded.
| `edge` | false | Please refer to [edge configuration document](edge.md) for detailed explanation. | `edge` | false | Please refer to [edge configuration document](edge.md) for detailed explanation.
| `experimental.use_sell_signal` | false | Use your sell strategy in addition of the `minimal_roi`. [Strategy Override](#parameters-in-strategy). | `experimental.use_sell_signal` | false | Use your sell strategy in addition of the `minimal_roi`. [Strategy Override](#parameters-in-strategy).
| `experimental.sell_profit_only` | false | Waits until you have made a positive profit before taking a sell decision. [Strategy Override](#parameters-in-strategy). | `experimental.sell_profit_only` | false | Waits until you have made a positive profit before taking a sell decision. [Strategy Override](#parameters-in-strategy).
@ -119,9 +120,10 @@ See the example below:
}, },
``` ```
Most of the strategy files already include the optimal `minimal_roi` Most of the strategy files already include the optimal `minimal_roi` value.
value. This parameter is optional. If you use it in the configuration file, it will take over the This parameter can be set in either Strategy or Configuration file. If you use it in the configuration file, it will override the
`minimal_roi` value from the strategy file. `minimal_roi` value from the strategy file.
If it is not set in either Strategy or Configuration, a default of 1000% `{"0": 10}` is used, and minimal roi is disabled unless your trade generates 1000% profit.
### Understand stoploss ### Understand stoploss

View File

@ -203,6 +203,7 @@ CONF_SCHEMA = {
'uniqueItems': True 'uniqueItems': True
}, },
'outdated_offset': {'type': 'integer', 'minimum': 1}, 'outdated_offset': {'type': 'integer', 'minimum': 1},
'markets_refresh_interval': {'type': 'integer'},
'ccxt_config': {'type': 'object'}, 'ccxt_config': {'type': 'object'},
'ccxt_async_config': {'type': 'object'} 'ccxt_async_config': {'type': 'object'}
}, },

View File

@ -88,6 +88,8 @@ class Exchange(object):
# Holds last candle refreshed time of each pair # Holds last candle refreshed time of each pair
self._pairs_last_refresh_time: Dict[Tuple[str, str], int] = {} self._pairs_last_refresh_time: Dict[Tuple[str, str], int] = {}
# Timestamp of last markets refresh
self._last_markets_refresh: int = 0
# Holds candles # Holds candles
self._klines: Dict[Tuple[str, str], DataFrame] = {} self._klines: Dict[Tuple[str, str], DataFrame] = {}
@ -106,7 +108,12 @@ class Exchange(object):
logger.info('Using Exchange "%s"', self.name) logger.info('Using Exchange "%s"', self.name)
self.markets = self._load_markets() # Converts the interval provided in minutes in config to seconds
self.markets_refresh_interval: int = exchange_config.get(
"markets_refresh_interval", 60) * 60
# Initial markets load
self._load_markets()
# Check if all pairs are available # Check if all pairs are available
self.validate_pairs(config['exchange']['pair_whitelist']) self.validate_pairs(config['exchange']['pair_whitelist'])
self.validate_ordertypes(config.get('order_types', {})) self.validate_ordertypes(config.get('order_types', {}))
@ -167,6 +174,14 @@ class Exchange(object):
"""exchange ccxt id""" """exchange ccxt id"""
return self._api.id return self._api.id
@property
def markets(self) -> Dict:
"""exchange ccxt markets"""
if not self._api.markets:
logger.warning("Markets were not loaded. Loading them now..")
self._load_markets()
return self._api.markets
def klines(self, pair_interval: Tuple[str, str], copy=True) -> DataFrame: def klines(self, pair_interval: Tuple[str, str], copy=True) -> DataFrame:
if pair_interval in self._klines: if pair_interval in self._klines:
return self._klines[pair_interval].copy() if copy else self._klines[pair_interval] return self._klines[pair_interval].copy() if copy else self._klines[pair_interval]
@ -183,24 +198,35 @@ class Exchange(object):
"Please check your config.json") "Please check your config.json")
raise OperationalException(f'Exchange {name} does not provide a sandbox api') raise OperationalException(f'Exchange {name} does not provide a sandbox api')
def _load_async_markets(self) -> None: def _load_async_markets(self, reload=False) -> None:
try: try:
if self._api_async: if self._api_async:
asyncio.get_event_loop().run_until_complete(self._api_async.load_markets()) asyncio.get_event_loop().run_until_complete(
self._api_async.load_markets(reload=reload))
except ccxt.BaseError as e: except ccxt.BaseError as e:
logger.warning('Could not load async markets. Reason: %s', e) logger.warning('Could not load async markets. Reason: %s', e)
return return
def _load_markets(self) -> Dict[str, Any]: def _load_markets(self) -> None:
""" Initialize markets both sync and async """ """ Initialize markets both sync and async """
try: try:
markets = self._api.load_markets() self._api.load_markets()
self._load_async_markets() self._load_async_markets()
return markets self._last_markets_refresh = arrow.utcnow().timestamp
except ccxt.BaseError as e: except ccxt.BaseError as e:
logger.warning('Unable to initialize markets. Reason: %s', e) logger.warning('Unable to initialize markets. Reason: %s', e)
return {}
def _reload_markets(self) -> None:
"""Reload markets both sync and async, if refresh interval has passed"""
# Check whether markets have to be reloaded
if (self._last_markets_refresh > 0) and (
self._last_markets_refresh + self.markets_refresh_interval
> arrow.utcnow().timestamp):
return None
logger.debug("Performing scheduled market reload..")
self._api.load_markets(reload=True)
self._last_markets_refresh = arrow.utcnow().timestamp
def validate_pairs(self, pairs: List[str]) -> None: def validate_pairs(self, pairs: List[str]) -> None:
""" """
@ -223,7 +249,7 @@ class Exchange(object):
f'Pair {pair} not compatible with stake_currency: {stake_cur}') f'Pair {pair} not compatible with stake_currency: {stake_cur}')
if self.markets and pair not in self.markets: if self.markets and pair not in self.markets:
raise OperationalException( raise OperationalException(
f'Pair {pair} is not available at {self.name}' f'Pair {pair} is not available on {self.name}. '
f'Please remove {pair} from your whitelist.') f'Please remove {pair} from your whitelist.')
def validate_timeframes(self, timeframe: List[str]) -> None: def validate_timeframes(self, timeframe: List[str]) -> None:
@ -295,8 +321,8 @@ class Exchange(object):
Returns the amount to buy or sell to a precision the Exchange accepts Returns the amount to buy or sell to a precision the Exchange accepts
Rounded down Rounded down
''' '''
if self._api.markets[pair]['precision']['amount']: if self.markets[pair]['precision']['amount']:
symbol_prec = self._api.markets[pair]['precision']['amount'] symbol_prec = self.markets[pair]['precision']['amount']
big_amount = amount * pow(10, symbol_prec) big_amount = amount * pow(10, symbol_prec)
amount = floor(big_amount) / pow(10, symbol_prec) amount = floor(big_amount) / pow(10, symbol_prec)
return amount return amount
@ -306,8 +332,8 @@ class Exchange(object):
Returns the price buying or selling with to the precision the Exchange accepts Returns the price buying or selling with to the precision the Exchange accepts
Rounds up Rounds up
''' '''
if self._api.markets[pair]['precision']['price']: if self.markets[pair]['precision']['price']:
symbol_prec = self._api.markets[pair]['precision']['price'] symbol_prec = self.markets[pair]['precision']['price']
big_price = price * pow(10, symbol_prec) big_price = price * pow(10, symbol_prec)
price = ceil(big_price) / pow(10, symbol_prec) price = ceil(big_price) / pow(10, symbol_prec)
return price return price
@ -678,16 +704,6 @@ class Exchange(object):
except ccxt.BaseError as e: except ccxt.BaseError as e:
raise OperationalException(e) raise OperationalException(e)
@retrier
def get_markets(self) -> List[dict]:
try:
return self._api.fetch_markets()
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
raise TemporaryError(
f'Could not load markets due to {e.__class__.__name__}. Message: {e}')
except ccxt.BaseError as e:
raise OperationalException(e)
@retrier @retrier
def get_fee(self, symbol='ETH/BTC', type='', side='', amount=1, def get_fee(self, symbol='ETH/BTC', type='', side='', amount=1,
price=1, taker_or_maker='maker') -> float: price=1, taker_or_maker='maker') -> float:

View File

@ -155,6 +155,9 @@ class FreqtradeBot(object):
""" """
state_changed = False state_changed = False
try: try:
# Check whether markets have to be reloaded
self.exchange._reload_markets()
# Refresh whitelist # Refresh whitelist
self.pairlists.refresh_pairlist() self.pairlists.refresh_pairlist()
self.active_pair_whitelist = self.pairlists.whitelist self.active_pair_whitelist = self.pairlists.whitelist
@ -280,12 +283,10 @@ class FreqtradeBot(object):
return stake_amount return stake_amount
def _get_min_pair_stake_amount(self, pair: str, price: float) -> Optional[float]: def _get_min_pair_stake_amount(self, pair: str, price: float) -> Optional[float]:
markets = self.exchange.get_markets() try:
markets = [m for m in markets if m['symbol'] == pair] market = self.exchange.markets[pair]
if not markets: except KeyError:
raise ValueError(f'Can\'t get market information for symbol {pair}') raise ValueError(f"Can't get market information for symbol {pair}")
market = markets[0]
if 'limits' not in market: if 'limits' not in market:
return None return None
@ -512,6 +513,7 @@ class FreqtradeBot(object):
except OperationalException as exception: except OperationalException as exception:
logger.warning("Could not update trade amount: %s", exception) logger.warning("Could not update trade amount: %s", exception)
# This handles both buy and sell orders!
trade.update(order) trade.update(order)
if self.strategy.order_types.get('stoploss_on_exchange') and trade.is_open: if self.strategy.order_types.get('stoploss_on_exchange') and trade.is_open:
@ -657,6 +659,7 @@ class FreqtradeBot(object):
if order['status'] == 'closed': if order['status'] == 'closed':
trade.sell_reason = SellType.STOPLOSS_ON_EXCHANGE.value trade.sell_reason = SellType.STOPLOSS_ON_EXCHANGE.value
trade.update(order) trade.update(order)
self.notify_sell(trade)
result = True result = True
elif self.config.get('trailing_stop', False): elif self.config.get('trailing_stop', False):
# if trailing stoploss is enabled we check if stoploss value has changed # if trailing stoploss is enabled we check if stoploss value has changed
@ -846,10 +849,17 @@ class FreqtradeBot(object):
trade.open_order_id = order_id trade.open_order_id = order_id
trade.close_rate_requested = limit trade.close_rate_requested = limit
trade.sell_reason = sell_reason.value trade.sell_reason = sell_reason.value
Trade.session.flush()
self.notify_sell(trade)
profit_trade = trade.calc_profit(rate=limit) def notify_sell(self, trade: Trade):
"""
Sends rpc notification when a sell occured.
"""
profit_rate = trade.close_rate if trade.close_rate else trade.close_rate_requested
profit_trade = trade.calc_profit(rate=profit_rate)
current_rate = self.exchange.get_ticker(trade.pair)['bid'] current_rate = self.exchange.get_ticker(trade.pair)['bid']
profit_percent = trade.calc_profit_percent(limit) profit_percent = trade.calc_profit_percent(profit_rate)
gain = "profit" if profit_percent > 0 else "loss" gain = "profit" if profit_percent > 0 else "loss"
msg = { msg = {
@ -857,13 +867,13 @@ class FreqtradeBot(object):
'exchange': trade.exchange.capitalize(), 'exchange': trade.exchange.capitalize(),
'pair': trade.pair, 'pair': trade.pair,
'gain': gain, 'gain': gain,
'limit': limit, 'limit': trade.close_rate_requested,
'amount': trade.amount, 'amount': trade.amount,
'open_rate': trade.open_rate, 'open_rate': trade.open_rate,
'current_rate': current_rate, 'current_rate': current_rate,
'profit_amount': profit_trade, 'profit_amount': profit_trade,
'profit_percent': profit_percent, 'profit_percent': profit_percent,
'sell_reason': sell_reason.value 'sell_reason': trade.sell_reason
} }
# For regular case, when the configuration exists # For regular case, when the configuration exists
@ -877,4 +887,3 @@ class FreqtradeBot(object):
# Send the message # Send the message
self.rpc.send_msg(msg) self.rpc.send_msg(msg)
Trade.session.flush()

View File

@ -66,12 +66,14 @@ class IPairList(ABC):
black_listed black_listed
""" """
sanitized_whitelist = whitelist sanitized_whitelist = whitelist
markets = self._freqtrade.exchange.get_markets() markets = self._freqtrade.exchange.markets
# Filter to markets in stake currency # Filter to markets in stake currency
markets = [m for m in markets if m['quote'] == self._config['stake_currency']] markets = [markets[pair] for pair in markets if
markets[pair]['quote'] == self._config['stake_currency']]
known_pairs = set() known_pairs = set()
# TODO: we should loop over whitelist instead of all markets
for market in markets: for market in markets:
pair = market['symbol'] pair = market['symbol']
# pair is not in the generated dynamic market, or in the blacklist ... ignore it # pair is not in the generated dynamic market, or in the blacklist ... ignore it

View File

@ -266,6 +266,7 @@ class Trade(_DECL_BASE):
logger.info('%s_SELL has been fulfilled for %s.', order_type.upper(), self) logger.info('%s_SELL has been fulfilled for %s.', order_type.upper(), self)
elif order_type == 'stop_loss_limit': elif order_type == 'stop_loss_limit':
self.stoploss_order_id = None self.stoploss_order_id = None
self.close_rate_requested = self.stop_loss
logger.info('STOP_LOSS_LIMIT is hit for %s.', self) logger.info('STOP_LOSS_LIMIT is hit for %s.', self)
self.close(order['average']) self.close(order['average'])
else: else:

View File

@ -31,7 +31,11 @@ class IResolver(object):
# Generate spec based on absolute path # Generate spec based on absolute path
spec = importlib.util.spec_from_file_location('unknown', str(module_path)) spec = importlib.util.spec_from_file_location('unknown', str(module_path))
module = importlib.util.module_from_spec(spec) module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module) # type: ignore # importlib does not use typehints try:
spec.loader.exec_module(module) # type: ignore # importlib does not use typehints
except ModuleNotFoundError as err:
# Catch errors in case a specific module is not installed
logger.info(f"Could not import {module_path} due to '{err}'")
valid_objects_gen = ( valid_objects_gen = (
obj for name, obj in inspect.getmembers(module, inspect.isclass) obj for name, obj in inspect.getmembers(module, inspect.isclass)

View File

@ -46,19 +46,19 @@ class StrategyResolver(IResolver):
# Set attributes # Set attributes
# Check if we need to override configuration # Check if we need to override configuration
# (Attribute name, default, experimental) # (Attribute name, default, experimental)
attributes = [("minimal_roi", None, False), attributes = [("minimal_roi", {"0": 10.0}, False),
("ticker_interval", None, False), ("ticker_interval", None, False),
("stoploss", None, False), ("stoploss", None, False),
("trailing_stop", None, False), ("trailing_stop", None, False),
("trailing_stop_positive", None, False), ("trailing_stop_positive", None, False),
("trailing_stop_positive_offset", 0.0, False), ("trailing_stop_positive_offset", 0.0, False),
("trailing_only_offset_is_reached", None, False), ("trailing_only_offset_is_reached", None, False),
("process_only_new_candles", None, False), ("process_only_new_candles", None, False),
("order_types", None, False), ("order_types", None, False),
("order_time_in_force", None, False), ("order_time_in_force", None, False),
("use_sell_signal", False, True), ("use_sell_signal", False, True),
("sell_profit_only", False, True), ("sell_profit_only", False, True),
("ignore_roi_if_buy_signal", False, True), ("ignore_roi_if_buy_signal", False, True),
] ]
for attribute, default, experimental in attributes: for attribute, default, experimental in attributes:
if experimental: if experimental:

View File

@ -2,7 +2,7 @@
This module contains class to manage RPC communications (Telegram, Slack, ...) This module contains class to manage RPC communications (Telegram, Slack, ...)
""" """
import logging import logging
from typing import List, Dict, Any from typing import Any, Dict, List
from freqtrade.rpc import RPC, RPCMessageType from freqtrade.rpc import RPC, RPCMessageType

View File

@ -37,6 +37,7 @@ def log_has_re(line, logs):
def patch_exchange(mocker, api_mock=None, id='bittrex') -> None: def patch_exchange(mocker, api_mock=None, id='bittrex') -> None:
mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={})) mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={}))
mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock())
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock()) mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock())
mocker.patch('freqtrade.exchange.Exchange.validate_ordertypes', MagicMock()) mocker.patch('freqtrade.exchange.Exchange.validate_ordertypes', MagicMock())
mocker.patch('freqtrade.exchange.Exchange.id', PropertyMock(return_value=id)) mocker.patch('freqtrade.exchange.Exchange.id', PropertyMock(return_value=id))
@ -225,8 +226,8 @@ def ticker_sell_down():
@pytest.fixture @pytest.fixture
def markets(): def markets():
return MagicMock(return_value=[ return {
{ 'ETH/BTC': {
'id': 'ethbtc', 'id': 'ethbtc',
'symbol': 'ETH/BTC', 'symbol': 'ETH/BTC',
'base': 'ETH', 'base': 'ETH',
@ -251,7 +252,7 @@ def markets():
}, },
'info': '', 'info': '',
}, },
{ 'TKN/BTC': {
'id': 'tknbtc', 'id': 'tknbtc',
'symbol': 'TKN/BTC', 'symbol': 'TKN/BTC',
'base': 'TKN', 'base': 'TKN',
@ -276,7 +277,7 @@ def markets():
}, },
'info': '', 'info': '',
}, },
{ 'BLK/BTC': {
'id': 'blkbtc', 'id': 'blkbtc',
'symbol': 'BLK/BTC', 'symbol': 'BLK/BTC',
'base': 'BLK', 'base': 'BLK',
@ -301,7 +302,7 @@ def markets():
}, },
'info': '', 'info': '',
}, },
{ 'LTC/BTC': {
'id': 'ltcbtc', 'id': 'ltcbtc',
'symbol': 'LTC/BTC', 'symbol': 'LTC/BTC',
'base': 'LTC', 'base': 'LTC',
@ -326,7 +327,7 @@ def markets():
}, },
'info': '', 'info': '',
}, },
{ 'XRP/BTC': {
'id': 'xrpbtc', 'id': 'xrpbtc',
'symbol': 'XRP/BTC', 'symbol': 'XRP/BTC',
'base': 'XRP', 'base': 'XRP',
@ -351,7 +352,7 @@ def markets():
}, },
'info': '', 'info': '',
}, },
{ 'NEO/BTC': {
'id': 'neobtc', 'id': 'neobtc',
'symbol': 'NEO/BTC', 'symbol': 'NEO/BTC',
'base': 'NEO', 'base': 'NEO',
@ -376,7 +377,7 @@ def markets():
}, },
'info': '', 'info': '',
}, },
{ 'BTT/BTC': {
'id': 'BTTBTC', 'id': 'BTTBTC',
'symbol': 'BTT/BTC', 'symbol': 'BTT/BTC',
'base': 'BTT', 'base': 'BTT',
@ -404,7 +405,7 @@ def markets():
}, },
'info': "", 'info': "",
}, },
{ 'ETH/USDT': {
'id': 'USDT-ETH', 'id': 'USDT-ETH',
'symbol': 'ETH/USDT', 'symbol': 'ETH/USDT',
'base': 'ETH', 'base': 'ETH',
@ -426,7 +427,7 @@ def markets():
'active': True, 'active': True,
'info': "" 'info': ""
}, },
{ 'LTC/USDT': {
'id': 'USDT-LTC', 'id': 'USDT-LTC',
'symbol': 'LTC/USDT', 'symbol': 'LTC/USDT',
'base': 'LTC', 'base': 'LTC',
@ -448,7 +449,7 @@ def markets():
}, },
'info': "" 'info': ""
} }
]) }
@pytest.fixture @pytest.fixture

View File

@ -152,10 +152,7 @@ def test_symbol_amount_prec(default_conf, mocker):
markets = PropertyMock(return_value={'ETH/BTC': {'precision': {'amount': 4}}}) markets = PropertyMock(return_value={'ETH/BTC': {'precision': {'amount': 4}}})
type(api_mock).markets = markets type(api_mock).markets = markets
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) exchange = get_patched_exchange(mocker, default_conf, api_mock)
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock())
mocker.patch('freqtrade.exchange.Exchange._load_async_markets', MagicMock())
exchange = Exchange(default_conf)
amount = 2.34559 amount = 2.34559
pair = 'ETH/BTC' pair = 'ETH/BTC'
@ -176,10 +173,7 @@ def test_symbol_price_prec(default_conf, mocker):
markets = PropertyMock(return_value={'ETH/BTC': {'precision': {'price': 4}}}) markets = PropertyMock(return_value={'ETH/BTC': {'precision': {'price': 4}}})
type(api_mock).markets = markets type(api_mock).markets = markets
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) exchange = get_patched_exchange(mocker, default_conf, api_mock)
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock())
mocker.patch('freqtrade.exchange.Exchange._load_async_markets', MagicMock())
exchange = Exchange(default_conf)
price = 2.34559 price = 2.34559
pair = 'ETH/BTC' pair = 'ETH/BTC'
@ -198,11 +192,7 @@ def test_set_sandbox(default_conf, mocker):
url_mock = PropertyMock(return_value={'test': "api-public.sandbox.gdax.com", url_mock = PropertyMock(return_value={'test': "api-public.sandbox.gdax.com",
'api': 'https://api.gdax.com'}) 'api': 'https://api.gdax.com'})
type(api_mock).urls = url_mock type(api_mock).urls = url_mock
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) exchange = get_patched_exchange(mocker, default_conf, api_mock)
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock())
mocker.patch('freqtrade.exchange.Exchange._load_async_markets', MagicMock())
exchange = Exchange(default_conf)
liveurl = exchange._api.urls['api'] liveurl = exchange._api.urls['api']
default_conf['exchange']['sandbox'] = True default_conf['exchange']['sandbox'] = True
exchange.set_sandbox(exchange._api, default_conf['exchange'], 'Logname') exchange.set_sandbox(exchange._api, default_conf['exchange'], 'Logname')
@ -220,12 +210,8 @@ def test_set_sandbox_exception(default_conf, mocker):
url_mock = PropertyMock(return_value={'api': 'https://api.gdax.com'}) url_mock = PropertyMock(return_value={'api': 'https://api.gdax.com'})
type(api_mock).urls = url_mock type(api_mock).urls = url_mock
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock())
mocker.patch('freqtrade.exchange.Exchange._load_async_markets', MagicMock())
with pytest.raises(OperationalException, match=r'does not provide a sandbox api'): with pytest.raises(OperationalException, match=r'does not provide a sandbox api'):
exchange = Exchange(default_conf) exchange = get_patched_exchange(mocker, default_conf, api_mock)
default_conf['exchange']['sandbox'] = True default_conf['exchange']['sandbox'] = True
exchange.set_sandbox(exchange._api, default_conf['exchange'], 'Logname') exchange.set_sandbox(exchange._api, default_conf['exchange'], 'Logname')
@ -247,29 +233,54 @@ def test__load_async_markets(default_conf, mocker, caplog):
def test__load_markets(default_conf, mocker, caplog): def test__load_markets(default_conf, mocker, caplog):
caplog.set_level(logging.INFO) caplog.set_level(logging.INFO)
api_mock = MagicMock() api_mock = MagicMock()
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)
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock())
mocker.patch('freqtrade.exchange.Exchange._load_async_markets', MagicMock())
expected_return = {'ETH/BTC': 'available'}
api_mock.load_markets = MagicMock(return_value=expected_return)
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
default_conf['exchange']['pair_whitelist'] = ['ETH/BTC']
ex = Exchange(default_conf)
assert ex.markets == expected_return
api_mock.load_markets = MagicMock(side_effect=ccxt.BaseError()) api_mock.load_markets = MagicMock(side_effect=ccxt.BaseError())
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock())
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock())
mocker.patch('freqtrade.exchange.Exchange._load_async_markets', MagicMock())
Exchange(default_conf) Exchange(default_conf)
assert log_has('Unable to initialize markets. Reason: ', caplog.record_tuples) assert log_has('Unable to initialize markets. Reason: ', caplog.record_tuples)
expected_return = {'ETH/BTC': 'available'}
def test_validate_pairs(default_conf, mocker):
api_mock = MagicMock() api_mock = MagicMock()
api_mock.load_markets = MagicMock(return_value={ api_mock.load_markets = MagicMock(return_value=expected_return)
type(api_mock).markets = expected_return
default_conf['exchange']['pair_whitelist'] = ['ETH/BTC']
ex = get_patched_exchange(mocker, default_conf, api_mock, id="binance")
assert ex.markets == expected_return
def test__reload_markets(default_conf, mocker, caplog):
caplog.set_level(logging.DEBUG)
initial_markets = {'ETH/BTC': {}}
def load_markets(*args, **kwargs):
exchange._api.markets = updated_markets
api_mock = MagicMock()
api_mock.load_markets = load_markets
type(api_mock).markets = initial_markets
default_conf['exchange']['markets_refresh_interval'] = 10
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="binance")
exchange._last_markets_refresh = arrow.utcnow().timestamp
updated_markets = {'ETH/BTC': {}, "LTC/BTC": {}}
assert exchange.markets == initial_markets
# less than 10 minutes have passed, no reload
exchange._reload_markets()
assert exchange.markets == initial_markets
# more than 10 minutes have passed, reload is executed
exchange._last_markets_refresh = arrow.utcnow().timestamp - 15 * 60
exchange._reload_markets()
assert exchange.markets == updated_markets
assert log_has('Performing scheduled market reload..', caplog.record_tuples)
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': '', 'LTC/BTC': '', 'XRP/BTC': '', 'NEO/BTC': ''
}) })
id_mock = PropertyMock(return_value='test_exchange') id_mock = PropertyMock(return_value='test_exchange')
@ -283,7 +294,9 @@ def test_validate_pairs(default_conf, mocker):
def test_validate_pairs_not_available(default_conf, mocker): def test_validate_pairs_not_available(default_conf, mocker):
api_mock = MagicMock() api_mock = MagicMock()
api_mock.load_markets = MagicMock(return_value={'XRP/BTC': 'inactive'}) type(api_mock).markets = PropertyMock(return_value={
'XRP/BTC': 'inactive'
})
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock()) mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock())
mocker.patch('freqtrade.exchange.Exchange._load_async_markets', MagicMock()) mocker.patch('freqtrade.exchange.Exchange._load_async_markets', MagicMock())
@ -294,7 +307,7 @@ def test_validate_pairs_not_available(default_conf, mocker):
def test_validate_pairs_not_compatible(default_conf, mocker): def test_validate_pairs_not_compatible(default_conf, mocker):
api_mock = MagicMock() api_mock = MagicMock()
api_mock.load_markets = MagicMock(return_value={ type(api_mock).markets = PropertyMock(return_value={
'ETH/BTC': '', 'TKN/BTC': '', 'TRST/BTC': '', 'SWT/BTC': '', 'BCC/BTC': '' 'ETH/BTC': '', 'TKN/BTC': '', 'TRST/BTC': '', 'SWT/BTC': '', 'BCC/BTC': ''
}) })
default_conf['stake_currency'] = 'ETH' default_conf['stake_currency'] = 'ETH'
@ -310,15 +323,15 @@ def test_validate_pairs_exception(default_conf, mocker, caplog):
api_mock = MagicMock() api_mock = MagicMock()
mocker.patch('freqtrade.exchange.Exchange.name', PropertyMock(return_value='Binance')) mocker.patch('freqtrade.exchange.Exchange.name', PropertyMock(return_value='Binance'))
api_mock.load_markets = MagicMock(return_value={}) type(api_mock).markets = PropertyMock(return_value={})
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', api_mock) mocker.patch('freqtrade.exchange.Exchange._init_ccxt', api_mock)
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock()) mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock())
mocker.patch('freqtrade.exchange.Exchange._load_async_markets', MagicMock()) mocker.patch('freqtrade.exchange.Exchange._load_async_markets', MagicMock())
with pytest.raises(OperationalException, match=r'Pair ETH/BTC is not available at Binance'): with pytest.raises(OperationalException, match=r'Pair ETH/BTC is not available on Binance'):
Exchange(default_conf) Exchange(default_conf)
mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={})) mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value={}))
Exchange(default_conf) Exchange(default_conf)
assert log_has('Unable to validate pairs (assuming they are correct).', assert log_has('Unable to validate pairs (assuming they are correct).',
caplog.record_tuples) caplog.record_tuples)
@ -353,6 +366,7 @@ def test_validate_timeframes(default_conf, mocker):
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={})) mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={}))
mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock())
Exchange(default_conf) Exchange(default_conf)
@ -369,6 +383,7 @@ def test_validate_timeframes_failed(default_conf, mocker):
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={})) mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={}))
mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock())
with pytest.raises(OperationalException, match=r'Invalid ticker 3m, this Exchange supports.*'): with pytest.raises(OperationalException, match=r'Invalid ticker 3m, this Exchange supports.*'):
Exchange(default_conf) Exchange(default_conf)
@ -386,6 +401,7 @@ def test_validate_timeframes_not_in_config(default_conf, mocker):
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={})) mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={}))
mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock())
Exchange(default_conf) Exchange(default_conf)
@ -395,6 +411,7 @@ def test_validate_order_types(default_conf, mocker):
type(api_mock).has = PropertyMock(return_value={'createMarketOrder': True}) type(api_mock).has = PropertyMock(return_value={'createMarketOrder': True})
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={})) mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={}))
mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock())
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock()) mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock())
mocker.patch('freqtrade.exchange.Exchange.name', 'Bittrex') mocker.patch('freqtrade.exchange.Exchange.name', 'Bittrex')
default_conf['order_types'] = { default_conf['order_types'] = {
@ -463,6 +480,7 @@ def test_validate_order_types_not_in_config(default_conf, mocker):
api_mock = MagicMock() api_mock = MagicMock()
mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock)) mocker.patch('freqtrade.exchange.Exchange._init_ccxt', MagicMock(return_value=api_mock))
mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={})) mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={}))
mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock())
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock()) mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock())
conf = copy.deepcopy(default_conf) conf = copy.deepcopy(default_conf)
@ -1339,22 +1357,6 @@ def test_get_trades_for_order(default_conf, mocker, exchange_name):
assert exchange.get_trades_for_order(order_id, 'LTC/BTC', since) == [] assert exchange.get_trades_for_order(order_id, 'LTC/BTC', since) == []
@pytest.mark.parametrize("exchange_name", EXCHANGES)
def test_get_markets(default_conf, mocker, markets, exchange_name):
api_mock = MagicMock()
api_mock.fetch_markets = markets
exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name)
ret = exchange.get_markets()
assert isinstance(ret, list)
assert len(ret) == 9
assert ret[0]["id"] == "ethbtc"
assert ret[0]["symbol"] == "ETH/BTC"
ccxt_exceptionhandlers(mocker, default_conf, api_mock, exchange_name,
'get_markets', 'fetch_markets')
@pytest.mark.parametrize("exchange_name", EXCHANGES) @pytest.mark.parametrize("exchange_name", EXCHANGES)
def test_get_fee(default_conf, mocker, exchange_name): def test_get_fee(default_conf, mocker, exchange_name):
api_mock = MagicMock() api_mock = MagicMock()

View File

@ -1,6 +1,6 @@
# pragma pylint: disable=missing-docstring,C0103,protected-access # pragma pylint: disable=missing-docstring,C0103,protected-access
from unittest.mock import MagicMock from unittest.mock import MagicMock, PropertyMock
from freqtrade import OperationalException from freqtrade import OperationalException
from freqtrade.constants import AVAILABLE_PAIRLISTS from freqtrade.constants import AVAILABLE_PAIRLISTS
@ -33,7 +33,7 @@ def whitelist_conf(default_conf):
def test_load_pairlist_noexist(mocker, markets, default_conf): def test_load_pairlist_noexist(mocker, markets, default_conf):
freqtradebot = get_patched_freqtradebot(mocker, default_conf) freqtradebot = get_patched_freqtradebot(mocker, default_conf)
mocker.patch('freqtrade.exchange.Exchange.get_markets', markets) mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets))
with pytest.raises(ImportError, with pytest.raises(ImportError,
match=r"Impossible to load Pairlist 'NonexistingPairList'." match=r"Impossible to load Pairlist 'NonexistingPairList'."
r" This class does not exist or contains Python code errors"): r" This class does not exist or contains Python code errors"):
@ -44,7 +44,7 @@ def test_refresh_market_pair_not_in_whitelist(mocker, markets, whitelist_conf):
freqtradebot = get_patched_freqtradebot(mocker, whitelist_conf) freqtradebot = get_patched_freqtradebot(mocker, whitelist_conf)
mocker.patch('freqtrade.exchange.Exchange.get_markets', markets) mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets))
freqtradebot.pairlists.refresh_pairlist() freqtradebot.pairlists.refresh_pairlist()
# List ordered by BaseVolume # List ordered by BaseVolume
whitelist = ['ETH/BTC', 'TKN/BTC'] whitelist = ['ETH/BTC', 'TKN/BTC']
@ -58,7 +58,7 @@ def test_refresh_market_pair_not_in_whitelist(mocker, markets, whitelist_conf):
def test_refresh_pairlists(mocker, markets, whitelist_conf): def test_refresh_pairlists(mocker, markets, whitelist_conf):
freqtradebot = get_patched_freqtradebot(mocker, whitelist_conf) freqtradebot = get_patched_freqtradebot(mocker, whitelist_conf)
mocker.patch('freqtrade.exchange.Exchange.get_markets', markets) mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets))
freqtradebot.pairlists.refresh_pairlist() freqtradebot.pairlists.refresh_pairlist()
# List ordered by BaseVolume # List ordered by BaseVolume
whitelist = ['ETH/BTC', 'TKN/BTC'] whitelist = ['ETH/BTC', 'TKN/BTC']
@ -73,7 +73,7 @@ def test_refresh_pairlist_dynamic(mocker, markets, tickers, whitelist_conf):
} }
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_markets=markets, markets=PropertyMock(return_value=markets),
get_tickers=tickers, get_tickers=tickers,
exchange_has=MagicMock(return_value=True) exchange_has=MagicMock(return_value=True)
) )
@ -96,7 +96,7 @@ def test_refresh_pairlist_dynamic(mocker, markets, tickers, whitelist_conf):
def test_VolumePairList_refresh_empty(mocker, markets_empty, whitelist_conf): def test_VolumePairList_refresh_empty(mocker, markets_empty, whitelist_conf):
freqtradebot = get_patched_freqtradebot(mocker, whitelist_conf) freqtradebot = get_patched_freqtradebot(mocker, whitelist_conf)
mocker.patch('freqtrade.exchange.Exchange.get_markets', markets_empty) mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets_empty))
# argument: use the whitelist dynamically by exchange-volume # argument: use the whitelist dynamically by exchange-volume
whitelist = [] whitelist = []
@ -111,7 +111,7 @@ def test_VolumePairList_whitelist_gen(mocker, whitelist_conf, markets, tickers)
whitelist_conf['pairlist']['method'] = 'VolumePairList' whitelist_conf['pairlist']['method'] = 'VolumePairList'
mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True)) mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True))
freqtrade = get_patched_freqtradebot(mocker, whitelist_conf) freqtrade = get_patched_freqtradebot(mocker, whitelist_conf)
mocker.patch('freqtrade.exchange.Exchange.get_markets', markets) mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets))
mocker.patch('freqtrade.exchange.Exchange.get_tickers', tickers) mocker.patch('freqtrade.exchange.Exchange.get_tickers', tickers)
mocker.patch('freqtrade.exchange.Exchange.symbol_price_prec', lambda s, p, r: round(r, 8)) mocker.patch('freqtrade.exchange.Exchange.symbol_price_prec', lambda s, p, r: round(r, 8))
@ -157,7 +157,7 @@ def test_gen_pair_whitelist_not_supported(mocker, default_conf, tickers) -> None
@pytest.mark.parametrize("pairlist", AVAILABLE_PAIRLISTS) @pytest.mark.parametrize("pairlist", AVAILABLE_PAIRLISTS)
def test_pairlist_class(mocker, whitelist_conf, markets, pairlist): def test_pairlist_class(mocker, whitelist_conf, markets, pairlist):
whitelist_conf['pairlist']['method'] = pairlist whitelist_conf['pairlist']['method'] = pairlist
mocker.patch('freqtrade.exchange.Exchange.get_markets', markets) mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets))
mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True)) mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True))
freqtrade = get_patched_freqtradebot(mocker, whitelist_conf) freqtrade = get_patched_freqtradebot(mocker, whitelist_conf)

View File

@ -2,7 +2,7 @@
# pragma pylint: disable=invalid-sequence-index, invalid-name, too-many-arguments # pragma pylint: disable=invalid-sequence-index, invalid-name, too-many-arguments
from datetime import datetime from datetime import datetime
from unittest.mock import MagicMock, ANY from unittest.mock import MagicMock, ANY, PropertyMock
import pytest import pytest
from numpy import isnan from numpy import isnan
@ -34,7 +34,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, markets, mocker) -> None:
_load_markets=MagicMock(return_value={}), _load_markets=MagicMock(return_value={}),
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = FreqtradeBot(default_conf)
@ -90,7 +90,7 @@ def test_rpc_status_table(default_conf, ticker, fee, markets, mocker) -> None:
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = FreqtradeBot(default_conf)
@ -126,7 +126,7 @@ def test_rpc_daily_profit(default_conf, update, ticker, fee,
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = FreqtradeBot(default_conf)
@ -180,7 +180,7 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = FreqtradeBot(default_conf)
@ -268,7 +268,7 @@ def test_rpc_trade_statistics_closed(mocker, default_conf, ticker, fee, markets,
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = FreqtradeBot(default_conf)
@ -424,7 +424,7 @@ def test_rpc_forcesell(default_conf, ticker, fee, mocker, markets) -> None:
} }
), ),
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = FreqtradeBot(default_conf)
@ -516,7 +516,7 @@ def test_performance_handle(default_conf, ticker, limit_buy_order, fee,
get_balances=MagicMock(return_value=ticker), get_balances=MagicMock(return_value=ticker),
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = FreqtradeBot(default_conf)
@ -552,7 +552,7 @@ def test_rpc_count(mocker, default_conf, ticker, fee, markets) -> None:
get_balances=MagicMock(return_value=ticker), get_balances=MagicMock(return_value=ticker),
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = FreqtradeBot(default_conf)
@ -581,7 +581,7 @@ def test_rpcforcebuy(mocker, default_conf, ticker, fee, markets, limit_buy_order
get_balances=MagicMock(return_value=ticker), get_balances=MagicMock(return_value=ticker),
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets, markets=PropertyMock(return_value=markets),
buy=buy_mm buy=buy_mm
) )

View File

@ -5,7 +5,7 @@
import re import re
from datetime import datetime from datetime import datetime
from random import randint from random import randint
from unittest.mock import MagicMock from unittest.mock import MagicMock, PropertyMock
import arrow import arrow
import pytest import pytest
@ -184,7 +184,7 @@ def test_status(default_conf, update, mocker, fee, ticker, markets) -> None:
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(markets)
) )
msg_mock = MagicMock() msg_mock = MagicMock()
status_table = MagicMock() status_table = MagicMock()
@ -232,7 +232,7 @@ def test_status_handle(default_conf, update, ticker, fee, markets, mocker) -> No
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(markets)
) )
msg_mock = MagicMock() msg_mock = MagicMock()
status_table = MagicMock() status_table = MagicMock()
@ -279,7 +279,7 @@ def test_status_table_handle(default_conf, update, ticker, fee, markets, mocker)
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': 'mocked_order_id'}), buy=MagicMock(return_value={'id': 'mocked_order_id'}),
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(markets)
) )
msg_mock = MagicMock() msg_mock = MagicMock()
mocker.patch.multiple( mocker.patch.multiple(
@ -334,7 +334,7 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee,
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(markets)
) )
msg_mock = MagicMock() msg_mock = MagicMock()
mocker.patch.multiple( mocker.patch.multiple(
@ -438,7 +438,7 @@ def test_profit_handle(default_conf, update, ticker, ticker_sell_up, fee,
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(markets)
) )
msg_mock = MagicMock() msg_mock = MagicMock()
mocker.patch.multiple( mocker.patch.multiple(
@ -693,7 +693,8 @@ def test_forcesell_handle(default_conf, update, ticker, fee,
_load_markets=MagicMock(return_value={}), _load_markets=MagicMock(return_value={}),
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets),
validate_pairs=MagicMock(return_value={})
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = FreqtradeBot(default_conf)
@ -743,7 +744,8 @@ def test_forcesell_down_handle(default_conf, update, ticker, fee,
_load_markets=MagicMock(return_value={}), _load_markets=MagicMock(return_value={}),
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets),
validate_pairs=MagicMock(return_value={})
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = FreqtradeBot(default_conf)
@ -796,7 +798,8 @@ def test_forcesell_all_handle(default_conf, update, ticker, fee, markets, mocker
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets),
validate_pairs=MagicMock(return_value={})
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = FreqtradeBot(default_conf)
@ -878,7 +881,8 @@ def test_forcebuy_handle(default_conf, update, markets, mocker) -> None:
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
_load_markets=MagicMock(return_value={}), _load_markets=MagicMock(return_value={}),
get_markets=markets markets=PropertyMock(markets),
validate_pairs=MagicMock(return_value={})
) )
fbuy_mock = MagicMock(return_value=None) fbuy_mock = MagicMock(return_value=None)
mocker.patch('freqtrade.rpc.RPC._rpc_forcebuy', fbuy_mock) mocker.patch('freqtrade.rpc.RPC._rpc_forcebuy', fbuy_mock)
@ -914,7 +918,8 @@ def test_forcebuy_handle_exception(default_conf, update, markets, mocker) -> Non
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
_load_markets=MagicMock(return_value={}), _load_markets=MagicMock(return_value={}),
get_markets=markets markets=PropertyMock(markets),
validate_pairs=MagicMock(return_value={})
) )
freqtradebot = FreqtradeBot(default_conf) freqtradebot = FreqtradeBot(default_conf)
patch_get_signal(freqtradebot, (True, False)) patch_get_signal(freqtradebot, (True, False))
@ -941,7 +946,8 @@ def test_performance_handle(default_conf, update, ticker, fee,
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(markets),
validate_pairs=MagicMock(return_value={})
) )
mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock()) mocker.patch('freqtrade.freqtradebot.RPCManager', MagicMock())
freqtradebot = FreqtradeBot(default_conf) freqtradebot = FreqtradeBot(default_conf)
@ -980,7 +986,7 @@ def test_count_handle(default_conf, update, ticker, fee, markets, mocker) -> Non
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': 'mocked_order_id'}), buy=MagicMock(return_value={'id': 'mocked_order_id'}),
get_markets=markets markets=PropertyMock(markets)
) )
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
freqtradebot = FreqtradeBot(default_conf) freqtradebot = FreqtradeBot(default_conf)

View File

@ -5,7 +5,7 @@ import logging
import re import re
import time import time
from copy import deepcopy from copy import deepcopy
from unittest.mock import MagicMock from unittest.mock import MagicMock, PropertyMock
import arrow import arrow
import pytest import pytest
@ -59,7 +59,8 @@ def patch_RPCManager(mocker) -> MagicMock:
# Unit tests # Unit tests
def test_freqtradebot(mocker, default_conf) -> None: def test_freqtradebot(mocker, default_conf, markets) -> None:
mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets))
freqtrade = get_patched_freqtradebot(mocker, default_conf) freqtrade = get_patched_freqtradebot(mocker, default_conf)
assert freqtrade.state is State.RUNNING assert freqtrade.state is State.RUNNING
@ -71,7 +72,6 @@ def test_freqtradebot(mocker, default_conf) -> None:
def test_cleanup(mocker, default_conf, caplog) -> None: def test_cleanup(mocker, default_conf, caplog) -> None:
mock_cleanup = MagicMock() mock_cleanup = MagicMock()
mocker.patch('freqtrade.persistence.cleanup', mock_cleanup) mocker.patch('freqtrade.persistence.cleanup', mock_cleanup)
freqtrade = get_patched_freqtradebot(mocker, default_conf) freqtrade = get_patched_freqtradebot(mocker, default_conf)
freqtrade.cleanup() freqtrade.cleanup()
assert log_has('Cleaning up modules ...', caplog.record_tuples) assert log_has('Cleaning up modules ...', caplog.record_tuples)
@ -171,11 +171,10 @@ def test_get_trade_stake_amount_unlimited_amount(default_conf,
patch_wallet(mocker, free=default_conf['stake_amount']) patch_wallet(mocker, free=default_conf['stake_amount'])
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
validate_pairs=MagicMock(), markets=PropertyMock(return_value=markets),
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee
get_markets=markets
) )
conf = deepcopy(default_conf) conf = deepcopy(default_conf)
@ -253,7 +252,7 @@ def test_edge_overrides_stoploss(limit_buy_order, fee, markets, caplog, mocker,
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets, markets=PropertyMock(return_value=markets)
) )
############################################# #############################################
@ -293,7 +292,7 @@ def test_edge_should_ignore_strategy_stoploss(limit_buy_order, fee, markets,
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets, markets=PropertyMock(return_value=markets),
) )
############################################# #############################################
@ -321,7 +320,7 @@ def test_total_open_trades_stakes(mocker, default_conf, ticker,
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
@ -349,131 +348,108 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
patch_exchange(mocker) patch_exchange(mocker)
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
freqtrade.strategy.stoploss = -0.05 freqtrade.strategy.stoploss = -0.05
markets = {'ETH/BTC': {'symbol': 'ETH/BTC'}}
# no pair found # no pair found
mocker.patch( mocker.patch(
'freqtrade.exchange.Exchange.get_markets', 'freqtrade.exchange.Exchange.markets',
MagicMock(return_value=[{ PropertyMock(return_value=markets)
'symbol': 'ETH/BTC'
}])
) )
with pytest.raises(ValueError, match=r'.*get market information.*'): with pytest.raises(ValueError, match=r'.*get market information.*'):
freqtrade._get_min_pair_stake_amount('BNB/BTC', 1) freqtrade._get_min_pair_stake_amount('BNB/BTC', 1)
# no 'limits' section # no 'limits' section
mocker.patch(
'freqtrade.exchange.Exchange.get_markets',
MagicMock(return_value=[{
'symbol': 'ETH/BTC'
}])
)
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1) result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1)
assert result is None assert result is None
# empty 'limits' section # empty 'limits' section
markets["ETH/BTC"]["limits"] = {}
mocker.patch( mocker.patch(
'freqtrade.exchange.Exchange.get_markets', 'freqtrade.exchange.Exchange.markets',
MagicMock(return_value=[{ PropertyMock(return_value=markets)
'symbol': 'ETH/BTC',
'limits': {}
}])
) )
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1) result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1)
assert result is None assert result is None
# no cost Min # no cost Min
markets["ETH/BTC"]["limits"] = {
'cost': {"min": None},
'amount': {}
}
mocker.patch( mocker.patch(
'freqtrade.exchange.Exchange.get_markets', 'freqtrade.exchange.Exchange.markets',
MagicMock(return_value=[{ PropertyMock(return_value=markets)
'symbol': 'ETH/BTC',
'limits': {
'cost': {"min": None},
'amount': {}
}
}])
) )
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1) result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1)
assert result is None assert result is None
# no amount Min # no amount Min
markets["ETH/BTC"]["limits"] = {
'cost': {},
'amount': {"min": None}
}
mocker.patch( mocker.patch(
'freqtrade.exchange.Exchange.get_markets', 'freqtrade.exchange.Exchange.markets',
MagicMock(return_value=[{ PropertyMock(return_value=markets)
'symbol': 'ETH/BTC',
'limits': {
'cost': {},
'amount': {"min": None}
}
}])
) )
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1) result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1)
assert result is None assert result is None
# empty 'cost'/'amount' section # empty 'cost'/'amount' section
markets["ETH/BTC"]["limits"] = {
'cost': {},
'amount': {}
}
mocker.patch( mocker.patch(
'freqtrade.exchange.Exchange.get_markets', 'freqtrade.exchange.Exchange.markets',
MagicMock(return_value=[{ PropertyMock(return_value=markets)
'symbol': 'ETH/BTC',
'limits': {
'cost': {},
'amount': {}
}
}])
) )
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1) result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1)
assert result is None assert result is None
# min cost is set # min cost is set
markets["ETH/BTC"]["limits"] = {
'cost': {'min': 2},
'amount': {}
}
mocker.patch( mocker.patch(
'freqtrade.exchange.Exchange.get_markets', 'freqtrade.exchange.Exchange.markets',
MagicMock(return_value=[{ PropertyMock(return_value=markets)
'symbol': 'ETH/BTC',
'limits': {
'cost': {'min': 2},
'amount': {}
}
}])
) )
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1) result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1)
assert result == 2 / 0.9 assert result == 2 / 0.9
# min amount is set # min amount is set
markets["ETH/BTC"]["limits"] = {
'cost': {},
'amount': {'min': 2}
}
mocker.patch( mocker.patch(
'freqtrade.exchange.Exchange.get_markets', 'freqtrade.exchange.Exchange.markets',
MagicMock(return_value=[{ PropertyMock(return_value=markets)
'symbol': 'ETH/BTC',
'limits': {
'cost': {},
'amount': {'min': 2}
}
}])
) )
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 2) result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 2)
assert result == 2 * 2 / 0.9 assert result == 2 * 2 / 0.9
# min amount and cost are set (cost is minimal) # min amount and cost are set (cost is minimal)
markets["ETH/BTC"]["limits"] = {
'cost': {'min': 2},
'amount': {'min': 2}
}
mocker.patch( mocker.patch(
'freqtrade.exchange.Exchange.get_markets', 'freqtrade.exchange.Exchange.markets',
MagicMock(return_value=[{ PropertyMock(return_value=markets)
'symbol': 'ETH/BTC',
'limits': {
'cost': {'min': 2},
'amount': {'min': 2}
}
}])
) )
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 2) result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 2)
assert result == min(2, 2 * 2) / 0.9 assert result == min(2, 2 * 2) / 0.9
# min amount and cost are set (amount is minial) # min amount and cost are set (amount is minial)
markets["ETH/BTC"]["limits"] = {
'cost': {'min': 8},
'amount': {'min': 2}
}
mocker.patch( mocker.patch(
'freqtrade.exchange.Exchange.get_markets', 'freqtrade.exchange.Exchange.markets',
MagicMock(return_value=[{ PropertyMock(return_value=markets)
'symbol': 'ETH/BTC',
'limits': {
'cost': {'min': 8},
'amount': {'min': 2}
}
}])
) )
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 2) result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 2)
assert result == min(8, 2 * 2) / 0.9 assert result == min(8, 2 * 2) / 0.9
@ -487,7 +463,7 @@ def test_create_trade(default_conf, ticker, limit_buy_order, fee, markets, mocke
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
# Save state of current whitelist # Save state of current whitelist
@ -522,7 +498,7 @@ def test_create_trade_no_stake_amount(default_conf, ticker, limit_buy_order,
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
@ -541,7 +517,7 @@ def test_create_trade_minimal_amount(default_conf, ticker, limit_buy_order,
get_ticker=ticker, get_ticker=ticker,
buy=buy_mock, buy=buy_mock,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
default_conf['stake_amount'] = 0.0005 default_conf['stake_amount'] = 0.0005
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
@ -562,7 +538,7 @@ def test_create_trade_too_small_stake_amount(default_conf, ticker, limit_buy_ord
get_ticker=ticker, get_ticker=ticker,
buy=buy_mock, buy=buy_mock,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
default_conf['stake_amount'] = 0.000000005 default_conf['stake_amount'] = 0.000000005
@ -583,7 +559,7 @@ def test_create_trade_limit_reached(default_conf, ticker, limit_buy_order,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_balance=MagicMock(return_value=default_conf['stake_amount']), get_balance=MagicMock(return_value=default_conf['stake_amount']),
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
default_conf['max_open_trades'] = 0 default_conf['max_open_trades'] = 0
default_conf['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT default_conf['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT
@ -603,7 +579,7 @@ def test_create_trade_no_pairs(default_conf, ticker, limit_buy_order, fee, marke
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
default_conf['exchange']['pair_whitelist'] = ["ETH/BTC"] default_conf['exchange']['pair_whitelist'] = ["ETH/BTC"]
@ -626,7 +602,7 @@ def test_create_trade_no_pairs_after_blacklist(default_conf, ticker,
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
default_conf['exchange']['pair_whitelist'] = ["ETH/BTC"] default_conf['exchange']['pair_whitelist'] = ["ETH/BTC"]
default_conf['exchange']['pair_blacklist'] = ["ETH/BTC"] default_conf['exchange']['pair_blacklist'] = ["ETH/BTC"]
@ -665,7 +641,7 @@ def test_process_trade_creation(default_conf, ticker, limit_buy_order,
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_markets=markets, markets=PropertyMock(return_value=markets),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_order=MagicMock(return_value=limit_buy_order), get_order=MagicMock(return_value=limit_buy_order),
get_fee=fee, get_fee=fee,
@ -702,7 +678,7 @@ def test_process_exchange_failures(default_conf, ticker, markets, mocker) -> Non
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_markets=markets, markets=PropertyMock(return_value=markets),
buy=MagicMock(side_effect=TemporaryError) buy=MagicMock(side_effect=TemporaryError)
) )
sleep_mock = mocker.patch('time.sleep', side_effect=lambda _: None) sleep_mock = mocker.patch('time.sleep', side_effect=lambda _: None)
@ -721,7 +697,7 @@ def test_process_operational_exception(default_conf, ticker, markets, mocker) ->
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_markets=markets, markets=PropertyMock(return_value=markets),
buy=MagicMock(side_effect=OperationalException) buy=MagicMock(side_effect=OperationalException)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
@ -742,7 +718,7 @@ def test_process_trade_handling(
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_markets=markets, markets=PropertyMock(return_value=markets),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_order=MagicMock(return_value=limit_buy_order), get_order=MagicMock(return_value=limit_buy_order),
get_fee=fee, get_fee=fee,
@ -769,7 +745,7 @@ def test_process_trade_no_whitelist_pair(
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_markets=markets, markets=PropertyMock(return_value=markets),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_order=MagicMock(return_value=limit_buy_order), get_order=MagicMock(return_value=limit_buy_order),
get_fee=fee, get_fee=fee,
@ -818,7 +794,7 @@ def test_process_informative_pairs_added(default_conf, ticker, markets, mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_ticker=ticker, get_ticker=ticker,
get_markets=markets, markets=PropertyMock(return_value=markets),
buy=MagicMock(side_effect=TemporaryError), buy=MagicMock(side_effect=TemporaryError),
refresh_latest_ohlcv=refresh_mock, refresh_latest_ohlcv=refresh_mock,
) )
@ -886,7 +862,7 @@ def test_execute_buy(mocker, default_conf, fee, markets, limit_buy_order) -> Non
}), }),
buy=buy_mm, buy=buy_mm,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
pair = 'ETH/BTC' pair = 'ETH/BTC'
print(buy_mm.call_args_list) print(buy_mm.call_args_list)
@ -997,7 +973,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf, fee, caplog,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}), sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets, markets=PropertyMock(return_value=markets),
stoploss_limit=stoploss_limit stoploss_limit=stoploss_limit
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
@ -1066,7 +1042,7 @@ def test_handle_stoploss_on_exchange_trailing(mocker, default_conf, fee, caplog,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}), sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets, markets=PropertyMock(return_value=markets),
stoploss_limit=stoploss_limit stoploss_limit=stoploss_limit
) )
@ -1164,7 +1140,7 @@ def test_tsl_on_exchange_compatible_with_edge(mocker, edge_conf, fee, caplog,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}), sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets, markets=PropertyMock(return_value=markets),
stoploss_limit=stoploss_limit stoploss_limit=stoploss_limit
) )
@ -1348,7 +1324,7 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}), sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
@ -1386,7 +1362,7 @@ def test_handle_overlpapping_signals(default_conf, ticker, limit_buy_order,
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
@ -1442,7 +1418,7 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order,
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
@ -1475,7 +1451,7 @@ def test_handle_trade_experimental(
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
@ -1503,7 +1479,7 @@ def test_close_trade(default_conf, ticker, limit_buy_order, limit_sell_order,
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
@ -1846,7 +1822,7 @@ def test_execute_sell_up(default_conf, ticker, fee, ticker_sell_up, markets, moc
_load_markets=MagicMock(return_value={}), _load_markets=MagicMock(return_value={}),
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
@ -1891,7 +1867,7 @@ def test_execute_sell_down(default_conf, ticker, fee, ticker_sell_down, markets,
_load_markets=MagicMock(return_value={}), _load_markets=MagicMock(return_value={}),
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
@ -1939,7 +1915,7 @@ def test_execute_sell_down_stoploss_on_exchange_dry_run(default_conf, ticker, fe
_load_markets=MagicMock(return_value={}), _load_markets=MagicMock(return_value={}),
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
@ -1996,7 +1972,7 @@ def test_execute_sell_with_stoploss_on_exchange(default_conf,
_load_markets=MagicMock(return_value={}), _load_markets=MagicMock(return_value={}),
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
stoploss_limit = MagicMock(return_value={ stoploss_limit = MagicMock(return_value={
@ -2051,7 +2027,7 @@ def test_may_execute_sell_after_stoploss_on_exchange_hit(default_conf,
_load_markets=MagicMock(return_value={}), _load_markets=MagicMock(return_value={}),
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
stoploss_limit = MagicMock(return_value={ stoploss_limit = MagicMock(return_value={
@ -2105,7 +2081,7 @@ def test_may_execute_sell_after_stoploss_on_exchange_hit(default_conf,
assert trade.is_open is False assert trade.is_open is False
print(trade.sell_reason) print(trade.sell_reason)
assert trade.sell_reason == SellType.STOPLOSS_ON_EXCHANGE.value assert trade.sell_reason == SellType.STOPLOSS_ON_EXCHANGE.value
assert rpc_mock.call_count == 1 assert rpc_mock.call_count == 2
def test_execute_sell_without_conf_sell_up(default_conf, ticker, fee, def test_execute_sell_without_conf_sell_up(default_conf, ticker, fee,
@ -2116,7 +2092,7 @@ def test_execute_sell_without_conf_sell_up(default_conf, ticker, fee,
_load_markets=MagicMock(return_value={}), _load_markets=MagicMock(return_value={}),
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
@ -2162,7 +2138,7 @@ def test_execute_sell_without_conf_sell_down(default_conf, ticker, fee,
_load_markets=MagicMock(return_value={}), _load_markets=MagicMock(return_value={}),
get_ticker=ticker, get_ticker=ticker,
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)
@ -2213,7 +2189,7 @@ def test_sell_profit_only_enable_profit(default_conf, limit_buy_order,
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
default_conf['experimental'] = { default_conf['experimental'] = {
'use_sell_signal': True, 'use_sell_signal': True,
@ -2245,7 +2221,7 @@ def test_sell_profit_only_disable_profit(default_conf, limit_buy_order,
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
default_conf['experimental'] = { default_conf['experimental'] = {
'use_sell_signal': True, 'use_sell_signal': True,
@ -2275,7 +2251,7 @@ def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, fee, market
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
default_conf['experimental'] = { default_conf['experimental'] = {
'use_sell_signal': True, 'use_sell_signal': True,
@ -2306,7 +2282,7 @@ def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, fee, marke
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
default_conf['experimental'] = { default_conf['experimental'] = {
'use_sell_signal': True, 'use_sell_signal': True,
@ -2338,7 +2314,7 @@ def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order, fee, markets, m
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
default_conf['experimental'] = { default_conf['experimental'] = {
'ignore_roi_if_buy_signal': True 'ignore_roi_if_buy_signal': True
@ -2372,7 +2348,7 @@ def test_trailing_stop_loss(default_conf, limit_buy_order, fee, markets, caplog,
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets, markets=PropertyMock(return_value=markets),
) )
default_conf['trailing_stop'] = True default_conf['trailing_stop'] = True
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
@ -2407,7 +2383,7 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, fee, markets
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets, markets=PropertyMock(return_value=markets),
) )
default_conf['trailing_stop'] = True default_conf['trailing_stop'] = True
default_conf['trailing_stop_positive'] = 0.01 default_conf['trailing_stop_positive'] = 0.01
@ -2465,7 +2441,7 @@ def test_trailing_stop_loss_offset(default_conf, limit_buy_order, fee,
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets, markets=PropertyMock(return_value=markets),
) )
default_conf['trailing_stop'] = True default_conf['trailing_stop'] = True
@ -2591,7 +2567,7 @@ def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order,
}), }),
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
default_conf['experimental'] = { default_conf['experimental'] = {
'ignore_roi_if_buy_signal': False 'ignore_roi_if_buy_signal': False
@ -2826,7 +2802,7 @@ def test_order_book_depth_of_market(default_conf, ticker, limit_buy_order, fee,
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
# Save state of current whitelist # Save state of current whitelist
@ -2862,7 +2838,7 @@ def test_order_book_depth_of_market_high_delta(default_conf, ticker, limit_buy_o
get_ticker=ticker, get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
# Save state of current whitelist # Save state of current whitelist
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
@ -2882,7 +2858,7 @@ def test_order_book_bid_strategy1(mocker, default_conf, order_book_l2, markets)
ticker_mock = MagicMock(return_value={'ask': 0.045, 'last': 0.046}) ticker_mock = MagicMock(return_value={'ask': 0.045, 'last': 0.046})
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_markets=markets, markets=PropertyMock(return_value=markets),
get_order_book=order_book_l2, get_order_book=order_book_l2,
get_ticker=ticker_mock, get_ticker=ticker_mock,
@ -2907,7 +2883,7 @@ def test_order_book_bid_strategy2(mocker, default_conf, order_book_l2, markets)
ticker_mock = MagicMock(return_value={'ask': 0.042, 'last': 0.046}) ticker_mock = MagicMock(return_value={'ask': 0.042, 'last': 0.046})
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_markets=markets, markets=PropertyMock(return_value=markets),
get_order_book=order_book_l2, get_order_book=order_book_l2,
get_ticker=ticker_mock, get_ticker=ticker_mock,
@ -2931,7 +2907,7 @@ def test_check_depth_of_market_buy(default_conf, mocker, order_book_l2, markets)
patch_exchange(mocker) patch_exchange(mocker)
mocker.patch.multiple( mocker.patch.multiple(
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
get_markets=markets, markets=PropertyMock(return_value=markets),
get_order_book=order_book_l2 get_order_book=order_book_l2
) )
default_conf['telegram']['enabled'] = False default_conf['telegram']['enabled'] = False
@ -2968,7 +2944,7 @@ def test_order_book_ask_strategy(default_conf, limit_buy_order, limit_sell_order
buy=MagicMock(return_value={'id': limit_buy_order['id']}), buy=MagicMock(return_value={'id': limit_buy_order['id']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}), sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee, get_fee=fee,
get_markets=markets markets=PropertyMock(return_value=markets)
) )
freqtrade = FreqtradeBot(default_conf) freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade) patch_get_signal(freqtrade)

View File

@ -4,7 +4,7 @@
flake8==3.7.7 flake8==3.7.7
flake8-type-annotations==0.1.0 flake8-type-annotations==0.1.0
flake8-tidy-imports==2.0.0 flake8-tidy-imports==2.0.0
pytest==4.3.0 pytest==4.3.1
pytest-mock==1.10.1 pytest-mock==1.10.1
pytest-asyncio==0.10.0 pytest-asyncio==0.10.0
pytest-cov==2.6.1 pytest-cov==2.6.1

View File

@ -1,4 +1,4 @@
ccxt==1.18.357 ccxt==1.18.361
SQLAlchemy==1.3.1 SQLAlchemy==1.3.1
python-telegram-bot==11.1.0 python-telegram-bot==11.1.0
arrow==0.13.1 arrow==0.13.1