conflict with develop resolved
This commit is contained in:
commit
9a226ec7e6
@ -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,
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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'}
|
||||||
},
|
},
|
||||||
|
@ -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:
|
||||||
|
@ -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()
|
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
@ -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)
|
||||||
|
@ -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:
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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()
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user