updated tests

This commit is contained in:
மனோஜ்குமார் பழனிச்சாமி 2022-04-04 19:14:52 +05:30
parent b646d8ba0e
commit 606e0f1b68
17 changed files with 141 additions and 10499 deletions

View File

@ -13,6 +13,7 @@ class ExitType(Enum):
FORCE_SELL = "force_sell" FORCE_SELL = "force_sell"
EMERGENCY_SELL = "emergency_sell" EMERGENCY_SELL = "emergency_sell"
CUSTOM_SELL = "custom_sell" CUSTOM_SELL = "custom_sell"
PARTIAL_SELL = "partial_sell"
NONE = "" NONE = ""
def __str__(self): def __str__(self):

View File

@ -1428,8 +1428,9 @@ class Exchange:
except ccxt.BaseError as e: except ccxt.BaseError as e:
raise OperationalException(e) from e raise OperationalException(e) from e
def get_rate(self, pair: str, refresh: bool, def get_rate(self, pair: str, refresh: bool, # noqa: max-complexity: 13
side: Literal['entry', 'exit'], is_short: bool, order_book: Optional[dict] = None, ticker: Optional[dict] = Non) -> float: side: Literal['entry', 'exit'], is_short: bool,
order_book: Optional[dict] = None, ticker: Optional[dict] = None) -> float:
""" """
Calculates bid/ask target Calculates bid/ask target
bid rate - between current ask price and last price bid rate - between current ask price and last price
@ -1533,7 +1534,8 @@ class Exchange:
if not entry_rate: if not entry_rate:
entry_rate = self.get_rate(pair, refresh, 'entry', is_short, ticker=ticker) entry_rate = self.get_rate(pair, refresh, 'entry', is_short, ticker=ticker)
if not exit_rate: if not exit_rate:
exit_rate = self.get_rate(pair, refresh, 'exit', order_book=order_book, ticker=ticker) exit_rate = self.get_rate(pair, refresh, 'exit',
is_short, order_book=order_book, ticker=ticker)
return entry_rate, exit_rate return entry_rate, exit_rate
# Fee handling # Fee handling

File diff suppressed because it is too large Load Diff

View File

