updated requested changes in PR #6545

This commit is contained in:
மனோஜ்குமார் பழனிச்சாமி 2022-03-28 20:36:58 +05:30
parent 389ae969fc
commit bd00f6de17
9 changed files with 118 additions and 141 deletions

View File

@ -1181,7 +1181,8 @@ class Exchange:
buy_rate = None buy_rate = None
sell_rate = None sell_rate = None
if not refresh: if not refresh:
buy_rate, sell_rate = self._buy_rate_cache.get(pair), self._sell_rate_cache.get(pair) buy_rate = self._buy_rate_cache.get(pair)
sell_rate = self._sell_rate_cache.get(pair)
if buy_rate: if buy_rate:
logger.debug(f"Using cached buy rate for {pair}.") logger.debug(f"Using cached buy rate for {pair}.")
if sell_rate: if sell_rate:

View File

@ -485,7 +485,7 @@ class FreqtradeBot(LoggingMixin):
return return
else: else:
logger.debug("Max adjustment entries is set to unlimited.") logger.debug("Max adjustment entries is set to unlimited.")
self.execute_entry(trade.pair, stake_amount, trade=trade) self.execute_entry(trade.pair, stake_amount, current_entry_rate, trade=trade)
if stake_amount is not None and stake_amount < 0.0: if stake_amount is not None and stake_amount < 0.0:
# We should decrease our position # We should decrease our position
@ -631,10 +631,6 @@ class FreqtradeBot(LoggingMixin):
trade.open_order_id = order_id trade.open_order_id = order_id
trade.orders.append(order_obj) trade.orders.append(order_obj)
if pos_adjust:
trade.recalc_trade_from_orders()
else:
trade.recalc_open_trade_value()
Trade.query.session.add(trade) Trade.query.session.add(trade)
Trade.commit() Trade.commit()
@ -1142,16 +1138,18 @@ class FreqtradeBot(LoggingMixin):
trade.open_order_id = None trade.open_order_id = None
trade.sell_reason = None trade.sell_reason = None
cancelled = True cancelled = True
self.wallets.update()
else: else:
# TODO: figure out how to handle partially complete sell orders # TODO: figure out how to handle partially complete sell orders
reason = constants.CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN'] reason = constants.CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN']
cancelled = False cancelled = False
self.wallets.update() order_obj = Order.parse_from_ccxt_object(order, trade.pair, 'sell')
sub_trade = order_obj.amount != trade.amount
self._notify_exit_cancel( self._notify_exit_cancel(
trade, trade,
order_type=self.strategy.order_types['sell'], order_type=self.strategy.order_types['sell'],
reason=reason reason=reason, sub_trade=sub_trade, order=order_obj
) )
return cancelled return cancelled
@ -1279,7 +1277,7 @@ class FreqtradeBot(LoggingMixin):
current_rate = self.exchange.get_rate( current_rate = self.exchange.get_rate(
trade.pair, refresh=False, side="sell") if not fill else None trade.pair, refresh=False, side="sell") if not fill else None
# second condtion is for mypy only; order will always be passed during sub trade # second condition is for mypy only; order will always be passed during sub trade
if sub_trade and order is not None: if sub_trade and order is not None:
amount = order.safe_filled amount = order.safe_filled
profit_rate = order.safe_price profit_rate = order.safe_price
@ -1327,7 +1325,7 @@ class FreqtradeBot(LoggingMixin):
self.rpc.send_msg(msg) self.rpc.send_msg(msg)
def _notify_exit_cancel(self, trade: Trade, order_type: str, reason: str, def _notify_exit_cancel(self, trade: Trade, order_type: str, reason: str,
sub_trade: bool = False) -> None: sub_trade: bool = False, order: Order=None) -> None:
""" """
Sends rpc notification when a sell cancel occurred. Sends rpc notification when a sell cancel occurred.
""" """
@ -1350,7 +1348,7 @@ class FreqtradeBot(LoggingMixin):
'gain': gain, 'gain': gain,
'limit': profit_rate or 0, 'limit': profit_rate or 0,
'order_type': order_type, 'order_type': order_type,
'amount': trade.amount, 'amount': order.safe_amount_after_fee,
'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,
@ -1419,7 +1417,7 @@ class FreqtradeBot(LoggingMixin):
trade.update_trade(order_obj) trade.update_trade(order_obj)
Trade.commit() Trade.commit()
if order['status'] in constants.NON_OPEN_EXCHANGE_STATES: if order.get('status') in constants.NON_OPEN_EXCHANGE_STATES:
# If a buy order was closed, force update on stoploss on exchange # If a buy order was closed, force update on stoploss on exchange
if order.get('side', None) == 'buy': if order.get('side', None) == 'buy':
trade = self.cancel_stoploss_on_exchange(trade) trade = self.cancel_stoploss_on_exchange(trade)

