conflict with develop resolved

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

View File

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

View File

@ -48,6 +48,7 @@ Mandatory Parameters are marked as **Required**.
| `exchange.ccxt_rate_limit` | True | DEPRECATED!! Have CCXT handle Exchange rate limits. Depending on the exchange, having this to false can lead to temporary bans from the exchange.
| `exchange.ccxt_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.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.
| `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).
@ -119,9 +120,10 @@ See the example below:
},
```
Most of the strategy files already include the optimal `minimal_roi`
value. This parameter is optional. If you use it in the configuration file, it will take over the
Most of the strategy files already include the optimal `minimal_roi` value.
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.
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

View File

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

View File

@ -88,6 +88,8 @@ class Exchange(object):
# Holds last candle refreshed time of each pair
self._pairs_last_refresh_time: Dict[Tuple[str, str], int] = {}
# Timestamp of last markets refresh
self._last_markets_refresh: int = 0
# Holds candles
self._klines: Dict[Tuple[str, str], DataFrame] = {}
@ -106,7 +108,12 @@ class Exchange(object):
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
self.validate_pairs(config['exchange']['pair_whitelist'])
self.validate_ordertypes(config.get('order_types', {}))
@ -167,6 +174,14 @@ class Exchange(object):
"""exchange ccxt 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:
if pair_interval in self._klines:
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")
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:
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:
logger.warning('Could not load async markets. Reason: %s', e)
return
def _load_markets(self) -> Dict[str, Any]:
def _load_markets(self) -> None:
""" Initialize markets both sync and async """
try:
markets = self._api.load_markets()
self._api.load_markets()
self._load_async_markets()
return markets
self._last_markets_refresh = arrow.utcnow().timestamp
except ccxt.BaseError as 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:
"""
@ -223,7 +249,7 @@ class Exchange(object):
f'Pair {pair} not compatible with stake_currency: {stake_cur}')
if self.markets and pair not in self.markets:
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.')
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
Rounded down
'''
if self._api.markets[pair]['precision']['amount']:
symbol_prec = self._api.markets[pair]['precision']['amount']
if self.markets[pair]['precision']['amount']:
symbol_prec = self.markets[pair]['precision']['amount']
big_amount = amount * pow(10, symbol_prec)
amount = floor(big_amount) / pow(10, symbol_prec)
return amount
@ -306,8 +332,8 @@ class Exchange(object):
Returns the price buying or selling with to the precision the Exchange accepts
Rounds up
'''
if self._api.markets[pair]['precision']['price']:
symbol_prec = self._api.markets[pair]['precision']['price']
if self.markets[pair]['precision']['price']:
symbol_prec = self.markets[pair]['precision']['price']
big_price = price * pow(10, symbol_prec)
price = ceil(big_price) / pow(10, symbol_prec)
return price
@ -678,16 +704,6 @@ class Exchange(object):
except ccxt.BaseError as 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
def get_fee(self, symbol='ETH/BTC', type='', side='', amount=1,
price=1, taker_or_maker='maker') -> float:

View File

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

View File

@ -66,12 +66,14 @@ class IPairList(ABC):
black_listed
"""
sanitized_whitelist = whitelist
markets = self._freqtrade.exchange.get_markets()
markets = self._freqtrade.exchange.markets
# 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()
# TODO: we should loop over whitelist instead of all markets
for market in markets:
pair = market['symbol']
# pair is not in the generated dynamic market, or in the blacklist ... ignore it

View File

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

View File

@ -31,7 +31,11 @@ class IResolver(object):
# Generate spec based on absolute path
spec = importlib.util.spec_from_file_location('unknown', str(module_path))
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 = (
obj for name, obj in inspect.getmembers(module, inspect.isclass)

View File

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

View File

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

View File

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

View File

@ -152,10 +152,7 @@ def test_symbol_amount_prec(default_conf, mocker):
markets = PropertyMock(return_value={'ETH/BTC': {'precision': {'amount': 4}}})
type(api_mock).markets = markets
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())
exchange = Exchange(default_conf)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
amount = 2.34559
pair = 'ETH/BTC'
@ -176,10 +173,7 @@ def test_symbol_price_prec(default_conf, mocker):
markets = PropertyMock(return_value={'ETH/BTC': {'precision': {'price': 4}}})
type(api_mock).markets = markets
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())
exchange = Exchange(default_conf)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
price = 2.34559
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",
'api': 'https://api.gdax.com'})
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())
exchange = Exchange(default_conf)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
liveurl = exchange._api.urls['api']
default_conf['exchange']['sandbox'] = True
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'})
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'):
exchange = Exchange(default_conf)
exchange = get_patched_exchange(mocker, default_conf, api_mock)
default_conf['exchange']['sandbox'] = True
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):
caplog.set_level(logging.INFO)
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())
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)
assert log_has('Unable to initialize markets. Reason: ', caplog.record_tuples)
def test_validate_pairs(default_conf, mocker):
expected_return = {'ETH/BTC': 'available'}
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': ''
})
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):
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.validate_timeframes', 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):
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': ''
})
default_conf['stake_currency'] = 'ETH'
@ -310,15 +323,15 @@ def test_validate_pairs_exception(default_conf, mocker, caplog):
api_mock = MagicMock()
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.validate_timeframes', 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)
mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={}))
mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value={}))
Exchange(default_conf)
assert log_has('Unable to validate pairs (assuming they are correct).',
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._load_markets', MagicMock(return_value={}))
mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock())
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._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.*'):
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._load_markets', MagicMock(return_value={}))
mocker.patch('freqtrade.exchange.Exchange.validate_pairs', MagicMock())
Exchange(default_conf)
@ -395,6 +411,7 @@ def test_validate_order_types(default_conf, mocker):
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._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.name', 'Bittrex')
default_conf['order_types'] = {
@ -463,6 +480,7 @@ def test_validate_order_types_not_in_config(default_conf, mocker):
api_mock = MagicMock()
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.validate_pairs', MagicMock())
mocker.patch('freqtrade.exchange.Exchange.validate_timeframes', MagicMock())
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) == []
@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)
def test_get_fee(default_conf, mocker, exchange_name):
api_mock = MagicMock()

View File

@ -1,6 +1,6 @@
# 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.constants import AVAILABLE_PAIRLISTS
@ -33,7 +33,7 @@ def whitelist_conf(default_conf):
def test_load_pairlist_noexist(mocker, markets, 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,
match=r"Impossible to load Pairlist 'NonexistingPairList'."
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)
mocker.patch('freqtrade.exchange.Exchange.get_markets', markets)
mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets))
freqtradebot.pairlists.refresh_pairlist()
# List ordered by BaseVolume
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):
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()
# List ordered by BaseVolume
whitelist = ['ETH/BTC', 'TKN/BTC']
@ -73,7 +73,7 @@ def test_refresh_pairlist_dynamic(mocker, markets, tickers, whitelist_conf):
}
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_markets=markets,
markets=PropertyMock(return_value=markets),
get_tickers=tickers,
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):
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
whitelist = []
@ -111,7 +111,7 @@ def test_VolumePairList_whitelist_gen(mocker, whitelist_conf, markets, tickers)
whitelist_conf['pairlist']['method'] = 'VolumePairList'
mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True))
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.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)
def test_pairlist_class(mocker, whitelist_conf, markets, 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))
freqtrade = get_patched_freqtradebot(mocker, whitelist_conf)

View File

@ -2,7 +2,7 @@
# pragma pylint: disable=invalid-sequence-index, invalid-name, too-many-arguments
from datetime import datetime
from unittest.mock import MagicMock, ANY
from unittest.mock import MagicMock, ANY, PropertyMock
import pytest
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={}),
get_ticker=ticker,
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
freqtradebot = FreqtradeBot(default_conf)
@ -90,7 +90,7 @@ def test_rpc_status_table(default_conf, ticker, fee, markets, mocker) -> None:
'freqtrade.exchange.Exchange',
get_ticker=ticker,
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
freqtradebot = FreqtradeBot(default_conf)
@ -126,7 +126,7 @@ def test_rpc_daily_profit(default_conf, update, ticker, fee,
'freqtrade.exchange.Exchange',
get_ticker=ticker,
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
freqtradebot = FreqtradeBot(default_conf)
@ -180,7 +180,7 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
'freqtrade.exchange.Exchange',
get_ticker=ticker,
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
freqtradebot = FreqtradeBot(default_conf)
@ -268,7 +268,7 @@ def test_rpc_trade_statistics_closed(mocker, default_conf, ticker, fee, markets,
'freqtrade.exchange.Exchange',
get_ticker=ticker,
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
freqtradebot = FreqtradeBot(default_conf)
@ -424,7 +424,7 @@ def test_rpc_forcesell(default_conf, ticker, fee, mocker, markets) -> None:
}
),
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
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_ticker=ticker,
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
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_ticker=ticker,
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
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_ticker=ticker,
get_fee=fee,
get_markets=markets,
markets=PropertyMock(return_value=markets),
buy=buy_mm
)

View File

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

View File

@ -5,7 +5,7 @@ import logging
import re
import time
from copy import deepcopy
from unittest.mock import MagicMock
from unittest.mock import MagicMock, PropertyMock
import arrow
import pytest
@ -59,7 +59,8 @@ def patch_RPCManager(mocker) -> MagicMock:
# 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)
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:
mock_cleanup = MagicMock()
mocker.patch('freqtrade.persistence.cleanup', mock_cleanup)
freqtrade = get_patched_freqtradebot(mocker, default_conf)
freqtrade.cleanup()
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'])
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
validate_pairs=MagicMock(),
markets=PropertyMock(return_value=markets),
get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
get_markets=markets
get_fee=fee
)
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']}),
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']}),
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,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade)
@ -349,131 +348,108 @@ def test_get_min_pair_stake_amount(mocker, default_conf) -> None:
patch_exchange(mocker)
freqtrade = FreqtradeBot(default_conf)
freqtrade.strategy.stoploss = -0.05
markets = {'ETH/BTC': {'symbol': 'ETH/BTC'}}
# no pair found
mocker.patch(
'freqtrade.exchange.Exchange.get_markets',
MagicMock(return_value=[{
'symbol': 'ETH/BTC'
}])
'freqtrade.exchange.Exchange.markets',
PropertyMock(return_value=markets)
)
with pytest.raises(ValueError, match=r'.*get market information.*'):
freqtrade._get_min_pair_stake_amount('BNB/BTC', 1)
# 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)
assert result is None
# empty 'limits' section
markets["ETH/BTC"]["limits"] = {}
mocker.patch(
'freqtrade.exchange.Exchange.get_markets',
MagicMock(return_value=[{
'symbol': 'ETH/BTC',
'limits': {}
}])
'freqtrade.exchange.Exchange.markets',
PropertyMock(return_value=markets)
)
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1)
assert result is None
# no cost Min
markets["ETH/BTC"]["limits"] = {
'cost': {"min": None},
'amount': {}
}
mocker.patch(
'freqtrade.exchange.Exchange.get_markets',
MagicMock(return_value=[{
'symbol': 'ETH/BTC',
'limits': {
'cost': {"min": None},
'amount': {}
}
}])
'freqtrade.exchange.Exchange.markets',
PropertyMock(return_value=markets)
)
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1)
assert result is None
# no amount Min
markets["ETH/BTC"]["limits"] = {
'cost': {},
'amount': {"min": None}
}
mocker.patch(
'freqtrade.exchange.Exchange.get_markets',
MagicMock(return_value=[{
'symbol': 'ETH/BTC',
'limits': {
'cost': {},
'amount': {"min": None}
}
}])
'freqtrade.exchange.Exchange.markets',
PropertyMock(return_value=markets)
)
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1)
assert result is None
# empty 'cost'/'amount' section
markets["ETH/BTC"]["limits"] = {
'cost': {},
'amount': {}
}
mocker.patch(
'freqtrade.exchange.Exchange.get_markets',
MagicMock(return_value=[{
'symbol': 'ETH/BTC',
'limits': {
'cost': {},
'amount': {}
}
}])
'freqtrade.exchange.Exchange.markets',
PropertyMock(return_value=markets)
)
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1)
assert result is None
# min cost is set
markets["ETH/BTC"]["limits"] = {
'cost': {'min': 2},
'amount': {}
}
mocker.patch(
'freqtrade.exchange.Exchange.get_markets',
MagicMock(return_value=[{
'symbol': 'ETH/BTC',
'limits': {
'cost': {'min': 2},
'amount': {}
}
}])
'freqtrade.exchange.Exchange.markets',
PropertyMock(return_value=markets)
)
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 1)
assert result == 2 / 0.9
# min amount is set
markets["ETH/BTC"]["limits"] = {
'cost': {},
'amount': {'min': 2}
}
mocker.patch(
'freqtrade.exchange.Exchange.get_markets',
MagicMock(return_value=[{
'symbol': 'ETH/BTC',
'limits': {
'cost': {},
'amount': {'min': 2}
}
}])
'freqtrade.exchange.Exchange.markets',
PropertyMock(return_value=markets)
)
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 2)
assert result == 2 * 2 / 0.9
# min amount and cost are set (cost is minimal)
markets["ETH/BTC"]["limits"] = {
'cost': {'min': 2},
'amount': {'min': 2}
}
mocker.patch(
'freqtrade.exchange.Exchange.get_markets',
MagicMock(return_value=[{
'symbol': 'ETH/BTC',
'limits': {
'cost': {'min': 2},
'amount': {'min': 2}
}
}])
'freqtrade.exchange.Exchange.markets',
PropertyMock(return_value=markets)
)
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 2)
assert result == min(2, 2 * 2) / 0.9
# min amount and cost are set (amount is minial)
markets["ETH/BTC"]["limits"] = {
'cost': {'min': 8},
'amount': {'min': 2}
}
mocker.patch(
'freqtrade.exchange.Exchange.get_markets',
MagicMock(return_value=[{
'symbol': 'ETH/BTC',
'limits': {
'cost': {'min': 8},
'amount': {'min': 2}
}
}])
'freqtrade.exchange.Exchange.markets',
PropertyMock(return_value=markets)
)
result = freqtrade._get_min_pair_stake_amount('ETH/BTC', 2)
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,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
# 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,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade)
@ -541,7 +517,7 @@ def test_create_trade_minimal_amount(default_conf, ticker, limit_buy_order,
get_ticker=ticker,
buy=buy_mock,
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
default_conf['stake_amount'] = 0.0005
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,
buy=buy_mock,
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
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']}),
get_balance=MagicMock(return_value=default_conf['stake_amount']),
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
default_conf['max_open_trades'] = 0
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,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
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,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
default_conf['exchange']['pair_whitelist'] = ["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(
'freqtrade.exchange.Exchange',
get_ticker=ticker,
get_markets=markets,
markets=PropertyMock(return_value=markets),
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_order=MagicMock(return_value=limit_buy_order),
get_fee=fee,
@ -702,7 +678,7 @@ def test_process_exchange_failures(default_conf, ticker, markets, mocker) -> Non
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_ticker=ticker,
get_markets=markets,
markets=PropertyMock(return_value=markets),
buy=MagicMock(side_effect=TemporaryError)
)
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(
'freqtrade.exchange.Exchange',
get_ticker=ticker,
get_markets=markets,
markets=PropertyMock(return_value=markets),
buy=MagicMock(side_effect=OperationalException)
)
freqtrade = FreqtradeBot(default_conf)
@ -742,7 +718,7 @@ def test_process_trade_handling(
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_ticker=ticker,
get_markets=markets,
markets=PropertyMock(return_value=markets),
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_order=MagicMock(return_value=limit_buy_order),
get_fee=fee,
@ -769,7 +745,7 @@ def test_process_trade_no_whitelist_pair(
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_ticker=ticker,
get_markets=markets,
markets=PropertyMock(return_value=markets),
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_order=MagicMock(return_value=limit_buy_order),
get_fee=fee,
@ -818,7 +794,7 @@ def test_process_informative_pairs_added(default_conf, ticker, markets, mocker)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_ticker=ticker,
get_markets=markets,
markets=PropertyMock(return_value=markets),
buy=MagicMock(side_effect=TemporaryError),
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,
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
pair = 'ETH/BTC'
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']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee,
get_markets=markets,
markets=PropertyMock(return_value=markets),
stoploss_limit=stoploss_limit
)
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']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee,
get_markets=markets,
markets=PropertyMock(return_value=markets),
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']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee,
get_markets=markets,
markets=PropertyMock(return_value=markets),
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']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade)
@ -1386,7 +1362,7 @@ def test_handle_overlpapping_signals(default_conf, ticker, limit_buy_order,
get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
freqtrade = FreqtradeBot(default_conf)
@ -1442,7 +1418,7 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order,
get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
freqtrade = FreqtradeBot(default_conf)
@ -1475,7 +1451,7 @@ def test_handle_trade_experimental(
get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
freqtrade = FreqtradeBot(default_conf)
@ -1503,7 +1479,7 @@ def test_close_trade(default_conf, ticker, limit_buy_order, limit_sell_order,
get_ticker=ticker,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
freqtrade = FreqtradeBot(default_conf)
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={}),
get_ticker=ticker,
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
freqtrade = FreqtradeBot(default_conf)
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={}),
get_ticker=ticker,
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
freqtrade = FreqtradeBot(default_conf)
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={}),
get_ticker=ticker,
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade)
@ -1996,7 +1972,7 @@ def test_execute_sell_with_stoploss_on_exchange(default_conf,
_load_markets=MagicMock(return_value={}),
get_ticker=ticker,
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
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={}),
get_ticker=ticker,
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
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
print(trade.sell_reason)
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,
@ -2116,7 +2092,7 @@ def test_execute_sell_without_conf_sell_up(default_conf, ticker, fee,
_load_markets=MagicMock(return_value={}),
get_ticker=ticker,
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
freqtrade = FreqtradeBot(default_conf)
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={}),
get_ticker=ticker,
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
freqtrade = FreqtradeBot(default_conf)
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']}),
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
default_conf['experimental'] = {
'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']}),
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
default_conf['experimental'] = {
'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']}),
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
default_conf['experimental'] = {
'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']}),
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
default_conf['experimental'] = {
'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']}),
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
default_conf['experimental'] = {
'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']}),
get_fee=fee,
get_markets=markets,
markets=PropertyMock(return_value=markets),
)
default_conf['trailing_stop'] = True
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']}),
get_fee=fee,
get_markets=markets,
markets=PropertyMock(return_value=markets),
)
default_conf['trailing_stop'] = True
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']}),
get_fee=fee,
get_markets=markets,
markets=PropertyMock(return_value=markets),
)
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']}),
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
default_conf['experimental'] = {
'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,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
# 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,
buy=MagicMock(return_value={'id': limit_buy_order['id']}),
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
# Save state of current whitelist
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})
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_markets=markets,
markets=PropertyMock(return_value=markets),
get_order_book=order_book_l2,
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})
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_markets=markets,
markets=PropertyMock(return_value=markets),
get_order_book=order_book_l2,
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)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_markets=markets,
markets=PropertyMock(return_value=markets),
get_order_book=order_book_l2
)
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']}),
sell=MagicMock(return_value={'id': limit_sell_order['id']}),
get_fee=fee,
get_markets=markets
markets=PropertyMock(return_value=markets)
)
freqtrade = FreqtradeBot(default_conf)
patch_get_signal(freqtrade)

View File

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

View File

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