@ -459,7 +459,6 @@ class FreqtradeBot(LoggingMixin):
if signal: if signal:
stake_amount = self.wallets.get_trade_stake_amount(pair, self.edge) stake_amount = self.wallets.get_trade_stake_amount(pair, self.edge)
bid_check_dom = self.config.get('entry_pricing', {}).get('check_depth_of_market', {}) bid_check_dom = self.config.get('entry_pricing', {}).get('check_depth_of_market', {})
if ((bid_check_dom.get('enabled', False)) and if ((bid_check_dom.get('enabled', False)) and
(bid_check_dom.get('bids_to_ask_delta', 0) > 0)): (bid_check_dom.get('bids_to_ask_delta', 0) > 0)):
@ -505,7 +504,8 @@ class FreqtradeBot(LoggingMixin):
If the strategy triggers the adjustment, a new order gets issued. If the strategy triggers the adjustment, a new order gets issued.
Once that completes, the existing trade is modified to match new data. Once that completes, the existing trade is modified to match new data.
""" """
current_entry_rate, current_exit_rate = self.exchange.get_rates(trade.pair, True, is_short) current_entry_rate, current_exit_rate = self.exchange.get_rates(
trade.pair, True, trade.is_short)
current_entry_profit = trade.calc_profit_ratio(current_entry_rate) current_entry_profit = trade.calc_profit_ratio(current_entry_rate)
current_exit_profit = trade.calc_profit_ratio(current_exit_rate) current_exit_profit = trade.calc_profit_ratio(current_exit_rate)
@ -528,7 +528,8 @@ class FreqtradeBot(LoggingMixin):
current_entry_rate=current_entry_rate, current_exit_rate=current_exit_rate, current_entry_rate=current_entry_rate, current_exit_rate=current_exit_rate,
current_entry_profit=current_entry_profit, current_exit_profit=current_exit_profit, current_entry_profit=current_entry_profit, current_exit_profit=current_exit_profit,
min_entry_stake=min_entry_stake, min_exit_stake=min_exit_stake, min_entry_stake=min_entry_stake, min_exit_stake=min_exit_stake,
max_entry_stake=min(max_entry_stake, stake_available), max_exit_stake=min(max_exit_stake, stake_available), max_entry_stake=min(max_entry_stake, stake_available),
max_exit_stake=min(max_exit_stake, stake_available)
) )
if stake_amount is not None and stake_amount > 0.0: if stake_amount is not None and stake_amount > 0.0:
@ -540,7 +541,8 @@ max_entry_stake=min(max_entry_stake, stake_available), max_exit_stake=min(max_ex
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, current_entry_rate, trade=trade, is_short=trade.is_short) self.execute_entry(trade.pair, stake_amount, current_entry_rate,
trade=trade, is_short=trade.is_short)
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
@ -553,8 +555,8 @@ max_entry_stake=min(max_entry_stake, stake_available), max_exit_stake=min(max_ex
logger.info( logger.info(
f"Adjusting amount to trade.amount as it is higher. {amount} > {trade.amount}") f"Adjusting amount to trade.amount as it is higher. {amount} > {trade.amount}")
amount = trade.amount amount = trade.amount
self.execute_trade_exit(trade, current_exit_rate, sell_reason=SellCheckTuple( self.execute_trade_exit(trade, current_exit_rate, exit_check=ExitCheckTuple(
sell_type=SellType.CUSTOM_SELL), sub_trade_amt=amount) exit_type=ExitType.PARTIAL_SELL), sub_trade_amt=amount)
def _check_depth_of_market(self, pair: str, conf: Dict, side: SignalDirection) -> bool: def _check_depth_of_market(self, pair: str, conf: Dict, side: SignalDirection) -> bool:
""" """
@ -628,7 +630,6 @@ max_entry_stake=min(max_entry_stake, stake_available), max_exit_stake=min(max_ex
amount = (stake_amount / enter_limit_requested) * leverage amount = (stake_amount / enter_limit_requested) * leverage
order_type = ordertype or self.strategy.order_types['entry'] order_type = ordertype or self.strategy.order_types['entry']
if not pos_adjust and not strategy_safe_wrapper( if not pos_adjust and not strategy_safe_wrapper(
self.strategy.confirm_trade_entry, default_retval=True)( self.strategy.confirm_trade_entry, default_retval=True)(
pair=pair, order_type=order_type, amount=amount, rate=enter_limit_requested, pair=pair, order_type=order_type, amount=amount, rate=enter_limit_requested,
@ -648,7 +649,7 @@ max_entry_stake=min(max_entry_stake, stake_available), max_exit_stake=min(max_ex
) )
order_obj = Order.parse_from_ccxt_object(order, pair, side) order_obj = Order.parse_from_ccxt_object(order, pair, side)
order_id = order['id'] order_id = order['id']
order_status = order.get('status', None) order_status = order.get('status')
logger.info(f"Order #{order_id} was created for {pair} and status is {order_status}.") logger.info(f"Order #{order_id} was created for {pair} and status is {order_status}.")
# we assume the order is executed at the price requested # we assume the order is executed at the price requested
@ -744,8 +745,8 @@ max_entry_stake=min(max_entry_stake, stake_available), max_exit_stake=min(max_ex
else: else:
logger.info(f"DCA order {order_status}, will wait for resolution: {trade}") logger.info(f"DCA order {order_status}, will wait for resolution: {trade}")
# Update fees if order is closed # Update fees if order is non-opened
if order_status == 'closed': if order_status in constants.NON_OPEN_EXCHANGE_STATES:
self.update_trade_state(trade, order_id, order) self.update_trade_state(trade, order_id, order)
return True return True
@ -1471,7 +1472,7 @@ max_entry_stake=min(max_entry_stake, stake_available), max_exit_stake=min(max_ex
profit_rate = order.safe_price profit_rate = order.safe_price
if not fill: if not fill:
trade.process_sell_sub_trade(order, is_closed=False) trade.process_exit_sub_trade(order, is_closed=False)
profit_ratio = trade.close_profit profit_ratio = trade.close_profit
profit = trade.close_profit_abs profit = trade.close_profit_abs
@ -1637,12 +1638,12 @@ max_entry_stake=min(max_entry_stake, stake_available), max_exit_stake=min(max_ex
# Updating wallets when order is closed # Updating wallets when order is closed
self.wallets.update() self.wallets.update()
sub_trade = not isclose(order_obj.safe_amount_after_fee,
trade.amount, abs_tol=constants.MATH_CLOSE_PREC)
if not trade.is_open: if not trade.is_open:
self.handle_protections(trade.pair)
sub_trade = order_obj.safe_amount_after_fee != trade.amount
if order.get('side', None) == 'sell':
if send_msg and not stoploss_order and not trade.open_order_id: if send_msg and not stoploss_order and not trade.open_order_id:
self._notify_exit(trade, '', True, sub_trade=sub_trade, order=order_obj) self._notify_exit(trade, '', True, sub_trade=sub_trade, order=order_obj)
self.handle_protections(trade.pair)
elif send_msg and not trade.open_order_id: elif send_msg and not trade.open_order_id:
# Enter fill # Enter fill
self._notify_enter(trade, order_obj, fill=True, sub_trade=sub_trade) self._notify_enter(trade, order_obj, fill=True, sub_trade=sub_trade)

File diff suppressed because it is too large Load Diff

View File

@ -480,10 +480,11 @@ class Backtesting:
stake_amount = strategy_safe_wrapper(self.strategy.adjust_trade_position, stake_amount = strategy_safe_wrapper(self.strategy.adjust_trade_position,
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=min(max_stake, stake_available), current_profit=current_profit, min_stake=min_stake,
max_stake=min(max_stake, stake_available),
current_entry_rate=current_rate, current_exit_rate=current_rate, current_entry_rate=current_rate, current_exit_rate=current_rate,
max_entry_stake=min(max_stake, stake_available), max_entry_stake=min(max_stake, stake_available),
max_exit_stake=min(max_stake, stake_available)) max_exit_stake=min(max_stake, stake_available))
# 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:
@ -586,7 +587,7 @@ max_exit_stake=min(max_stake, stake_available))
close_rate: 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['exit']
amount = amount or trade.amount amount = amount or trade.amount
order = Order( order = Order(
id=self.order_id_counter, id=self.order_id_counter,
@ -905,7 +906,7 @@ max_exit_stake=min(max_stake, stake_available))
return None return None
return row return row
def backtest(self, processed: Dict, def backtest(self, processed: Dict, # noqa: max-complexity: 13
start_date: datetime, end_date: datetime, start_date: datetime, end_date: datetime,
max_open_trades: int = 0, position_stacking: bool = False, max_open_trades: int = 0, position_stacking: bool = False,
enable_protections: bool = False) -> Dict[str, Any]: enable_protections: bool = False) -> Dict[str, Any]:
@ -1007,7 +1008,7 @@ max_exit_stake=min(max_stake, stake_available))
sub_trade = order.safe_amount_after_fee != trade.amount sub_trade = order.safe_amount_after_fee != trade.amount
if sub_trade: if sub_trade:
order.close_bt_order(current_time) order.close_bt_order(current_time)
trade.process_sell_sub_trade(order) trade.process_exit_sub_trade(order)
trade.recalc_trade_from_orders() trade.recalc_trade_from_orders()
else: else:
trade.close_date = current_time trade.close_date = current_time

File diff suppressed because it is too large Load Diff

View File

@ -4,6 +4,7 @@ This module contains the class to persist trades into SQLite
import logging import logging
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from decimal import Decimal from decimal import Decimal
from math import isclose
from typing import Any, Dict, List, Optional from typing import Any, Dict, List, Optional
from sqlalchemy import (Boolean, Column, DateTime, Enum, Float, ForeignKey, Integer, String, from sqlalchemy import (Boolean, Column, DateTime, Enum, Float, ForeignKey, Integer, String,
@ -13,7 +14,7 @@ from sqlalchemy.orm import Query, declarative_base, relationship, scoped_session
from sqlalchemy.pool import StaticPool from sqlalchemy.pool import StaticPool
from sqlalchemy.sql.schema import UniqueConstraint from sqlalchemy.sql.schema import UniqueConstraint
from freqtrade.constants import DATETIME_PRINT_FORMAT, NON_OPEN_EXCHANGE_STATES from freqtrade.constants import DATETIME_PRINT_FORMAT, NON_OPEN_EXCHANGE_STATES, MATH_CLOSE_PREC
from freqtrade.enums import ExitType, TradingMode from freqtrade.enums import ExitType, TradingMode
from freqtrade.exceptions import DependencyException, OperationalException from freqtrade.exceptions import DependencyException, OperationalException
from freqtrade.leverage import interest from freqtrade.leverage import interest
@ -193,7 +194,7 @@ class Order(_DECL_BASE):
self.order_filled_date = datetime.now(timezone.utc) self.order_filled_date = datetime.now(timezone.utc)
self.order_update_date = datetime.now(timezone.utc) self.order_update_date = datetime.now(timezone.utc)
def to_json(self, entry_side: str) -> Dict[str, Any]: def to_json(self, enter_side: str) -> Dict[str, Any]:
return { return {
'pair': self.ft_pair, 'pair': self.ft_pair,
'order_id': self.order_id, 'order_id': self.order_id,
@ -215,7 +216,7 @@ class Order(_DECL_BASE):
tzinfo=timezone.utc).timestamp() * 1000) if self.order_filled_date else None, tzinfo=timezone.utc).timestamp() * 1000) if self.order_filled_date else None,
'order_type': self.order_type, 'order_type': self.order_type,
'price': self.price, 'price': self.price,
'ft_is_entry': self.ft_order_side == entry_side, 'ft_is_entry': self.ft_order_side == enter_side,
'remaining': self.remaining, 'remaining': self.remaining,
} }
@ -359,7 +360,7 @@ class LocalTrade():
if self.has_no_leverage: if self.has_no_leverage:
return 0.0 return 0.0
elif not self.is_short: elif not self.is_short:
return (self.amount * self.open_rate) * ((self.leverage-1)/self.leverage) return (self.amount * self.open_rate) * ((self.leverage - 1) / self.leverage)
else: else:
return self.amount return self.amount
@ -613,6 +614,9 @@ class LocalTrade():
# condition to avoid reset value when updating fees # condition to avoid reset value when updating fees
if self.open_order_id == order.order_id: if self.open_order_id == order.order_id:
self.open_order_id = None self.open_order_id = None
else:
logger.warning(
f'Got different open_order_id {self.open_order_id} != {order.order_id}')
self.recalc_trade_from_orders() self.recalc_trade_from_orders()
elif order.ft_order_side == self.exit_side: elif order.ft_order_side == self.exit_side:
if self.is_open: if self.is_open:
@ -622,10 +626,16 @@ class LocalTrade():
# condition to avoid reset value when updating fees # condition to avoid reset value when updating fees
if self.open_order_id == order.order_id: if self.open_order_id == order.order_id:
self.open_order_id = None self.open_order_id = None
if self.amount == order.safe_amount_after_fee: else:
logger.warning(
f'Got different open_order_id {self.open_order_id} != {order.order_id}')
if isclose(order.safe_amount_after_fee,
self.amount, abs_tol=MATH_CLOSE_PREC):
self.close(order.safe_price) self.close(order.safe_price)
else: else:
self.process_sell_sub_trade(order) logger.info((self.amount, self.to_json(), order.to_json(
self.enter_side), order.safe_amount_after_fee))
self.process_exit_sub_trade(order)
elif order.ft_order_side == 'stoploss': elif order.ft_order_side == 'stoploss':
self.stoploss_order_id = None self.stoploss_order_id = None
self.close_rate_requested = self.stop_loss self.close_rate_requested = self.stop_loss
@ -637,25 +647,29 @@ class LocalTrade():
raise ValueError(f'Unknown order type: {order.order_type}') raise ValueError(f'Unknown order type: {order.order_type}')
Trade.commit() Trade.commit()
def process_sell_sub_trade(self, order: Order, is_closed: bool = True) -> None: def process_exit_sub_trade(self, order: Order, is_closed: bool = True) -> None:
sell_amount = order.safe_amount_after_fee exit_amount = order.safe_amount_after_fee
sell_rate = order.safe_price exit_rate = order.safe_price
sell_stake_amount = sell_rate * sell_amount * (1 - self.fee_close) exit_stake_amount = exit_rate * exit_amount * (1 - self.fee_close)
profit = self.calc_profit2(self.open_rate, sell_rate, sell_amount) profit = self.calc_profit2(self.open_rate, exit_rate, exit_amount)
if is_closed: if is_closed:
self.amount -= sell_amount self.amount -= exit_amount
self.stake_amount = self.open_rate * self.amount self.stake_amount = self.open_rate * self.amount
self.realized_profit += profit self.realized_profit += profit
logger.info(
'Processed exit sub trade for %s',
self
)
self.close_profit_abs = profit self.close_profit_abs = profit
self.close_profit = sell_stake_amount / (sell_stake_amount - profit) - 1 self.close_profit = exit_stake_amount / (exit_stake_amount - profit) - 1
self.recalc_open_trade_value() self.recalc_open_trade_value()
def calc_profit2(self, open_rate: float, close_rate: float, def calc_profit2(self, open_rate: float, close_rate: float,
amount: float) -> float: amount: float) -> float:
return float(Decimal(amount) * return float(Decimal(amount)
(Decimal(1 - self.fee_close) * Decimal(close_rate) - * (Decimal(1 - self.fee_close) * Decimal(close_rate)
Decimal(1 + self.fee_open) * Decimal(open_rate))) - Decimal(1 + self.fee_open) * Decimal(open_rate)))
def close(self, rate: float, *, show_msg: bool = True) -> None: def close(self, rate: float, *, show_msg: bool = True) -> None:
""" """
@ -729,7 +743,7 @@ class LocalTrade():
def recalc_open_trade_value(self) -> None: def recalc_open_trade_value(self) -> None:
""" """
Recalculate open_trade_value. Recalculate open_trade_value.
Must be called whenever open_rate, fee_open or is_short is changed. Must be called whenever open_rate, fee_open is changed.
""" """
self.open_trade_value = self._calc_open_trade_value() self.open_trade_value = self._calc_open_trade_value()
@ -747,7 +761,7 @@ class LocalTrade():
now = (self.close_date or datetime.now(timezone.utc)).replace(tzinfo=None) now = (self.close_date or datetime.now(timezone.utc)).replace(tzinfo=None)
sec_per_hour = Decimal(3600) sec_per_hour = Decimal(3600)
total_seconds = Decimal((now - open_date).total_seconds()) total_seconds = Decimal((now - open_date).total_seconds())
hours = total_seconds/sec_per_hour or zero hours = total_seconds / sec_per_hour or zero
rate = Decimal(interest_rate or self.interest_rate) rate = Decimal(interest_rate or self.interest_rate)
borrowed = Decimal(self.borrowed) borrowed = Decimal(self.borrowed)
@ -861,9 +875,9 @@ class LocalTrade():
return 0.0 return 0.0
else: else:
if self.is_short: if self.is_short:
profit_ratio = (1 - (close_trade_value/self.open_trade_value)) * leverage profit_ratio = (1 - (close_trade_value / self.open_trade_value)) * leverage
else: else:
profit_ratio = ((close_trade_value/self.open_trade_value) - 1) * leverage profit_ratio = ((close_trade_value / self.open_trade_value) - 1) * leverage
return float(f"{profit_ratio:.8f}") return float(f"{profit_ratio:.8f}")
@ -878,11 +892,11 @@ class LocalTrade():
tmp_amount = o.safe_amount_after_fee tmp_amount = o.safe_amount_after_fee
tmp_price = o.safe_price tmp_price = o.safe_price
is_sell = o.ft_order_side != 'buy' is_exit = o.ft_order_side != self.enter_side
side = -1 if is_sell else 1 side = -1 if is_exit else 1
if tmp_amount > 0.0 and tmp_price is not None: if tmp_amount > 0.0 and tmp_price is not None:
total_amount += tmp_amount * side total_amount += tmp_amount * side
price = avg_price if is_sell else tmp_price price = avg_price if is_exit else tmp_price
total_stake += price * tmp_amount * side total_stake += price * tmp_amount * side
if total_amount > 0: if total_amount > 0:
avg_price = total_stake / total_amount avg_price = total_stake / total_amount
@ -932,9 +946,9 @@ class LocalTrade():
:return: array of Order objects :return: array of Order objects
""" """
return [o for o in self.orders if ((o.ft_order_side == order_side) or (order_side is None)) return [o for o in self.orders if ((o.ft_order_side == order_side) or (order_side is None))
and o.ft_is_open is False and and o.ft_is_open is False
(o.filled or 0) > 0 and and o.filled
o.status in NON_OPEN_EXCHANGE_STATES] and o.status in NON_OPEN_EXCHANGE_STATES]
@property @property
def nr_of_successful_entries(self) -> int: def nr_of_successful_entries(self) -> int:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -969,7 +969,12 @@ class IStrategy(ABC, HyperStrategyMixin):
# Make sure current_profit is calculated using high for backtesting. # Make sure current_profit is calculated using high for backtesting.
bound = low if trade.is_short else high bound = low if trade.is_short else high
bound_profit = current_profit if not bound else trade.calc_profit_ratio(bound) bound_profit = current_profit if not bound else trade.calc_profit_ratio(bound)
from pprint import pformat
logger.info(pformat(trade.to_json()))
logger.info((self.trailing_only_offset_is_reached,
self.trailing_stop_positive, bound_profit, sl_offset))
logger.debug(f"{trade.pair} - Using positive stoploss: {stop_loss_value} "
f"offset: {sl_offset:.4g} profit: {current_profit:.2%}")
# Don't update stoploss if trailing_only_offset_is_reached is true. # Don't update stoploss if trailing_only_offset_is_reached is true.
if not (self.trailing_only_offset_is_reached and bound_profit < sl_offset): if not (self.trailing_only_offset_is_reached and bound_profit < sl_offset):
# Specific handling for trailing_stop_positive # Specific handling for trailing_stop_positive

View File

@ -2469,7 +2469,7 @@ def test_get_exit_rate_exception(default_conf, mocker, is_short):
assert exchange.get_rate(pair, refresh=True, side="exit", is_short=is_short) == 0.13 assert exchange.get_rate(pair, refresh=True, side="exit", is_short=is_short) == 0.13
@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_entry_rate_data)
@pytest.mark.parametrize("side2", ['bid', 'ask']) @pytest.mark.parametrize("side2", ['bid', 'ask'])
@pytest.mark.parametrize("use_order_book", [True, False]) @pytest.mark.parametrize("use_order_book", [True, False])
def test_get_rates_testing_buy(mocker, default_conf, caplog, side, ask, bid, def test_get_rates_testing_buy(mocker, default_conf, caplog, side, ask, bid,
@ -2477,26 +2477,26 @@ def test_get_rates_testing_buy(mocker, default_conf, caplog, side, ask, bid,
side2, use_order_book, order_book_l2) -> None: side2, use_order_book, order_book_l2) -> None:
caplog.set_level(logging.DEBUG) caplog.set_level(logging.DEBUG)
if last_ab is None: if last_ab is None:
del default_conf['bid_strategy']['ask_last_balance'] del default_conf['entry_pricing']['price_last_balance']
else: else:
default_conf['bid_strategy']['ask_last_balance'] = last_ab default_conf['entry_pricing']['price_last_balance'] = last_ab
default_conf['bid_strategy']['price_side'] = side default_conf['entry_pricing']['price_side'] = side
default_conf['ask_strategy']['price_side'] = side2 default_conf['exit_pricing']['price_side'] = side2
default_conf['ask_strategy']['use_order_book'] = use_order_book default_conf['exit_pricing']['use_order_book'] = use_order_book
api_mock = MagicMock() api_mock = MagicMock()
api_mock.fetch_l2_order_book = order_book_l2 api_mock.fetch_l2_order_book = order_book_l2
api_mock.fetch_ticker = MagicMock( api_mock.fetch_ticker = MagicMock(
return_value={'ask': ask, 'last': last, 'bid': bid}) return_value={'ask': ask, 'last': last, 'bid': bid})
exchange = get_patched_exchange(mocker, default_conf, api_mock) exchange = get_patched_exchange(mocker, default_conf, api_mock)
assert exchange.get_rates('ETH/BTC', refresh=True)[0] == expected assert exchange.get_rates('ETH/BTC', refresh=True, is_short=False)[0] == 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_rates('ETH/BTC', refresh=False)[0] == expected assert exchange.get_rates('ETH/BTC', refresh=False, is_short=False)[0] == 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_rates('ETH/BTC', refresh=True)[0] == expected assert exchange.get_rates('ETH/BTC', refresh=True, is_short=False)[0] == 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)
api_mock.fetch_l2_order_book.call_count = int(use_order_book) api_mock.fetch_l2_order_book.call_count = int(use_order_book)
@ -2511,12 +2511,12 @@ def test_get_rates_testing_sell(default_conf, mocker, caplog, side, bid, ask,
side2, use_order_book, order_book_l2) -> None: side2, use_order_book, order_book_l2) -> None:
caplog.set_level(logging.DEBUG) caplog.set_level(logging.DEBUG)
default_conf['ask_strategy']['price_side'] = side default_conf['exit_pricing']['price_side'] = side
if last_ab is not None: if last_ab is not None:
default_conf['ask_strategy']['bid_last_balance'] = last_ab default_conf['exit_pricing']['price_last_balance'] = last_ab
default_conf['bid_strategy']['price_side'] = side2 default_conf['entry_pricing']['price_side'] = side2
default_conf['bid_strategy']['use_order_book'] = use_order_book default_conf['entry_pricing']['use_order_book'] = use_order_book
api_mock = MagicMock() api_mock = MagicMock()
api_mock.fetch_l2_order_book = order_book_l2 api_mock.fetch_l2_order_book = order_book_l2
api_mock.fetch_ticker = MagicMock( api_mock.fetch_ticker = MagicMock(
@ -2526,12 +2526,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_rates(pair, refresh=True)[1] rate = exchange.get_rates(pair, refresh=True, is_short=False)[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_rates(pair, refresh=False)[1] rate = exchange.get_rates(pair, refresh=False, is_short=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

@ -297,6 +297,7 @@ def test_rpc_daily_profit(default_conf, update, ticker, fee,
# Simulate buy & sell # Simulate buy & sell
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.orders[0] = oobj
trade.update_trade(oobj) trade.update_trade(oobj)
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
trade.update_trade(oobj) trade.update_trade(oobj)
@ -438,7 +439,8 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
freqtradebot.enter_positions() freqtradebot.enter_positions()
trade = Trade.query.first() trade = Trade.query.first()
# Simulate fulfilled LIMIT_BUY order for trade # Simulate fulfilled LIMIT_BUY order for trade
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'sell') oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.orders[0] = oobj
trade.update_trade(oobj) trade.update_trade(oobj)
# Update the ticker with a market going up # Update the ticker with a market going up
@ -452,20 +454,23 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee,
trade.is_open = False trade.is_open = False
freqtradebot.enter_positions() freqtradebot.enter_positions()
trade = Trade.query.first()
# Simulate fulfilled LIMIT_BUY order for trade # TODO: updated the first trade again
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') # trade = Trade.query.first()
trade.update_trade(oobj) # # Simulate fulfilled LIMIT_BUY order for trade
# oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
# trade.orders[0] = oobj
# trade.update_trade(oobj)
# Update the ticker with a market going up # Update the ticker with a market going up
mocker.patch.multiple( # mocker.patch.multiple(
'freqtrade.exchange.Exchange', # 'freqtrade.exchange.Exchange',
fetch_ticker=ticker_sell_up # fetch_ticker=ticker_sell_up
) # )
oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell') # oobj = Order.parse_from_ccxt_object(limit_sell_order, limit_sell_order['symbol'], 'sell')
trade.update_trade(oobj) # trade.update_trade(oobj)
trade.close_date = datetime.utcnow() # trade.close_date = datetime.utcnow()
trade.is_open = False # trade.is_open = False
stats = rpc._rpc_trade_statistics(stake_currency, fiat_display_currency) stats = rpc._rpc_trade_statistics(stake_currency, fiat_display_currency)
assert prec_satoshi(stats['profit_closed_coin'], 6.217e-05) assert prec_satoshi(stats['profit_closed_coin'], 6.217e-05)
@ -523,6 +528,7 @@ def test_rpc_trade_statistics_closed(mocker, default_conf, ticker, fee,
trade = Trade.query.first() trade = Trade.query.first()
# Simulate fulfilled LIMIT_BUY order for trade # Simulate fulfilled LIMIT_BUY order for trade
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.orders[0] = oobj
trade.update_trade(oobj) trade.update_trade(oobj)
# Update the ticker with a market going up # Update the ticker with a market going up
mocker.patch.multiple( mocker.patch.multiple(
@ -924,6 +930,7 @@ def test_performance_handle(default_conf, ticker, limit_buy_order, fee,
# Simulate fulfilled LIMIT_BUY order for trade # Simulate fulfilled LIMIT_BUY order for trade
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.orders[0] = oobj
trade.update_trade(oobj) trade.update_trade(oobj)
# Simulate fulfilled LIMIT_SELL order for trade # Simulate fulfilled LIMIT_SELL order for trade
@ -960,6 +967,7 @@ def test_enter_tag_performance_handle(default_conf, ticker, limit_buy_order, fee
# Simulate fulfilled LIMIT_BUY order for trade # Simulate fulfilled LIMIT_BUY order for trade
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.orders[0] = oobj
trade.update_trade(oobj) trade.update_trade(oobj)
# Simulate fulfilled LIMIT_SELL order for trade # Simulate fulfilled LIMIT_SELL order for trade
@ -1034,6 +1042,7 @@ def test_exit_reason_performance_handle(default_conf, ticker, limit_buy_order, f
# Simulate fulfilled LIMIT_BUY order for trade # Simulate fulfilled LIMIT_BUY order for trade
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.orders[0] = oobj
trade.update_trade(oobj) trade.update_trade(oobj)
# Simulate fulfilled LIMIT_SELL order for trade # Simulate fulfilled LIMIT_SELL order for trade
@ -1108,6 +1117,7 @@ def test_mix_tag_performance_handle(default_conf, ticker, limit_buy_order, fee,
# Simulate fulfilled LIMIT_BUY order for trade # Simulate fulfilled LIMIT_BUY order for trade
oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy') oobj = Order.parse_from_ccxt_object(limit_buy_order, limit_buy_order['symbol'], 'buy')
trade.orders[0] = oobj
trade.update_trade(oobj) trade.update_trade(oobj)
# Simulate fulfilled LIMIT_SELL order for trade # Simulate fulfilled LIMIT_SELL order for trade

File diff suppressed because it is too large Load Diff

View File

@ -2057,7 +2057,7 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
'profit_ratio': -0.57405275, 'profit_ratio': -0.57405275,
'stake_currency': 'ETH', 'stake_currency': 'ETH',
'enter_tag': 'buy_signal1', 'enter_tag': 'buy_signal1',
'exit_reason': SellType.STOP_LOSS.value, 'exit_reason': ExitType.STOP_LOSS.value,
'open_date': arrow.utcnow().shift(days=-1, hours=-2, minutes=-30), 'open_date': arrow.utcnow().shift(days=-1, hours=-2, minutes=-30),
'close_date': arrow.utcnow(), 'close_date': arrow.utcnow(),
}) })
@ -2144,7 +2144,7 @@ def test_send_msg_sell_fill_notification(default_conf, mocker, direction,
leverage_text = f'*Leverage:* `{leverage}`\n' if leverage and leverage != 1.0 else '' leverage_text = f'*Leverage:* `{leverage}`\n' if leverage and leverage != 1.0 else ''
assert msg_mock.call_args[0][0] == ( assert msg_mock.call_args[0][0] == (
'\N{WARNING SIGN} *Binance:* Exited KEY/ETH (#1)\n' '\N{WARNING SIGN} *Binance:* Exited KEY/ETH (#1)\n'
'*Profit:* `-57.41% (loss: -0.05746268 ETH)`\`\n' '*Profit:* `-57.41% (loss: -0.05746268 ETH)`\n'
f'*Enter Tag:* `{enter_signal}`\n' f'*Enter Tag:* `{enter_signal}`\n'
'*Exit Reason:* `stop_loss`\n' '*Exit Reason:* `stop_loss`\n'
f"*Direction:* `{direction}`\n" f"*Direction:* `{direction}`\n"

View File

@ -845,7 +845,7 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order,
assert trade assert trade
assert trade.open_order_id is None assert trade.open_order_id is None
assert trade.open_rate == 10 assert trade.open_rate == 10
assert trade.stake_amount == round(order['price'] * order['filled'] / leverage, 8) assert trade.stake_amount == round(order['average'] * order['filled'] / leverage, 8)
# In case of rejected or expired order and partially filled # In case of rejected or expired order and partially filled
order['status'] = 'expired' order['status'] = 'expired'
@ -861,7 +861,7 @@ def test_execute_entry(mocker, default_conf_usdt, fee, limit_order,
trade = Trade.query.all()[3] trade = Trade.query.all()[3]
trade.is_short = is_short trade.is_short = is_short
assert trade assert trade
assert trade.open_order_id == '555' assert trade.open_order_id is None
assert trade.open_rate == 0.5 assert trade.open_rate == 0.5
assert trade.stake_amount == round(order['average'] * order['filled'] / leverage, 8) assert trade.stake_amount == round(order['average'] * order['filled'] / leverage, 8)
@ -1075,7 +1075,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_
'last': 1.9 'last': 1.9
}), }),
create_order=MagicMock(side_effect=[ create_order=MagicMock(side_effect=[
{'id': enter_order['id']}, enter_order,
exit_order, exit_order,
]), ]),
get_fee=fee, get_fee=fee,
@ -1101,20 +1101,20 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_
# should do nothing and return false # should do nothing and return false
trade.is_open = True trade.is_open = True
trade.open_order_id = None trade.open_order_id = None
trade.stoploss_order_id = 100 trade.stoploss_order_id = "100"
hanging_stoploss_order = MagicMock(return_value={'status': 'open'}) hanging_stoploss_order = MagicMock(return_value={'status': 'open'})
mocker.patch('freqtrade.exchange.Exchange.fetch_stoploss_order', hanging_stoploss_order) mocker.patch('freqtrade.exchange.Exchange.fetch_stoploss_order', hanging_stoploss_order)
assert freqtrade.handle_stoploss_on_exchange(trade) is False assert freqtrade.handle_stoploss_on_exchange(trade) is False
assert trade.stoploss_order_id == 100 assert trade.stoploss_order_id == "100"
# Third case: when stoploss was set but it was canceled for some reason # Third case: when stoploss was set but it was canceled for some reason
# should set a stoploss immediately and return False # should set a stoploss immediately and return False
caplog.clear() caplog.clear()
trade.is_open = True trade.is_open = True
trade.open_order_id = None trade.open_order_id = None
trade.stoploss_order_id = 100 trade.stoploss_order_id = "100"
canceled_stoploss_order = MagicMock(return_value={'status': 'canceled'}) canceled_stoploss_order = MagicMock(return_value={'status': 'canceled'})
mocker.patch('freqtrade.exchange.Exchange.fetch_stoploss_order', canceled_stoploss_order) mocker.patch('freqtrade.exchange.Exchange.fetch_stoploss_order', canceled_stoploss_order)
@ -1134,6 +1134,7 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_
trade.is_open = True trade.is_open = True
trade.open_order_id = None trade.open_order_id = None
trade.stoploss_order_id = "100" trade.stoploss_order_id = "100"
trade.orders.append(Order( trade.orders.append(Order(
ft_order_side='stoploss', ft_order_side='stoploss',
order_id='100', order_id='100',
@ -1201,7 +1202,6 @@ def test_handle_stoploss_on_exchange(mocker, default_conf_usdt, fee, caplog, is_
trade.is_open = True trade.is_open = True
trade.stoploss_last_update = arrow.utcnow().shift(hours=-1).datetime trade.stoploss_last_update = arrow.utcnow().shift(hours=-1).datetime
trade.stop_loss = 24 trade.stop_loss = 24
trade.amount = limit_buy_order_usdt['amount']
freqtrade.config['trailing_stop'] = True freqtrade.config['trailing_stop'] = True
stoploss = MagicMock(side_effect=InvalidOrderException()) stoploss = MagicMock(side_effect=InvalidOrderException())
@ -2341,9 +2341,9 @@ def test_close_trade(
trade.is_short = is_short trade.is_short = is_short
assert trade assert trade
oobj = Order.parse_from_ccxt_object(enter_order, enter_order['symbol'], 'buy') oobj = Order.parse_from_ccxt_object(enter_order, enter_order['symbol'], trade.enter_side)
trade.update_trade(oobj) trade.update_trade(oobj)
oobj = Order.parse_from_ccxt_object(exit_order, exit_order['symbol'], 'sell') oobj = Order.parse_from_ccxt_object(exit_order, exit_order['symbol'], trade.exit_side)
trade.update_trade(oobj) trade.update_trade(oobj)
assert trade.is_open is False assert trade.is_open is False
@ -2534,9 +2534,9 @@ def test_check_handle_timedout_exit_usercustom(
is_short, open_trade_usdt, caplog is_short, open_trade_usdt, caplog
) -> None: ) -> None:
default_conf_usdt["unfilledtimeout"] = {"entry": 1440, "exit": 1440, "exit_timeout_count": 1} default_conf_usdt["unfilledtimeout"] = {"entry": 1440, "exit": 1440, "exit_timeout_count": 1}
open_trade.open_order_id = limit_sell_order_old['id'] open_trade_usdt.open_order_id = limit_sell_order_old['id']
order = Order.parse_from_ccxt_object(limit_sell_order_old, 'mocked', 'sell') order = Order.parse_from_ccxt_object(limit_sell_order_old, 'mocked', 'sell')
open_trade.orders[0] = order open_trade_usdt.orders[0] = order
if is_short: if is_short:
limit_sell_order_old['side'] = 'buy' limit_sell_order_old['side'] = 'buy'
open_trade_usdt.is_short = is_short open_trade_usdt.is_short = is_short
@ -3505,11 +3505,11 @@ def test_may_execute_trade_exit_after_stoploss_on_exchange_hit(
if is_short: if is_short:
assert rpc_mock.call_args_list[0][0][0]['type'] == RPCMessageType.SHORT assert rpc_mock.call_args_list[0][0][0]['type'] == RPCMessageType.SHORT
assert rpc_mock.call_args_list[1][0][0]['type'] == RPCMessageType.SHORT_FILL assert rpc_mock.call_args_list[1][0][0]['type'] == RPCMessageType.SHORT_FILL
assert rpc_mock.call_args_list[2][0][0]['type'] == RPCMessageType.SELL
else: else:
assert rpc_mock.call_args_list[0][0][0]['type'] == RPCMessageType.BUY assert rpc_mock.call_args_list[0][0][0]['type'] == RPCMessageType.BUY
assert rpc_mock.call_args_list[1][0][0]['type'] == RPCMessageType.BUY_FILL assert rpc_mock.call_args_list[1][0][0]['type'] == RPCMessageType.BUY_FILL
assert rpc_mock.call_args_list[2][0][0]['type'] == RPCMessageType.SELL assert rpc_mock.call_args_list[2][0][0]['type'] == RPCMessageType.SELL
@ -3674,7 +3674,7 @@ def test_sell_profit_only(
'last': bid 'last': bid
}), }),
create_order=MagicMock(side_effect=[ create_order=MagicMock(side_effect=[
limit_order_open[eside], limit_order[eside],
{'id': 1234553382}, {'id': 1234553382},
]), ]),
get_fee=fee, get_fee=fee,
@ -3956,7 +3956,7 @@ def test_trailing_stop_loss_positive(
'last': enter_price - (-0.01 if is_short else 0.01), 'last': enter_price - (-0.01 if is_short else 0.01),
}), }),
create_order=MagicMock(side_effect=[ create_order=MagicMock(side_effect=[
limit_order_open[eside], limit_order[eside],
{'id': 1234553382}, {'id': 1234553382},
]), ]),
get_fee=fee, get_fee=fee,
@ -5420,7 +5420,7 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None:
mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order', mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order',
MagicMock(return_value=closed_sell_dca_order_1)) MagicMock(return_value=closed_sell_dca_order_1))
assert freqtrade.execute_trade_exit(trade=trade, limit=8, assert freqtrade.execute_trade_exit(trade=trade, limit=8,
sell_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS), exit_check=ExitCheckTuple(exit_type=ExitType.PARTIAL_SELL),
sub_trade_amt=15) sub_trade_amt=15)
# Assert trade is as expected (averaged dca) # Assert trade is as expected (averaged dca)
@ -5552,7 +5552,7 @@ def test_position_adjust2(mocker, default_conf_usdt, fee) -> None:
mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order', mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order',
MagicMock(return_value=closed_sell_dca_order_1)) MagicMock(return_value=closed_sell_dca_order_1))
assert freqtrade.execute_trade_exit(trade=trade, limit=ask, assert freqtrade.execute_trade_exit(trade=trade, limit=ask,
sell_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS), exit_check=ExitCheckTuple(exit_type=ExitType.PARTIAL_SELL),
sub_trade_amt=amount) sub_trade_amt=amount)
trades: List[Trade] = trade.get_open_trades_without_assigned_fees() trades: List[Trade] = trade.get_open_trades_without_assigned_fees()
assert len(trades) == 1 assert len(trades) == 1
@ -5598,7 +5598,7 @@ def test_position_adjust2(mocker, default_conf_usdt, fee) -> None:
mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order', mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order',
MagicMock(return_value=closed_sell_dca_order_2)) MagicMock(return_value=closed_sell_dca_order_2))
assert freqtrade.execute_trade_exit(trade=trade, limit=ask, assert freqtrade.execute_trade_exit(trade=trade, limit=ask,
sell_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS), exit_check=ExitCheckTuple(exit_type=ExitType.PARTIAL_SELL),
sub_trade_amt=amount) sub_trade_amt=amount)
# Assert trade is as expected (averaged dca) # Assert trade is as expected (averaged dca)
@ -5694,7 +5694,7 @@ def test_position_adjust3(mocker, default_conf_usdt, fee, data) -> None:
else: else:
assert freqtrade.execute_trade_exit( assert freqtrade.execute_trade_exit(
trade=trade, limit=price, trade=trade, limit=price,
sell_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS), exit_check=ExitCheckTuple(exit_type=ExitType.PARTIAL_SELL),
sub_trade_amt=amount) sub_trade_amt=amount)
orders1 = Order.query.all() orders1 = Order.query.all()