View File

@ -383,8 +383,7 @@ class Backtesting:
def _get_adjust_trade_entry_for_candle(self, trade: LocalTrade, row: Tuple def _get_adjust_trade_entry_for_candle(self, trade: LocalTrade, row: Tuple
) -> LocalTrade: ) -> LocalTrade:
current_entry_rate = current_exit_rate = row[OPEN_IDX] current_rate = row[OPEN_IDX]
current_rate = current_entry_rate
current_profit = trade.calc_profit_ratio(current_rate) current_profit = trade.calc_profit_ratio(current_rate)
min_stake = self.exchange.get_min_pair_stake_amount(trade.pair, current_rate, -0.1) min_stake = self.exchange.get_min_pair_stake_amount(trade.pair, current_rate, -0.1)
@ -393,7 +392,7 @@ class Backtesting:
default_retval=None)( default_retval=None)(
trade=trade, current_time=row[DATE_IDX].to_pydatetime(), current_rate=current_rate, trade=trade, current_time=row[DATE_IDX].to_pydatetime(), current_rate=current_rate,
current_profit=current_profit, min_stake=min_stake, max_stake=max_stake, current_profit=current_profit, min_stake=min_stake, max_stake=max_stake,
current_entry_rate=current_entry_rate, current_exit_rate=current_exit_rate) current_entry_rate=current_rate, current_exit_rate=current_rate)
# Check if we should increase our position # Check if we should increase our position
if stake_amount is not None and stake_amount > 0.0: if stake_amount is not None and stake_amount > 0.0:
@ -403,9 +402,8 @@ class Backtesting:
return pos_trade return pos_trade
if stake_amount is not None and stake_amount < 0.0: if stake_amount is not None and stake_amount < 0.0:
amount = -stake_amount / current_rate amount = abs(stake_amount) / current_rate
if amount > trade.amount: if amount > trade.amount:
logger.info(f"Amount is higher than available. {amount} > {trade.amount}")
return trade return trade
pos_trade = self._exit_trade(trade, row, current_rate, amount) pos_trade = self._exit_trade(trade, row, current_rate, amount)
if pos_trade is not None: if pos_trade is not None:
@ -441,29 +439,29 @@ class Backtesting:
trade_dur = int((trade.close_date_utc - trade.open_date_utc).total_seconds() // 60) trade_dur = int((trade.close_date_utc - trade.open_date_utc).total_seconds() // 60)
try: try:
closerate = self._get_close_rate(sell_row, trade, sell, trade_dur) close_rate = self._get_close_rate(sell_row, trade, sell, trade_dur)
except ValueError: except ValueError:
return None return None
# call the custom exit price,with default value as previous closerate # call the custom exit price,with default value as previous close_rate
current_profit = trade.calc_profit_ratio(closerate) current_profit = trade.calc_profit_ratio(close_rate)
order_type = self.strategy.order_types['sell'] order_type = self.strategy.order_types['sell']
if sell.sell_type in (SellType.SELL_SIGNAL, SellType.CUSTOM_SELL): if sell.sell_type in (SellType.SELL_SIGNAL, SellType.CUSTOM_SELL):
# Custom exit pricing only for sell-signals # Custom exit pricing only for sell-signals
if order_type == 'limit': if order_type == 'limit':
closerate = strategy_safe_wrapper(self.strategy.custom_exit_price, close_rate = strategy_safe_wrapper(self.strategy.custom_exit_price,
default_retval=closerate)( default_retval=close_rate)(
pair=trade.pair, trade=trade, pair=trade.pair, trade=trade,
current_time=sell_candle_time, current_time=sell_candle_time,
proposed_rate=closerate, current_profit=current_profit) proposed_rate=close_rate, current_profit=current_profit)
# We can't place orders lower than current low. # We can't place orders lower than current low.
# freqtrade does not support this in live, and the order would fill immediately # freqtrade does not support this in live, and the order would fill immediately
closerate = max(closerate, sell_row[LOW_IDX]) close_rate = max(close_rate, sell_row[LOW_IDX])
# Confirm trade exit: # Confirm trade exit:
time_in_force = self.strategy.order_time_in_force['sell'] time_in_force = self.strategy.order_time_in_force['sell']
if not strategy_safe_wrapper(self.strategy.confirm_trade_exit, default_retval=True)( if not strategy_safe_wrapper(self.strategy.confirm_trade_exit, default_retval=True)(
pair=trade.pair, trade=trade, order_type='limit', amount=trade.amount, pair=trade.pair, trade=trade, order_type='limit', amount=trade.amount,
rate=closerate, rate=close_rate,
time_in_force=time_in_force, time_in_force=time_in_force,
sell_reason=sell.sell_reason, sell_reason=sell.sell_reason,
current_time=sell_candle_time): current_time=sell_candle_time):
@ -480,15 +478,16 @@ class Backtesting:
): ):
trade.sell_reason = sell_row[EXIT_TAG_IDX] trade.sell_reason = sell_row[EXIT_TAG_IDX]
return self._exit_trade(trade, sell_row, closerate) return self._exit_trade(trade, sell_row, close_rate)
return None return None
def _exit_trade(self, trade: LocalTrade, sell_row: Tuple, def _exit_trade(self, trade: LocalTrade, sell_row: Tuple,
closerate: float, amount: float = None) -> Optional[LocalTrade]: close_rate: float, amount: float = None) -> Optional[LocalTrade]:
self.order_id_counter += 1 self.order_id_counter += 1
sell_candle_time = sell_row[DATE_IDX].to_pydatetime() sell_candle_time = sell_row[DATE_IDX].to_pydatetime()
order_type = self.strategy.order_types['sell'] order_type = self.strategy.order_types['sell']
amount = amount or trade.amount
order = Order( order = Order(
id=self.order_id_counter, id=self.order_id_counter,
ft_trade_id=trade.id, ft_trade_id=trade.id,
@ -502,12 +501,12 @@ class Backtesting:
side="sell", side="sell",
order_type=order_type, order_type=order_type,
status="open", status="open",
price=closerate, price=close_rate,
average=closerate, average=close_rate,
amount=amount or trade.amount, amount=amount,
filled=0, filled=0,
remaining=trade.amount, remaining=amount,
cost=trade.amount * closerate, cost=amount * close_rate,
) )
trade.orders.append(order) trade.orders.append(order)
return trade return trade

