Merge pull request #5284 from samgermain/merge_get_buy_sell_rate
Merge get_buy_rate and get_sell_rate
This commit is contained in:
commit
e4b42b2b5b
@ -551,7 +551,7 @@ class Exchange:
|
|||||||
amount_reserve_percent = 1.0 + self._config.get('amount_reserve_percent',
|
amount_reserve_percent = 1.0 + self._config.get('amount_reserve_percent',
|
||||||
DEFAULT_AMOUNT_RESERVE_PERCENT)
|
DEFAULT_AMOUNT_RESERVE_PERCENT)
|
||||||
amount_reserve_percent = (
|
amount_reserve_percent = (
|
||||||
amount_reserve_percent / (1 - abs(stoploss)) if abs(stoploss) != 1 else 1.5
|
amount_reserve_percent / (1 - abs(stoploss)) if abs(stoploss) != 1 else 1.5
|
||||||
)
|
)
|
||||||
# it should not be more than 50%
|
# it should not be more than 50%
|
||||||
amount_reserve_percent = max(min(amount_reserve_percent, 1.5), 1)
|
amount_reserve_percent = max(min(amount_reserve_percent, 1.5), 1)
|
||||||
@ -999,94 +999,64 @@ class Exchange:
|
|||||||
except ccxt.BaseError as e:
|
except ccxt.BaseError as e:
|
||||||
raise OperationalException(e) from e
|
raise OperationalException(e) from e
|
||||||
|
|
||||||
def get_buy_rate(self, pair: str, refresh: bool) -> float:
|
def get_rate(self, pair: str, refresh: bool, side: str) -> float:
|
||||||
"""
|
"""
|
||||||
Calculates bid target between current ask price and last price
|
Calculates bid/ask target
|
||||||
|
bid rate - between current ask price and last price
|
||||||
|
ask rate - either using ticker bid or first bid based on orderbook
|
||||||
|
or remain static in any other case since it's not updating.
|
||||||
:param pair: Pair to get rate for
|
:param pair: Pair to get rate for
|
||||||
:param refresh: allow cached data
|
:param refresh: allow cached data
|
||||||
|
:param side: "buy" or "sell"
|
||||||
:return: float: Price
|
:return: float: Price
|
||||||
:raises PricingError if orderbook price could not be determined.
|
:raises PricingError if orderbook price could not be determined.
|
||||||
"""
|
"""
|
||||||
|
cache_rate: TTLCache = self._buy_rate_cache if side == "buy" else self._sell_rate_cache
|
||||||
|
[strat_name, name] = ['bid_strategy', 'Buy'] if side == "buy" else ['ask_strategy', 'Sell']
|
||||||
|
|
||||||
if not refresh:
|
if not refresh:
|
||||||
rate = self._buy_rate_cache.get(pair)
|
rate = cache_rate.get(pair)
|
||||||
# Check if cache has been invalidated
|
# Check if cache has been invalidated
|
||||||
if rate:
|
if rate:
|
||||||
logger.debug(f"Using cached buy rate for {pair}.")
|
logger.debug(f"Using cached {side} rate for {pair}.")
|
||||||
return rate
|
return rate
|
||||||
|
|
||||||
bid_strategy = self._config.get('bid_strategy', {})
|
conf_strategy = self._config.get(strat_name, {})
|
||||||
if 'use_order_book' in bid_strategy and bid_strategy.get('use_order_book', False):
|
|
||||||
|
|
||||||
order_book_top = bid_strategy.get('order_book_top', 1)
|
if conf_strategy.get('use_order_book', False) and ('use_order_book' in conf_strategy):
|
||||||
|
|
||||||
|
order_book_top = conf_strategy.get('order_book_top', 1)
|
||||||
order_book = self.fetch_l2_order_book(pair, order_book_top)
|
order_book = self.fetch_l2_order_book(pair, order_book_top)
|
||||||
logger.debug('order_book %s', order_book)
|
logger.debug('order_book %s', order_book)
|
||||||
# top 1 = index 0
|
# top 1 = index 0
|
||||||
try:
|
try:
|
||||||
rate_from_l2 = order_book[f"{bid_strategy['price_side']}s"][order_book_top - 1][0]
|
rate = order_book[f"{conf_strategy['price_side']}s"][order_book_top - 1][0]
|
||||||
except (IndexError, KeyError) as e:
|
except (IndexError, KeyError) as e:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Buy Price from orderbook could not be determined."
|
f"{name} Price at location {order_book_top} from orderbook could not be "
|
||||||
f"Orderbook: {order_book}"
|
|
||||||
)
|
|
||||||
raise PricingError from e
|
|
||||||
logger.info(f"Buy price from orderbook {bid_strategy['price_side'].capitalize()} side "
|
|
||||||
f"- top {order_book_top} order book buy rate {rate_from_l2:.8f}")
|
|
||||||
used_rate = rate_from_l2
|
|
||||||
else:
|
|
||||||
logger.info(f"Using Last {bid_strategy['price_side'].capitalize()} / Last Price")
|
|
||||||
ticker = self.fetch_ticker(pair)
|
|
||||||
ticker_rate = ticker[bid_strategy['price_side']]
|
|
||||||
if ticker['last'] and ticker_rate > ticker['last']:
|
|
||||||
balance = bid_strategy['ask_last_balance']
|
|
||||||
ticker_rate = ticker_rate + balance * (ticker['last'] - ticker_rate)
|
|
||||||
used_rate = ticker_rate
|
|
||||||
|
|
||||||
self._buy_rate_cache[pair] = used_rate
|
|
||||||
|
|
||||||
return used_rate
|
|
||||||
|
|
||||||
def get_sell_rate(self, pair: str, refresh: bool) -> float:
|
|
||||||
"""
|
|
||||||
Get sell rate - either using ticker bid or first bid based on orderbook
|
|
||||||
or remain static in any other case since it's not updating.
|
|
||||||
:param pair: Pair to get rate for
|
|
||||||
:param refresh: allow cached data
|
|
||||||
:return: Bid rate
|
|
||||||
:raises PricingError if price could not be determined.
|
|
||||||
"""
|
|
||||||
if not refresh:
|
|
||||||
rate = self._sell_rate_cache.get(pair)
|
|
||||||
# Check if cache has been invalidated
|
|
||||||
if rate:
|
|
||||||
logger.debug(f"Using cached sell rate for {pair}.")
|
|
||||||
return rate
|
|
||||||
|
|
||||||
ask_strategy = self._config.get('ask_strategy', {})
|
|
||||||
if ask_strategy.get('use_order_book', False):
|
|
||||||
logger.debug(
|
|
||||||
f"Getting price from order book {ask_strategy['price_side'].capitalize()} side."
|
|
||||||
)
|
|
||||||
order_book_top = ask_strategy.get('order_book_top', 1)
|
|
||||||
order_book = self.fetch_l2_order_book(pair, order_book_top)
|
|
||||||
try:
|
|
||||||
rate = order_book[f"{ask_strategy['price_side']}s"][order_book_top - 1][0]
|
|
||||||
except (IndexError, KeyError) as e:
|
|
||||||
logger.warning(
|
|
||||||
f"Sell Price at location {order_book_top} from orderbook could not be "
|
|
||||||
f"determined. Orderbook: {order_book}"
|
f"determined. Orderbook: {order_book}"
|
||||||
)
|
)
|
||||||
raise PricingError from e
|
raise PricingError from e
|
||||||
|
|
||||||
|
logger.info(f"{name} price from orderbook {conf_strategy['price_side'].capitalize()}"
|
||||||
|
f"side - top {order_book_top} order book {side} rate {rate:.8f}")
|
||||||
else:
|
else:
|
||||||
|
logger.info(f"Using Last {conf_strategy['price_side'].capitalize()} / Last Price")
|
||||||
ticker = self.fetch_ticker(pair)
|
ticker = self.fetch_ticker(pair)
|
||||||
ticker_rate = ticker[ask_strategy['price_side']]
|
ticker_rate = ticker[conf_strategy['price_side']]
|
||||||
if ticker['last'] and ticker_rate < ticker['last']:
|
if ticker['last']:
|
||||||
balance = ask_strategy.get('bid_last_balance', 0.0)
|
if side == 'buy' and ticker_rate > ticker['last']:
|
||||||
ticker_rate = ticker_rate - balance * (ticker_rate - ticker['last'])
|
balance = conf_strategy['ask_last_balance']
|
||||||
|
ticker_rate = ticker_rate + balance * (ticker['last'] - ticker_rate)
|
||||||
|
elif side == 'sell' and ticker_rate < ticker['last']:
|
||||||
|
balance = conf_strategy.get('bid_last_balance', 0.0)
|
||||||
|
ticker_rate = ticker_rate - balance * (ticker_rate - ticker['last'])
|
||||||
rate = ticker_rate
|
rate = ticker_rate
|
||||||
|
|
||||||
if rate is None:
|
if rate is None:
|
||||||
raise PricingError(f"Sell-Rate for {pair} was empty.")
|
raise PricingError(f"{name}-Rate for {pair} was empty.")
|
||||||
self._sell_rate_cache[pair] = rate
|
cache_rate[pair] = rate
|
||||||
|
|
||||||
return rate
|
return rate
|
||||||
|
|
||||||
# Fee handling
|
# Fee handling
|
||||||
@ -1318,8 +1288,8 @@ class Exchange:
|
|||||||
self._pairs_last_refresh_time[(pair, timeframe)] = ticks[-1][0] // 1000
|
self._pairs_last_refresh_time[(pair, timeframe)] = ticks[-1][0] // 1000
|
||||||
# keeping parsed dataframe in cache
|
# keeping parsed dataframe in cache
|
||||||
ohlcv_df = ohlcv_to_dataframe(
|
ohlcv_df = ohlcv_to_dataframe(
|
||||||
ticks, timeframe, pair=pair, fill_missing=True,
|
ticks, timeframe, pair=pair, fill_missing=True,
|
||||||
drop_incomplete=self._ohlcv_partial_candle)
|
drop_incomplete=self._ohlcv_partial_candle)
|
||||||
results_df[(pair, timeframe)] = ohlcv_df
|
results_df[(pair, timeframe)] = ohlcv_df
|
||||||
if cache:
|
if cache:
|
||||||
self._klines[(pair, timeframe)] = ohlcv_df
|
self._klines[(pair, timeframe)] = ohlcv_df
|
||||||
|
@ -475,7 +475,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
buy_limit_requested = price
|
buy_limit_requested = price
|
||||||
else:
|
else:
|
||||||
# Calculate price
|
# Calculate price
|
||||||
buy_limit_requested = self.exchange.get_buy_rate(pair, True)
|
buy_limit_requested = self.exchange.get_rate(pair, refresh=True, side="buy")
|
||||||
|
|
||||||
if not buy_limit_requested:
|
if not buy_limit_requested:
|
||||||
raise PricingError('Could not determine buy price.')
|
raise PricingError('Could not determine buy price.')
|
||||||
@ -609,7 +609,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
"""
|
"""
|
||||||
Sends rpc notification when a buy cancel occurred.
|
Sends rpc notification when a buy cancel occurred.
|
||||||
"""
|
"""
|
||||||
current_rate = self.exchange.get_buy_rate(trade.pair, False)
|
current_rate = self.exchange.get_rate(trade.pair, refresh=False, side="buy")
|
||||||
|
|
||||||
msg = {
|
msg = {
|
||||||
'trade_id': trade.id,
|
'trade_id': trade.id,
|
||||||
@ -695,7 +695,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
(buy, sell) = self.strategy.get_signal(trade.pair, self.strategy.timeframe, analyzed_df)
|
(buy, sell) = self.strategy.get_signal(trade.pair, self.strategy.timeframe, analyzed_df)
|
||||||
|
|
||||||
logger.debug('checking sell')
|
logger.debug('checking sell')
|
||||||
sell_rate = self.exchange.get_sell_rate(trade.pair, True)
|
sell_rate = self.exchange.get_rate(trade.pair, refresh=True, side="sell")
|
||||||
if self._check_and_execute_sell(trade, sell_rate, buy, sell):
|
if self._check_and_execute_sell(trade, sell_rate, buy, sell):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -1132,7 +1132,8 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
profit_rate = trade.close_rate if trade.close_rate else trade.close_rate_requested
|
profit_rate = trade.close_rate if trade.close_rate else trade.close_rate_requested
|
||||||
profit_trade = trade.calc_profit(rate=profit_rate)
|
profit_trade = trade.calc_profit(rate=profit_rate)
|
||||||
# Use cached rates here - it was updated seconds ago.
|
# Use cached rates here - it was updated seconds ago.
|
||||||
current_rate = self.exchange.get_sell_rate(trade.pair, False) if not fill else None
|
current_rate = self.exchange.get_rate(
|
||||||
|
trade.pair, refresh=False, side="sell") if not fill else None
|
||||||
profit_ratio = trade.calc_profit_ratio(profit_rate)
|
profit_ratio = trade.calc_profit_ratio(profit_rate)
|
||||||
gain = "profit" if profit_ratio > 0 else "loss"
|
gain = "profit" if profit_ratio > 0 else "loss"
|
||||||
|
|
||||||
@ -1177,7 +1178,7 @@ class FreqtradeBot(LoggingMixin):
|
|||||||
|
|
||||||
profit_rate = trade.close_rate if trade.close_rate else trade.close_rate_requested
|
profit_rate = trade.close_rate if trade.close_rate else trade.close_rate_requested
|
||||||
profit_trade = trade.calc_profit(rate=profit_rate)
|
profit_trade = trade.calc_profit(rate=profit_rate)
|
||||||
current_rate = self.exchange.get_sell_rate(trade.pair, False)
|
current_rate = self.exchange.get_rate(trade.pair, refresh=False, side="sell")
|
||||||
profit_ratio = trade.calc_profit_ratio(profit_rate)
|
profit_ratio = trade.calc_profit_ratio(profit_rate)
|
||||||
gain = "profit" if profit_ratio > 0 else "loss"
|
gain = "profit" if profit_ratio > 0 else "loss"
|
||||||
|
|
||||||
|
@ -154,7 +154,8 @@ class RPC:
|
|||||||
# calculate profit and send message to user
|
# calculate profit and send message to user
|
||||||
if trade.is_open:
|
if trade.is_open:
|
||||||
try:
|
try:
|
||||||
current_rate = self._freqtrade.exchange.get_sell_rate(trade.pair, False)
|
current_rate = self._freqtrade.exchange.get_rate(
|
||||||
|
trade.pair, refresh=False, side="sell")
|
||||||
except (ExchangeError, PricingError):
|
except (ExchangeError, PricingError):
|
||||||
current_rate = NAN
|
current_rate = NAN
|
||||||
else:
|
else:
|
||||||
@ -213,7 +214,8 @@ class RPC:
|
|||||||
for trade in trades:
|
for trade in trades:
|
||||||
# calculate profit and send message to user
|
# calculate profit and send message to user
|
||||||
try:
|
try:
|
||||||
current_rate = self._freqtrade.exchange.get_sell_rate(trade.pair, False)
|
current_rate = self._freqtrade.exchange.get_rate(
|
||||||
|
trade.pair, refresh=False, side="sell")
|
||||||
except (PricingError, ExchangeError):
|
except (PricingError, ExchangeError):
|
||||||
current_rate = NAN
|
current_rate = NAN
|
||||||
trade_percent = (100 * trade.calc_profit_ratio(current_rate))
|
trade_percent = (100 * trade.calc_profit_ratio(current_rate))
|
||||||
@ -272,10 +274,10 @@ class RPC:
|
|||||||
'date': key,
|
'date': key,
|
||||||
'abs_profit': value["amount"],
|
'abs_profit': value["amount"],
|
||||||
'fiat_value': self._fiat_converter.convert_amount(
|
'fiat_value': self._fiat_converter.convert_amount(
|
||||||
value['amount'],
|
value['amount'],
|
||||||
stake_currency,
|
stake_currency,
|
||||||
fiat_display_currency
|
fiat_display_currency
|
||||||
) if self._fiat_converter else 0,
|
) if self._fiat_converter else 0,
|
||||||
'trade_count': value["trades"],
|
'trade_count': value["trades"],
|
||||||
}
|
}
|
||||||
for key, value in profit_days.items()
|
for key, value in profit_days.items()
|
||||||
@ -372,7 +374,8 @@ class RPC:
|
|||||||
else:
|
else:
|
||||||
# Get current rate
|
# Get current rate
|
||||||
try:
|
try:
|
||||||
current_rate = self._freqtrade.exchange.get_sell_rate(trade.pair, False)
|
current_rate = self._freqtrade.exchange.get_rate(
|
||||||
|
trade.pair, refresh=False, side="sell")
|
||||||
except (PricingError, ExchangeError):
|
except (PricingError, ExchangeError):
|
||||||
current_rate = NAN
|
current_rate = NAN
|
||||||
profit_ratio = trade.calc_profit_ratio(rate=current_rate)
|
profit_ratio = trade.calc_profit_ratio(rate=current_rate)
|
||||||
@ -551,7 +554,8 @@ class RPC:
|
|||||||
|
|
||||||
if not fully_canceled:
|
if not fully_canceled:
|
||||||
# Get current rate and execute sell
|
# Get current rate and execute sell
|
||||||
current_rate = self._freqtrade.exchange.get_sell_rate(trade.pair, False)
|
current_rate = self._freqtrade.exchange.get_rate(
|
||||||
|
trade.pair, refresh=False, side="sell")
|
||||||
sell_reason = SellCheckTuple(sell_type=SellType.FORCE_SELL)
|
sell_reason = SellCheckTuple(sell_type=SellType.FORCE_SELL)
|
||||||
self._freqtrade.execute_sell(trade, current_rate, sell_reason)
|
self._freqtrade.execute_sell(trade, current_rate, sell_reason)
|
||||||
# ---- EOF def _exec_forcesell ----
|
# ---- EOF def _exec_forcesell ----
|
||||||
|
@ -1783,14 +1783,14 @@ def test_get_buy_rate(mocker, default_conf, caplog, side, ask, bid,
|
|||||||
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
|
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
|
||||||
return_value={'ask': ask, 'last': last, 'bid': bid})
|
return_value={'ask': ask, 'last': last, 'bid': bid})
|
||||||
|
|
||||||
assert exchange.get_buy_rate('ETH/BTC', True) == expected
|
assert exchange.get_rate('ETH/BTC', refresh=True, side="buy") == expected
|
||||||
assert not log_has("Using cached buy rate for ETH/BTC.", caplog)
|
assert not log_has("Using cached buy rate for ETH/BTC.", caplog)
|
||||||
|
|
||||||
assert exchange.get_buy_rate('ETH/BTC', False) == expected
|
assert exchange.get_rate('ETH/BTC', refresh=False, side="buy") == expected
|
||||||
assert log_has("Using cached buy rate for ETH/BTC.", caplog)
|
assert log_has("Using cached buy rate for ETH/BTC.", caplog)
|
||||||
# Running a 2nd time with Refresh on!
|
# Running a 2nd time with Refresh on!
|
||||||
caplog.clear()
|
caplog.clear()
|
||||||
assert exchange.get_buy_rate('ETH/BTC', True) == expected
|
assert exchange.get_rate('ETH/BTC', refresh=True, side="buy") == expected
|
||||||
assert not log_has("Using cached buy rate for ETH/BTC.", caplog)
|
assert not log_has("Using cached buy rate for ETH/BTC.", caplog)
|
||||||
|
|
||||||
|
|
||||||
@ -1825,12 +1825,12 @@ def test_get_sell_rate(default_conf, mocker, caplog, side, bid, ask,
|
|||||||
|
|
||||||
# Test regular mode
|
# Test regular mode
|
||||||
exchange = get_patched_exchange(mocker, default_conf)
|
exchange = get_patched_exchange(mocker, default_conf)
|
||||||
rate = exchange.get_sell_rate(pair, True)
|
rate = exchange.get_rate(pair, refresh=True, side="sell")
|
||||||
assert not log_has("Using cached sell rate for ETH/BTC.", caplog)
|
assert not log_has("Using cached sell rate for ETH/BTC.", caplog)
|
||||||
assert isinstance(rate, float)
|
assert isinstance(rate, float)
|
||||||
assert rate == expected
|
assert rate == expected
|
||||||
# Use caching
|
# Use caching
|
||||||
rate = exchange.get_sell_rate(pair, False)
|
rate = exchange.get_rate(pair, refresh=False, side="sell")
|
||||||
assert rate == expected
|
assert rate == expected
|
||||||
assert log_has("Using cached sell rate for ETH/BTC.", caplog)
|
assert log_has("Using cached sell rate for ETH/BTC.", caplog)
|
||||||
|
|
||||||
@ -1848,11 +1848,11 @@ def test_get_sell_rate_orderbook(default_conf, mocker, caplog, side, expected, o
|
|||||||
pair = "ETH/BTC"
|
pair = "ETH/BTC"
|
||||||
mocker.patch('freqtrade.exchange.Exchange.fetch_l2_order_book', order_book_l2)
|
mocker.patch('freqtrade.exchange.Exchange.fetch_l2_order_book', order_book_l2)
|
||||||
exchange = get_patched_exchange(mocker, default_conf)
|
exchange = get_patched_exchange(mocker, default_conf)
|
||||||
rate = exchange.get_sell_rate(pair, True)
|
rate = exchange.get_rate(pair, refresh=True, side="sell")
|
||||||
assert not log_has("Using cached sell rate for ETH/BTC.", caplog)
|
assert not log_has("Using cached sell rate for ETH/BTC.", caplog)
|
||||||
assert isinstance(rate, float)
|
assert isinstance(rate, float)
|
||||||
assert rate == expected
|
assert rate == expected
|
||||||
rate = exchange.get_sell_rate(pair, False)
|
rate = exchange.get_rate(pair, refresh=False, side="sell")
|
||||||
assert rate == expected
|
assert rate == expected
|
||||||
assert log_has("Using cached sell rate for ETH/BTC.", caplog)
|
assert log_has("Using cached sell rate for ETH/BTC.", caplog)
|
||||||
|
|
||||||
@ -1868,7 +1868,7 @@ def test_get_sell_rate_orderbook_exception(default_conf, mocker, caplog):
|
|||||||
return_value={'bids': [[]], 'asks': [[]]})
|
return_value={'bids': [[]], 'asks': [[]]})
|
||||||
exchange = get_patched_exchange(mocker, default_conf)
|
exchange = get_patched_exchange(mocker, default_conf)
|
||||||
with pytest.raises(PricingError):
|
with pytest.raises(PricingError):
|
||||||
exchange.get_sell_rate(pair, True)
|
exchange.get_rate(pair, refresh=True, side="sell")
|
||||||
assert log_has_re(r"Sell Price at location 1 from orderbook could not be determined\..*",
|
assert log_has_re(r"Sell Price at location 1 from orderbook could not be determined\..*",
|
||||||
caplog)
|
caplog)
|
||||||
|
|
||||||
@ -1881,18 +1881,18 @@ def test_get_sell_rate_exception(default_conf, mocker, caplog):
|
|||||||
return_value={'ask': None, 'bid': 0.12, 'last': None})
|
return_value={'ask': None, 'bid': 0.12, 'last': None})
|
||||||
exchange = get_patched_exchange(mocker, default_conf)
|
exchange = get_patched_exchange(mocker, default_conf)
|
||||||
with pytest.raises(PricingError, match=r"Sell-Rate for ETH/BTC was empty."):
|
with pytest.raises(PricingError, match=r"Sell-Rate for ETH/BTC was empty."):
|
||||||
exchange.get_sell_rate(pair, True)
|
exchange.get_rate(pair, refresh=True, side="sell")
|
||||||
|
|
||||||
exchange._config['ask_strategy']['price_side'] = 'bid'
|
exchange._config['ask_strategy']['price_side'] = 'bid'
|
||||||
assert exchange.get_sell_rate(pair, True) == 0.12
|
assert exchange.get_rate(pair, refresh=True, side="sell") == 0.12
|
||||||
# Reverse sides
|
# Reverse sides
|
||||||
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
|
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker',
|
||||||
return_value={'ask': 0.13, 'bid': None, 'last': None})
|
return_value={'ask': 0.13, 'bid': None, 'last': None})
|
||||||
with pytest.raises(PricingError, match=r"Sell-Rate for ETH/BTC was empty."):
|
with pytest.raises(PricingError, match=r"Sell-Rate for ETH/BTC was empty."):
|
||||||
exchange.get_sell_rate(pair, True)
|
exchange.get_rate(pair, refresh=True, side="sell")
|
||||||
|
|
||||||
exchange._config['ask_strategy']['price_side'] = 'ask'
|
exchange._config['ask_strategy']['price_side'] = 'ask'
|
||||||
assert exchange.get_sell_rate(pair, True) == 0.13
|
assert exchange.get_rate(pair, refresh=True, side="sell") == 0.13
|
||||||
|
|
||||||
|
|
||||||
def make_fetch_ohlcv_mock(data):
|
def make_fetch_ohlcv_mock(data):
|
||||||
@ -2203,7 +2203,7 @@ def test_cancel_order_dry_run(default_conf, mocker, exchange_name):
|
|||||||
({'status': 'canceled', 'filled': 10.0}, False),
|
({'status': 'canceled', 'filled': 10.0}, False),
|
||||||
({'status': 'unknown', 'filled': 10.0}, False),
|
({'status': 'unknown', 'filled': 10.0}, False),
|
||||||
({'result': 'testest123'}, False),
|
({'result': 'testest123'}, False),
|
||||||
])
|
])
|
||||||
def test_check_order_canceled_empty(mocker, default_conf, exchange_name, order, result):
|
def test_check_order_canceled_empty(mocker, default_conf, exchange_name, order, result):
|
||||||
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
exchange = get_patched_exchange(mocker, default_conf, id=exchange_name)
|
||||||
assert exchange.check_order_canceled_empty(order) == result
|
assert exchange.check_order_canceled_empty(order) == result
|
||||||
|
@ -109,7 +109,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None:
|
|||||||
'exchange': 'binance',
|
'exchange': 'binance',
|
||||||
}
|
}
|
||||||
|
|
||||||
mocker.patch('freqtrade.exchange.Exchange.get_sell_rate',
|
mocker.patch('freqtrade.exchange.Exchange.get_rate',
|
||||||
MagicMock(side_effect=ExchangeError("Pair 'ETH/BTC' not available")))
|
MagicMock(side_effect=ExchangeError("Pair 'ETH/BTC' not available")))
|
||||||
results = rpc._rpc_trade_status()
|
results = rpc._rpc_trade_status()
|
||||||
assert isnan(results[0]['current_profit'])
|
assert isnan(results[0]['current_profit'])
|
||||||
@ -217,7 +217,7 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None:
|
|||||||
assert '-0.41% (-0.06)' == result[0][3]
|
assert '-0.41% (-0.06)' == result[0][3]
|
||||||
assert '-0.06' == f'{fiat_profit_sum:.2f}'
|
assert '-0.06' == f'{fiat_profit_sum:.2f}'
|
||||||
|
|
||||||
mocker.patch('freqtrade.exchange.Exchange.get_sell_rate',
|
mocker.patch('freqtrade.exchange.Exchange.get_rate',
|
||||||
MagicMock(side_effect=ExchangeError("Pair 'ETH/BTC' not available")))
|
MagicMock(side_effect=ExchangeError("Pair 'ETH/BTC' not available")))
|
||||||
result, headers, fiat_profit_sum = rpc._rpc_status_table(default_conf['stake_currency'], 'USD')
|
result, headers, fiat_profit_sum = rpc._rpc_status_table(default_conf['stake_currency'], 'USD')
|
||||||
assert 'instantly' == result[0][2]
|
assert 'instantly' == result[0][2]
|
||||||
@ -427,7 +427,7 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
|
|||||||
assert prec_satoshi(stats['best_rate'], 6.2)
|
assert prec_satoshi(stats['best_rate'], 6.2)
|
||||||
|
|
||||||
# Test non-available pair
|
# Test non-available pair
|
||||||
mocker.patch('freqtrade.exchange.Exchange.get_sell_rate',
|
mocker.patch('freqtrade.exchange.Exchange.get_rate',
|
||||||
MagicMock(side_effect=ExchangeError("Pair 'ETH/BTC' not available")))
|
MagicMock(side_effect=ExchangeError("Pair 'ETH/BTC' not available")))
|
||||||
stats = rpc._rpc_trade_statistics(stake_currency, fiat_display_currency)
|
stats = rpc._rpc_trade_statistics(stake_currency, fiat_display_currency)
|
||||||
assert stats['trade_count'] == 2
|
assert stats['trade_count'] == 2
|
||||||
|
@ -879,7 +879,7 @@ def test_api_status(botclient, mocker, ticker, fee, markets):
|
|||||||
'exchange': 'binance',
|
'exchange': 'binance',
|
||||||
}
|
}
|
||||||
|
|
||||||
mocker.patch('freqtrade.exchange.Exchange.get_sell_rate',
|
mocker.patch('freqtrade.exchange.Exchange.get_rate',
|
||||||
MagicMock(side_effect=ExchangeError("Pair 'ETH/BTC' not available")))
|
MagicMock(side_effect=ExchangeError("Pair 'ETH/BTC' not available")))
|
||||||
|
|
||||||
rc = client_get(client, f"{BASE_URI}/status")
|
rc = client_get(client, f"{BASE_URI}/status")
|
||||||
|
@ -161,7 +161,7 @@ def test_get_trade_stake_amount(default_conf, ticker, mocker) -> None:
|
|||||||
(True, 0.0022, 3, 0.5, [0.001, 0.001, 0.0]),
|
(True, 0.0022, 3, 0.5, [0.001, 0.001, 0.0]),
|
||||||
(True, 0.0027, 3, 0.5, [0.001, 0.001, 0.000673]),
|
(True, 0.0027, 3, 0.5, [0.001, 0.001, 0.000673]),
|
||||||
(True, 0.0022, 3, 1, [0.001, 0.001, 0.0]),
|
(True, 0.0022, 3, 1, [0.001, 0.001, 0.0]),
|
||||||
])
|
])
|
||||||
def test_check_available_stake_amount(default_conf, ticker, mocker, fee, limit_buy_order_open,
|
def test_check_available_stake_amount(default_conf, ticker, mocker, fee, limit_buy_order_open,
|
||||||
amend_last, wallet, max_open, lsamr, expected) -> None:
|
amend_last, wallet, max_open, lsamr, expected) -> None:
|
||||||
patch_RPCManager(mocker)
|
patch_RPCManager(mocker)
|
||||||
@ -784,7 +784,7 @@ def test_execute_buy(mocker, default_conf, fee, limit_buy_order, limit_buy_order
|
|||||||
buy_mm = MagicMock(return_value=limit_buy_order_open)
|
buy_mm = MagicMock(return_value=limit_buy_order_open)
|
||||||
mocker.patch.multiple(
|
mocker.patch.multiple(
|
||||||
'freqtrade.exchange.Exchange',
|
'freqtrade.exchange.Exchange',
|
||||||
get_buy_rate=buy_rate_mock,
|
get_rate=buy_rate_mock,
|
||||||
fetch_ticker=MagicMock(return_value={
|
fetch_ticker=MagicMock(return_value={
|
||||||
'bid': 0.00001172,
|
'bid': 0.00001172,
|
||||||
'ask': 0.00001173,
|
'ask': 0.00001173,
|
||||||
@ -824,7 +824,7 @@ def test_execute_buy(mocker, default_conf, fee, limit_buy_order, limit_buy_order
|
|||||||
limit_buy_order_open['id'] = '33'
|
limit_buy_order_open['id'] = '33'
|
||||||
fix_price = 0.06
|
fix_price = 0.06
|
||||||
assert freqtrade.execute_buy(pair, stake_amount, fix_price)
|
assert freqtrade.execute_buy(pair, stake_amount, fix_price)
|
||||||
# Make sure get_buy_rate wasn't called again
|
# Make sure get_rate wasn't called again
|
||||||
assert buy_rate_mock.call_count == 0
|
assert buy_rate_mock.call_count == 0
|
||||||
|
|
||||||
assert buy_mm.call_count == 2
|
assert buy_mm.call_count == 2
|
||||||
@ -893,7 +893,7 @@ def test_execute_buy(mocker, default_conf, fee, limit_buy_order, limit_buy_order
|
|||||||
assert not freqtrade.execute_buy(pair, stake_amount)
|
assert not freqtrade.execute_buy(pair, stake_amount)
|
||||||
|
|
||||||
# Fail to get price...
|
# Fail to get price...
|
||||||
mocker.patch('freqtrade.exchange.Exchange.get_buy_rate', MagicMock(return_value=0.0))
|
mocker.patch('freqtrade.exchange.Exchange.get_rate', MagicMock(return_value=0.0))
|
||||||
|
|
||||||
with pytest.raises(PricingError, match="Could not determine buy price."):
|
with pytest.raises(PricingError, match="Could not determine buy price."):
|
||||||
freqtrade.execute_buy(pair, stake_amount)
|
freqtrade.execute_buy(pair, stake_amount)
|
||||||
@ -909,7 +909,7 @@ def test_execute_buy_confirm_error(mocker, default_conf, fee, limit_buy_order) -
|
|||||||
'last': 0.00001172
|
'last': 0.00001172
|
||||||
}),
|
}),
|
||||||
buy=MagicMock(return_value=limit_buy_order),
|
buy=MagicMock(return_value=limit_buy_order),
|
||||||
get_buy_rate=MagicMock(return_value=0.11),
|
get_rate=MagicMock(return_value=0.11),
|
||||||
get_min_pair_stake_amount=MagicMock(return_value=1),
|
get_min_pair_stake_amount=MagicMock(return_value=1),
|
||||||
get_fee=fee,
|
get_fee=fee,
|
||||||
)
|
)
|
||||||
@ -2513,7 +2513,7 @@ def test_handle_cancel_sell_limit(mocker, default_conf, fee) -> None:
|
|||||||
'freqtrade.exchange.Exchange',
|
'freqtrade.exchange.Exchange',
|
||||||
cancel_order=cancel_order_mock,
|
cancel_order=cancel_order_mock,
|
||||||
)
|
)
|
||||||
mocker.patch('freqtrade.exchange.Exchange.get_sell_rate', return_value=0.245441)
|
mocker.patch('freqtrade.exchange.Exchange.get_rate', return_value=0.245441)
|
||||||
|
|
||||||
freqtrade = FreqtradeBot(default_conf)
|
freqtrade = FreqtradeBot(default_conf)
|
||||||
|
|
||||||
@ -3956,7 +3956,7 @@ def test_order_book_depth_of_market_high_delta(default_conf, ticker, limit_buy_o
|
|||||||
|
|
||||||
def test_order_book_bid_strategy1(mocker, default_conf, order_book_l2) -> None:
|
def test_order_book_bid_strategy1(mocker, default_conf, order_book_l2) -> None:
|
||||||
"""
|
"""
|
||||||
test if function get_buy_rate will return the order book price
|
test if function get_rate will return the order book price
|
||||||
instead of the ask rate
|
instead of the ask rate
|
||||||
"""
|
"""
|
||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
@ -3974,7 +3974,7 @@ def test_order_book_bid_strategy1(mocker, default_conf, order_book_l2) -> None:
|
|||||||
default_conf['telegram']['enabled'] = False
|
default_conf['telegram']['enabled'] = False
|
||||||
|
|
||||||
freqtrade = FreqtradeBot(default_conf)
|
freqtrade = FreqtradeBot(default_conf)
|
||||||
assert freqtrade.exchange.get_buy_rate('ETH/BTC', True) == 0.043935
|
assert freqtrade.exchange.get_rate('ETH/BTC', refresh=True, side="buy") == 0.043935
|
||||||
assert ticker_mock.call_count == 0
|
assert ticker_mock.call_count == 0
|
||||||
|
|
||||||
|
|
||||||
@ -3996,8 +3996,8 @@ def test_order_book_bid_strategy_exception(mocker, default_conf, caplog) -> None
|
|||||||
freqtrade = FreqtradeBot(default_conf)
|
freqtrade = FreqtradeBot(default_conf)
|
||||||
# orderbook shall be used even if tickers would be lower.
|
# orderbook shall be used even if tickers would be lower.
|
||||||
with pytest.raises(PricingError):
|
with pytest.raises(PricingError):
|
||||||
freqtrade.exchange.get_buy_rate('ETH/BTC', refresh=True)
|
freqtrade.exchange.get_rate('ETH/BTC', refresh=True, side="buy")
|
||||||
assert log_has_re(r'Buy Price from orderbook could not be determined.', caplog)
|
assert log_has_re(r'Buy Price at location 1 from orderbook could not be determined.', caplog)
|
||||||
|
|
||||||
|
|
||||||
def test_check_depth_of_market_buy(default_conf, mocker, order_book_l2) -> None:
|
def test_check_depth_of_market_buy(default_conf, mocker, order_book_l2) -> None:
|
||||||
|
Loading…
Reference in New Issue
Block a user