View File

@ -478,7 +478,7 @@ def test_update_limit_order(fee, caplog, limit_buy_order_usdt, limit_sell_order_
assert trade.close_profit is None assert trade.close_profit is None
assert trade.close_date is None assert trade.close_date is None
trade.open_order_id = 'mocked_limit_buy_usdt' trade.open_order_id = enter_order['id']
oobj = Order.parse_from_ccxt_object(enter_order, 'ADA/USDT', enter_side) oobj = Order.parse_from_ccxt_object(enter_order, 'ADA/USDT', enter_side)
trade.update_trade(oobj) trade.update_trade(oobj)
assert trade.open_order_id is None assert trade.open_order_id is None
@ -492,7 +492,7 @@ def test_update_limit_order(fee, caplog, limit_buy_order_usdt, limit_sell_order_
caplog) caplog)
caplog.clear() caplog.clear()
trade.open_order_id = 'mocked_limit_sell_usdt' trade.open_order_id = enter_order['id']
time_machine.move_to("2022-03-31 21:45:05 +00:00") time_machine.move_to("2022-03-31 21:45:05 +00:00")
oobj = Order.parse_from_ccxt_object(exit_order, 'ADA/USDT', exit_side) oobj = Order.parse_from_ccxt_object(exit_order, 'ADA/USDT', exit_side)
trade.update_trade(oobj) trade.update_trade(oobj)
@ -2543,7 +2543,6 @@ def test_recalc_trade_from_orders_ignores_bad_orders(fee, is_short):
assert trade.open_trade_value == o1_trade_val assert trade.open_trade_value == o1_trade_val
assert trade.nr_of_successful_entries == 2 assert trade.nr_of_successful_entries == 2
# Check with 1 order # Check with 1 order
order_noavg = Order( order_noavg = Order(
ft_order_side=enter_side, ft_order_side=enter_side,