View File

@ -249,7 +249,7 @@ class Wallets:
if min_stake_amount is not None and min_stake_amount > max_stake_amount: if min_stake_amount is not None and min_stake_amount > max_stake_amount:
if self._log: if self._log:
logger.warning("Minimum stake amount > available balance.") logger.warning(f"Minimum stake amount > available balance.{min_stake_amount} > {max_stake_amount}")
return 0 return 0
if min_stake_amount is not None and stake_amount < min_stake_amount: if min_stake_amount is not None and stake_amount < min_stake_amount:
if self._log: if self._log:

View File

@ -26,6 +26,54 @@ from tests.conftest import get_mock_coro, get_patched_exchange, log_has, log_has
# Make sure to always keep one exchange here which is NOT subclassed!! # Make sure to always keep one exchange here which is NOT subclassed!!
EXCHANGES = ['bittrex', 'binance', 'kraken', 'ftx'] EXCHANGES = ['bittrex', 'binance', 'kraken', 'ftx']
get_buy_rate_data = [
('ask', 20, 19, 10, 0.0, 20), # Full ask side
('ask', 20, 19, 10, 1.0, 10), # Full last side
('ask', 20, 19, 10, 0.5, 15), # Between ask and last
('ask', 20, 19, 10, 0.7, 13), # Between ask and last
('ask', 20, 19, 10, 0.3, 17), # Between ask and last
('ask', 5, 6, 10, 1.0, 5), # last bigger than ask
('ask', 5, 6, 10, 0.5, 5), # last bigger than ask
('ask', 20, 19, 10, None, 20), # ask_last_balance missing
('ask', 10, 20, None, 0.5, 10), # last not available - uses ask
('ask', 4, 5, None, 0.5, 4), # last not available - uses ask
('ask', 4, 5, None, 1, 4), # last not available - uses ask
('ask', 4, 5, None, 0, 4), # last not available - uses ask
('bid', 21, 20, 10, 0.0, 20), # Full bid side
('bid', 21, 20, 10, 1.0, 10), # Full last side
('bid', 21, 20, 10, 0.5, 15), # Between bid and last
('bid', 21, 20, 10, 0.7, 13), # Between bid and last
('bid', 21, 20, 10, 0.3, 17), # Between bid and last
('bid', 6, 5, 10, 1.0, 5), # last bigger than bid
('bid', 21, 20, 10, None, 20), # ask_last_balance missing
('bid', 6, 5, 10, 0.5, 5), # last bigger than bid
('bid', 21, 20, None, 0.5, 20), # last not available - uses bid
('bid', 6, 5, None, 0.5, 5), # last not available - uses bid
('bid', 6, 5, None, 1, 5), # last not available - uses bid
('bid', 6, 5, None, 0, 5), # last not available - uses bid
]
get_sell_rate_data = [
('bid', 12.0, 11.0, 11.5, 0.0, 11.0), # full bid side
('bid', 12.0, 11.0, 11.5, 1.0, 11.5), # full last side
('bid', 12.0, 11.0, 11.5, 0.5, 11.25), # between bid and lat
('bid', 12.0, 11.2, 10.5, 0.0, 11.2), # Last smaller than bid
('bid', 12.0, 11.2, 10.5, 1.0, 11.2), # Last smaller than bid - uses bid
('bid', 12.0, 11.2, 10.5, 0.5, 11.2), # Last smaller than bid - uses bid
('bid', 0.003, 0.002, 0.005, 0.0, 0.002),
('bid', 0.003, 0.002, 0.005, None, 0.002),
('ask', 12.0, 11.0, 12.5, 0.0, 12.0), # full ask side
('ask', 12.0, 11.0, 12.5, 1.0, 12.5), # full last side
('ask', 12.0, 11.0, 12.5, 0.5, 12.25), # between bid and lat
('ask', 12.2, 11.2, 10.5, 0.0, 12.2), # Last smaller than ask
('ask', 12.0, 11.0, 10.5, 1.0, 12.0), # Last smaller than ask - uses ask
('ask', 12.0, 11.2, 10.5, 0.5, 12.0), # Last smaller than ask - uses ask
('ask', 10.0, 11.0, 11.0, 0.0, 10.0),
('ask', 10.11, 11.2, 11.0, 0.0, 10.11),
('ask', 0.001, 0.002, 11.0, 0.0, 0.001),
('ask', 0.006, 1.0, 11.0, 0.0, 0.006),
('ask', 0.006, 1.0, 11.0, None, 0.006),
]
def ccxt_exceptionhandlers(mocker, default_conf, api_mock, exchange_name, def ccxt_exceptionhandlers(mocker, default_conf, api_mock, exchange_name,
fun, mock_ccxt_fun, retries=API_RETRY_COUNT + 1, **kwargs): fun, mock_ccxt_fun, retries=API_RETRY_COUNT + 1, **kwargs):
@ -1903,33 +1951,6 @@ def test_fetch_l2_order_book_exception(default_conf, mocker, exchange_name):
exchange.fetch_l2_order_book(pair='ETH/BTC', limit=50) exchange.fetch_l2_order_book(pair='ETH/BTC', limit=50)
get_buy_rate_data = [
('ask', 20, 19, 10, 0.0, 20), # Full ask side
('ask', 20, 19, 10, 1.0, 10), # Full last side
('ask', 20, 19, 10, 0.5, 15), # Between ask and last
('ask', 20, 19, 10, 0.7, 13), # Between ask and last
('ask', 20, 19, 10, 0.3, 17), # Between ask and last
('ask', 5, 6, 10, 1.0, 5), # last bigger than ask
('ask', 5, 6, 10, 0.5, 5), # last bigger than ask
('ask', 20, 19, 10, None, 20), # ask_last_balance missing
('ask', 10, 20, None, 0.5, 10), # last not available - uses ask
('ask', 4, 5, None, 0.5, 4), # last not available - uses ask
('ask', 4, 5, None, 1, 4), # last not available - uses ask
('ask', 4, 5, None, 0, 4), # last not available - uses ask
('bid', 21, 20, 10, 0.0, 20), # Full bid side
('bid', 21, 20, 10, 1.0, 10), # Full last side
('bid', 21, 20, 10, 0.5, 15), # Between bid and last
('bid', 21, 20, 10, 0.7, 13), # Between bid and last
('bid', 21, 20, 10, 0.3, 17), # Between bid and last
('bid', 6, 5, 10, 1.0, 5), # last bigger than bid
('bid', 21, 20, 10, None, 20), # ask_last_balance missing
('bid', 6, 5, 10, 0.5, 5), # last bigger than bid
('bid', 21, 20, None, 0.5, 20), # last not available - uses bid
('bid', 6, 5, None, 0.5, 5), # last not available - uses bid
('bid', 6, 5, None, 1, 5), # last not available - uses bid
('bid', 6, 5, None, 0, 5), # last not available - uses bid
]
@pytest.mark.parametrize("side,ask,bid,last,last_ab,expected", get_buy_rate_data) @pytest.mark.parametrize("side,ask,bid,last,last_ab,expected", get_buy_rate_data)
def test_get_buy_rate(mocker, default_conf, caplog, side, ask, bid, def test_get_buy_rate(mocker, default_conf, caplog, side, ask, bid,
@ -1955,29 +1976,6 @@ def test_get_buy_rate(mocker, default_conf, caplog, side, ask, bid,
assert not log_has("Using cached buy rate for ETH/BTC.", caplog) assert not log_has("Using cached buy rate for ETH/BTC.", caplog)
get_sell_rate_data = [
('bid', 12.0, 11.0, 11.5, 0.0, 11.0), # full bid side
('bid', 12.0, 11.0, 11.5, 1.0, 11.5), # full last side
('bid', 12.0, 11.0, 11.5, 0.5, 11.25), # between bid and lat
('bid', 12.0, 11.2, 10.5, 0.0, 11.2), # Last smaller than bid
('bid', 12.0, 11.2, 10.5, 1.0, 11.2), # Last smaller than bid - uses bid
('bid', 12.0, 11.2, 10.5, 0.5, 11.2), # Last smaller than bid - uses bid
('bid', 0.003, 0.002, 0.005, 0.0, 0.002),
('bid', 0.003, 0.002, 0.005, None, 0.002),
('ask', 12.0, 11.0, 12.5, 0.0, 12.0), # full ask side
('ask', 12.0, 11.0, 12.5, 1.0, 12.5), # full last side
('ask', 12.0, 11.0, 12.5, 0.5, 12.25), # between bid and lat
('ask', 12.2, 11.2, 10.5, 0.0, 12.2), # Last smaller than ask
('ask', 12.0, 11.0, 10.5, 1.0, 12.0), # Last smaller than ask - uses ask
('ask', 12.0, 11.2, 10.5, 0.5, 12.0), # Last smaller than ask - uses ask
('ask', 10.0, 11.0, 11.0, 0.0, 10.0),
('ask', 10.11, 11.2, 11.0, 0.0, 10.11),
('ask', 0.001, 0.002, 11.0, 0.0, 0.001),
('ask', 0.006, 1.0, 11.0, 0.0, 0.006),
('ask', 0.006, 1.0, 11.0, None, 0.006),
]
@pytest.mark.parametrize('side,ask,bid,last,last_ab,expected', get_sell_rate_data) @pytest.mark.parametrize('side,ask,bid,last,last_ab,expected', get_sell_rate_data)
def test_get_sell_rate(default_conf, mocker, caplog, side, bid, ask, def test_get_sell_rate(default_conf, mocker, caplog, side, bid, ask,
last, last_ab, expected) -> None: last, last_ab, expected) -> None:
@ -2148,12 +2146,12 @@ def test_get_rates_testing_sell(default_conf, mocker, caplog, side, bid, ask,
pair = "ETH/BTC" pair = "ETH/BTC"
# Test regular mode # Test regular mode
rate = exchange.get_rate(pair, refresh=True, side="sell") rate = exchange.get_rates(pair, refresh=True)[1]
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_rate(pair, refresh=False, side="sell") rate = exchange.get_rates(pair, refresh=False)[1]
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)

View File

@ -467,9 +467,8 @@ def test_daily_handle(default_conf, update, ticker, limit_buy_order, fee,
trades = Trade.query.all() trades = Trade.query.all()
for trade in trades: for trade in trades:
trade.open_rate = oobj.safe_price trade.orders[0] = oobj
trade.amount = oobj.safe_amount_after_fee trade.update_trade(oobj)
trade.recalc_open_trade_value()
trade.update_trade(oobjs) trade.update_trade(oobjs)
trade.close_date = datetime.utcnow() trade.close_date = datetime.utcnow()
trade.is_open = False trade.is_open = False
@ -586,9 +585,8 @@ def test_weekly_handle(default_conf, update, ticker, limit_buy_order, fee,
trades = Trade.query.all() trades = Trade.query.all()
for trade in trades: for trade in trades:
trade.open_rate = oobj.safe_price trade.orders[0] = oobj
trade.amount = oobj.safe_amount_after_fee trade.update_trade(oobj)
trade.recalc_open_trade_value()
trade.update_trade(oobjs) trade.update_trade(oobjs)
trade.close_date = datetime.utcnow() trade.close_date = datetime.utcnow()
trade.is_open = False trade.is_open = False
@ -708,9 +706,8 @@ def test_monthly_handle(default_conf, update, ticker, limit_buy_order, fee,
trades = Trade.query.all() trades = Trade.query.all()
for trade in trades: for trade in trades:
trade.open_rate = oobj.safe_price trade.orders[0] = oobj
trade.amount = oobj.safe_amount_after_fee trade.update_trade(oobj)
trade.recalc_open_trade_value()
trade.update_trade(oobjs) trade.update_trade(oobjs)
trade.close_date = datetime.utcnow() trade.close_date = datetime.utcnow()
trade.is_open = False trade.is_open = False

View File

@ -2075,9 +2075,9 @@ def test_check_handle_timedout_buy_usercustom(default_conf_usdt, ticker_usdt, li
default_conf_usdt["unfilledtimeout"] = {"buy": 1400, "sell": 30} default_conf_usdt["unfilledtimeout"] = {"buy": 1400, "sell": 30}
limit_buy_order_old['id'] = open_trade.open_order_id limit_buy_order_old['id'] = open_trade.open_order_id
rpc_mock = patch_RPCManager(mocker) rpc_mock = patch_RPCManager(mocker)
cancel_order_mock = MagicMock(return_value=limit_buy_order_old)
cancel_buy_order = deepcopy(limit_buy_order_old) cancel_buy_order = deepcopy(limit_buy_order_old)
cancel_buy_order['status'] = 'canceled' cancel_buy_order['status'] = 'canceled'
cancel_order_mock = MagicMock(return_value=limit_buy_order_old)
cancel_order_wr_mock = MagicMock(return_value=cancel_buy_order) cancel_order_wr_mock = MagicMock(return_value=cancel_buy_order)
patch_exchange(mocker) patch_exchange(mocker)
@ -2085,8 +2085,8 @@ def test_check_handle_timedout_buy_usercustom(default_conf_usdt, ticker_usdt, li
'freqtrade.exchange.Exchange', 'freqtrade.exchange.Exchange',
fetch_ticker=ticker_usdt, fetch_ticker=ticker_usdt,
fetch_order=MagicMock(return_value=limit_buy_order_old), fetch_order=MagicMock(return_value=limit_buy_order_old),
cancel_order_with_result=cancel_order_wr_mock,
cancel_order=cancel_order_mock, cancel_order=cancel_order_mock,
cancel_order_with_result=cancel_order_wr_mock,
get_fee=fee get_fee=fee
) )
freqtrade = FreqtradeBot(default_conf_usdt) freqtrade = FreqtradeBot(default_conf_usdt)
@ -2129,7 +2129,9 @@ def test_check_handle_timedout_buy_usercustom(default_conf_usdt, ticker_usdt, li
def test_check_handle_timedout_buy(default_conf_usdt, ticker_usdt, limit_buy_order_old, open_trade, def test_check_handle_timedout_buy(default_conf_usdt, ticker_usdt, limit_buy_order_old, open_trade,
fee, mocker) -> None: fee, mocker) -> None:
rpc_mock = patch_RPCManager(mocker) rpc_mock = patch_RPCManager(mocker)
limit_buy_order_old['id'] = open_trade.open_order_id open_trade.open_order_id = limit_buy_order_old['id']
order = Order.parse_from_ccxt_object(limit_buy_order_old, 'mocked', 'buy')
open_trade.orders[0] = order
limit_buy_cancel = deepcopy(limit_buy_order_old) limit_buy_cancel = deepcopy(limit_buy_order_old)
limit_buy_cancel['status'] = 'canceled' limit_buy_cancel['status'] = 'canceled'
cancel_order_mock = MagicMock(return_value=limit_buy_cancel) cancel_order_mock = MagicMock(return_value=limit_buy_cancel)
@ -2214,8 +2216,9 @@ def test_check_handle_timedout_buy_exception(default_conf_usdt, ticker_usdt,
def test_check_handle_timedout_sell_usercustom(default_conf_usdt, ticker_usdt, limit_sell_order_old, def test_check_handle_timedout_sell_usercustom(default_conf_usdt, ticker_usdt, limit_sell_order_old,
mocker, open_trade, caplog) -> None: mocker, open_trade, caplog) -> None:
default_conf_usdt["unfilledtimeout"] = {"buy": 1440, "sell": 1440, "exit_timeout_count": 1} default_conf_usdt["unfilledtimeout"] = {"buy": 1440, "sell": 1440, "exit_timeout_count": 1}
limit_sell_order_old['id'] = open_trade.open_order_id open_trade.open_order_id = limit_sell_order_old['id']
order = Order.parse_from_ccxt_object(limit_sell_order_old, 'mocked', 'sell')
open_trade.orders[0] = order
rpc_mock = patch_RPCManager(mocker) rpc_mock = patch_RPCManager(mocker)
cancel_order_mock = MagicMock() cancel_order_mock = MagicMock()
patch_exchange(mocker) patch_exchange(mocker)
@ -4877,45 +4880,26 @@ def test_position_adjust2(mocker, default_conf_usdt, fee) -> None:
assert trade.is_open is False assert trade.is_open is False
@pytest.mark.parametrize('orders, results', [ @pytest.mark.parametrize('data', [
( (
( # tuple 1 - side amount, price
# side ampunt, price # tuple 2 - amount, open_rate, stake_amount, cumulative_profit, realized_profit
('buy', 100, 10), (('buy', 100, 10), (100.0, 10.0, 1000.0, 0.0, None)),
('buy', 100, 15), (('buy', 100, 15), (200.0, 12.5, 2500.0, 0.0, None)),
('sell', 50, 12), (('sell', 50, 12), (150.0, 12.5, 1875.0, -28.0625, -28.0625)),
('sell', 100, 20), (('sell', 100, 20), (50.0, 12.5, 625.0, 713.8125, 741.875)),
('sell', 50, 5), (('sell', 50, 5), (50.0, 12.5, 625.0, 713.8125, 336.625)),
), ),
( (
# amount, open_rate, stake_amount, cumulative_profit, realized_profit (('buy', 100, 3), (100.0, 3.0, 300.0, 0.0, None)),
(100.0, 10.0, 1000.0, 0.0, None,), (('buy', 100, 7), (200.0, 5.0, 1000.0, 0.0, None)),
(200.0, 12.5, 2500.0, 0.0, None,), (('sell', 100, 11), (100.0, 5.0, 500.0, 596.0, 596.0)),
(150.0, 12.5, 1875.0, -28.0625, -28.0625,), (('buy', 150, 15), (250.0, 11.0, 2750.0, 596.0, 596.0)),
(50.0, 12.5, 625.0, 713.8125, 741.875,), (('sell', 100, 19), (150.0, 11.0, 1650.0, 1388.5, 792.5)),
(50.0, 12.5, 625.0, 713.8125, 336.625,), (('sell', 150, 23), (150.0, 11.0, 1650.0, 1388.5, 3175.75)),
) )
),
(
(
('buy', 100, 3),
('buy', 100, 7),
('sell', 100, 11),
('buy', 150, 15),
('sell', 100, 19),
('sell', 150, 23),
),
(
(100.0, 3.0, 300.0, 0.0, None,),
(200.0, 5.0, 1000.0, 0.0, None,),
(100.0, 5.0, 500.0, 596.0, 596.0,),
(250.0, 11.0, 2750.0, 596.0, 596.0,),
(150.0, 11.0, 1650.0, 1388.5, 792.5,),
(150.0, 11.0, 1650.0, 1388.5, 3175.75,),
)
),
]) ])
def test_position_adjust3(mocker, default_conf_usdt, fee, orders, results) -> None: def test_position_adjust3(mocker, default_conf_usdt, fee, data) -> None:
default_conf_usdt.update({ default_conf_usdt.update({
"position_adjustment_enable": True, "position_adjustment_enable": True,
"dry_run": False, "dry_run": False,
@ -4928,7 +4912,7 @@ def test_position_adjust3(mocker, default_conf_usdt, fee, orders, results) -> No
freqtrade = FreqtradeBot(default_conf_usdt) freqtrade = FreqtradeBot(default_conf_usdt)
trade = None trade = None
freqtrade.strategy.confirm_trade_entry = MagicMock(return_value=True) freqtrade.strategy.confirm_trade_entry = MagicMock(return_value=True)
for idx, (order, result) in enumerate(zip(orders, results)): for idx, (order, result) in enumerate(data):
amount = order[1] amount = order[1]
price = order[2] price = order[2]
price_mock = MagicMock(return_value=price) price_mock = MagicMock(return_value=price)

View File

@ -1641,7 +1641,7 @@ def test_recalc_trade_from_orders_ignores_bad_orders(fee):
assert trade.open_trade_value == 2 * o1_trade_val assert trade.open_trade_value == 2 * o1_trade_val
assert trade.nr_of_successful_buys == 2 assert trade.nr_of_successful_buys == 2
# Just to make sure sell orders are ignored, let's calculate one more time. # Just to make sure non partial sell orders are ignored, let's calculate one more time.
sell1 = Order( sell1 = Order(
ft_order_side='sell', ft_order_side='sell',
ft_pair=trade.pair, ft_pair=trade.pair,