telegram message fix

This commit is contained in:
Kavinkumar 2022-02-24 11:48:52 +05:30
parent 06d14b81dd
commit ec8e0b1fcb
6 changed files with 359 additions and 44 deletions

View File

@ -1238,16 +1238,26 @@ class FreqtradeBot(LoggingMixin):
return True return True
def _notify_exit(self, trade: Trade, order_type: str, fill: bool = False, def _notify_exit(self, trade: Trade, order_type: str, fill: bool = False,
sub_trade: bool = False) -> None: sub_trade: bool = False, order: Dict = None) -> None:
""" """
Sends rpc notification when a sell occurred. Sends rpc notification when a sell occurred.
""" """
profit_rate = trade.close_rate if trade.close_rate else trade.close_rate_requested
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_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
profit_ratio = trade.calc_profit_ratio(profit_rate) if order:
profit_rate = safe_value_fallback(order, 'average', 'price')
amount = safe_value_fallback(order, 'filled', 'amount')
profit = trade.process_sell_sub_trade(order, is_closed=False)
open_rate = trade.get_open_rate(profit, profit_rate, amount)
open_cost=open_rate * amount * (1+ trade.fee_open)
profit_ratio = ( open_cost + profit)/open_cost - 1
else:
profit_rate = trade.close_rate if trade.close_rate else trade.close_rate_requested
profit = trade.calc_profit(rate=profit_rate)
profit_ratio = trade.calc_profit_ratio(profit_rate)
amount = trade.amount
open_rate = trade.open_rate
gain = "profit" if profit_ratio > 0 else "loss" gain = "profit" if profit_ratio > 0 else "loss"
msg = { msg = {
@ -1259,11 +1269,11 @@ class FreqtradeBot(LoggingMixin):
'gain': gain, 'gain': gain,
'limit': profit_rate, 'limit': profit_rate,
'order_type': order_type, 'order_type': order_type,
'amount': trade.amount, 'amount': amount,
'open_rate': trade.open_rate, 'open_rate': open_rate,
'close_rate': trade.close_rate, 'close_rate': trade.close_rate,
'current_rate': current_rate, 'current_rate': current_rate,
'profit_amount': profit_trade, 'profit_amount': profit,
'profit_ratio': profit_ratio, 'profit_ratio': profit_ratio,
'buy_tag': trade.buy_tag, 'buy_tag': trade.buy_tag,
'sell_reason': trade.sell_reason, 'sell_reason': trade.sell_reason,
@ -1275,10 +1285,7 @@ class FreqtradeBot(LoggingMixin):
'sub_trade': sub_trade, 'sub_trade': sub_trade,
} }
if 'fiat_display_currency' in self.config:
msg.update({
'fiat_currency': self.config['fiat_display_currency'],
})
# Send the message # Send the message
self.rpc.send_msg(msg) self.rpc.send_msg(msg)
@ -1382,9 +1389,10 @@ class FreqtradeBot(LoggingMixin):
self.wallets.update() self.wallets.update()
if not trade.is_open: if not trade.is_open:
self.handle_protections(trade.pair)
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) self._notify_exit(trade, '', True, sub_trade=sub_trade)
self.handle_protections(trade.pair)
elif send_msg and not trade.open_order_id: elif send_msg and not trade.open_order_id:
# Buy fill # Buy fill
self._notify_enter(trade, order, fill=True, sub_trade=sub_trade) self._notify_enter(trade, order, fill=True, sub_trade=sub_trade)

View File

@ -495,10 +495,16 @@ class LocalTrade():
raise ValueError(f'Unknown order type: {order_type}') raise ValueError(f'Unknown order type: {order_type}')
Trade.commit() Trade.commit()
def process_sell_sub_trade(self, order: Dict) -> None: def process_sell_sub_trade(self, order: Dict, is_closed: bool = True) -> float:
orders = (self.select_filled_orders('buy')) orders = (self.select_filled_orders('buy'))
sell_rate = float(safe_value_fallback(order, 'average', 'price')) # is_closed = order['ft_is_open']
sell_amount = float(safe_value_fallback(order, 'filled', 'amount')) sell_amount = float(safe_value_fallback(order, 'filled', 'amount'))
if is_closed:
if sell_amount == self.amount:
self.close(safe_value_fallback(order, 'average', 'price'))
Trade.commit()
return
sell_rate = float(safe_value_fallback(order, 'average', 'price'))
profit = 0.0 profit = 0.0
idx = -1 idx = -1
while sell_amount: while sell_amount:
@ -507,25 +513,25 @@ class LocalTrade():
buy_rate = b_order.average or b_order.price buy_rate = b_order.average or b_order.price
if sell_amount < buy_amount: if sell_amount < buy_amount:
amount = sell_amount amount = sell_amount
b_order.filled -= amount if is_closed:
b_order.filled -= amount
else: else:
if sell_amount == self.amount: if is_closed:
self.close(safe_value_fallback(order, 'average', 'price')) b_order.is_fully_realized = True
Trade.commit() self.update_order(b_order)
return
b_order.is_fully_realized = True
self.update_order(b_order)
idx -= 1 idx -= 1
amount = buy_amount amount = buy_amount
sell_amount -= amount sell_amount -= amount
profit += self.calc_profit2(buy_rate, sell_rate, amount) profit += self.calc_profit2(buy_rate, sell_rate, amount)
b_order2 = orders[idx] b_order2 = orders[idx]
amount2 = b_order2.filled or b_order2.amount amount2 = b_order2.filled or b_order2.amount
b_order2.average = (b_order2.average * amount2 - profit) / amount2 if is_closed :
self.update_order(b_order2) b_order2.average = (b_order2.average * amount2 - profit) / amount2
Order.query.session.commit() self.update_order(b_order2)
self.recalc_trade_from_orders() Order.query.session.commit()
Trade.commit() self.recalc_trade_from_orders()
Trade.commit()
return profit
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:
@ -533,6 +539,12 @@ class LocalTrade():
(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 get_open_rate(self, profit: float, close_rate: float,
amount: float) -> float:
return float(Decimal(amount) *
(Decimal(1 - self.fee_close) * Decimal(close_rate)) -
profit)/(Decimal(amount) * Decimal(1 + self.fee_open))
def close(self, rate: float, *, show_msg: bool = True) -> None: def close(self, rate: float, *, show_msg: bool = True) -> None:
""" """
Sets close_rate to the given rate, calculates total profit Sets close_rate to the given rate, calculates total profit

View File

@ -218,7 +218,7 @@ class RPC:
return results return results
def _rpc_status_table(self, stake_currency: str, def _rpc_status_table(self, stake_currency: str,
fiat_display_currency: str) -> Tuple[List, List, float]: fiat_display_currency: str, show_order: bool = False) -> Tuple[List, List, float]:
trades = Trade.get_open_trades() trades = Trade.get_open_trades()
if not trades: if not trades:
raise RPCException('no active trade') raise RPCException('no active trade')
@ -232,8 +232,17 @@ class RPC:
trade.pair, refresh=False, side="sell") trade.pair, refresh=False, side="sell")
except (PricingError, ExchangeError): except (PricingError, ExchangeError):
current_rate = NAN current_rate = NAN
trade_profit = trade.calc_profit(current_rate) if show_order:
profit_str = f'{trade.calc_profit_ratio(current_rate):.2%}' b_order = trade.select_order('buy', is_open=False)
amount = b_order.filled or b_order.amount
open_rate = b_order.average or b_order.price
open_cost=open_rate * amount * (1+ trade.fee_open)
trade_profit = trade.calc_profit2(open_rate, current_rate, amount)
profit_pct = ( open_cost + profit)/open_cost - 1
profit_str = f'{profit_pct:.2%}'
else:
trade_profit = trade.calc_profit(current_rate)
profit_str = f'{trade.calc_profit_ratio(current_rate):.2%}'
if self._fiat_converter: if self._fiat_converter:
fiat_profit = self._fiat_converter.convert_amount( fiat_profit = self._fiat_converter.convert_amount(
trade_profit, trade_profit,
@ -244,11 +253,14 @@ class RPC:
profit_str += f" ({fiat_profit:.2f})" profit_str += f" ({fiat_profit:.2f})"
fiat_profit_sum = fiat_profit if isnan(fiat_profit_sum) \ fiat_profit_sum = fiat_profit if isnan(fiat_profit_sum) \
else fiat_profit_sum + fiat_profit else fiat_profit_sum + fiat_profit
last_sell_order = trade.select_order('sell')
last_sell_order_id = last_sell_order.order_id if last_sell_order else None
detail_trade = [ detail_trade = [
trade.id, trade.id,
trade.pair + ('*' if (trade.open_order_id is not None trade.pair + ('*' if (trade.open_order_id ==
and trade.close_rate_requested is None) else '') trade.select_order('buy').order_id) else '')
+ ('**' if (trade.close_rate_requested is not None) else ''), + ('**' if (trade.open_order_id ==
last_sell_order_id) else ''),
shorten_date(arrow.get(trade.open_date).humanize(only_distance=True)), shorten_date(arrow.get(trade.open_date).humanize(only_distance=True)),
profit_str profit_str
] ]

View File

@ -291,7 +291,6 @@ class Telegram(RPCHandler):
f"`{msg['profit_ratio']:.2%}{msg['profit_extra']}`\n" f"`{msg['profit_ratio']:.2%}{msg['profit_extra']}`\n"
f"*Buy Tag:* `{msg['buy_tag']}`\n" f"*Buy Tag:* `{msg['buy_tag']}`\n"
f"*Sell Reason:* `{msg['sell_reason']}`\n" f"*Sell Reason:* `{msg['sell_reason']}`\n"
f"*Duration:* `{msg['duration']} ({msg['duration_min']:.1f} min)`\n"
f"*Amount:* `{msg['amount']:.8f}`\n" f"*Amount:* `{msg['amount']:.8f}`\n"
f"*Open Rate:* `{msg['open_rate']:.8f}`\n") f"*Open Rate:* `{msg['open_rate']:.8f}`\n")
@ -314,6 +313,8 @@ class Telegram(RPCHandler):
message += f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}" message += f", {round_coin_value(msg['stake_amount_fiat'], msg['fiat_currency'])}"
message += ")`" message += ")`"
else:
message += f"\n*Duration:* `{msg['duration']} ({msg['duration_min']:.1f} min)`"
return message return message
def compose_message(self, msg: Dict[str, Any], msg_type: RPCMessageType) -> str: def compose_message(self, msg: Dict[str, Any], msg_type: RPCMessageType) -> str:
@ -453,7 +454,9 @@ class Telegram(RPCHandler):
if context.args and 'table' in context.args: if context.args and 'table' in context.args:
self._status_table(update, context) self._status_table(update, context)
return return
if context.args and 'order' in context.args:
self._status_table(update, context, show_order=True)
return
try: try:
# Check if there's at least one numerical ID provided. # Check if there's at least one numerical ID provided.
@ -525,7 +528,7 @@ class Telegram(RPCHandler):
self._send_msg(str(e)) self._send_msg(str(e))
@authorized_only @authorized_only
def _status_table(self, update: Update, context: CallbackContext) -> None: def _status_table(self, update: Update, context: CallbackContext, show_order: bool = False) -> None:
""" """
Handler for /status table. Handler for /status table.
Returns the current TradeThread status in table format Returns the current TradeThread status in table format
@ -536,7 +539,7 @@ class Telegram(RPCHandler):
try: try:
fiat_currency = self._config.get('fiat_display_currency', '') fiat_currency = self._config.get('fiat_display_currency', '')
statlist, head, fiat_profit_sum = self._rpc._rpc_status_table( statlist, head, fiat_profit_sum = self._rpc._rpc_status_table(
self._config['stake_currency'], fiat_currency) self._config['stake_currency'], fiat_currency, show_order)
show_total = not isnan(fiat_profit_sum) and len(statlist) > 1 show_total = not isnan(fiat_profit_sum) and len(statlist) > 1
max_trades_per_msg = 50 max_trades_per_msg = 50

View File

@ -1879,11 +1879,11 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
'*Unrealized Profit:* `-57.41% (loss: -0.05746268 ETH / -24.812 USD)`\n' '*Unrealized Profit:* `-57.41% (loss: -0.05746268 ETH / -24.812 USD)`\n'
'*Buy Tag:* `buy_signal1`\n' '*Buy Tag:* `buy_signal1`\n'
'*Sell Reason:* `stop_loss`\n' '*Sell Reason:* `stop_loss`\n'
'*Duration:* `1:00:00 (60.0 min)`\n'
'*Amount:* `1333.33333333`\n' '*Amount:* `1333.33333333`\n'
'*Open Rate:* `0.00007500`\n' '*Open Rate:* `0.00007500`\n'
'*Current Rate:* `0.00003201`\n' '*Current Rate:* `0.00003201`\n'
'*Close Rate:* `0.00003201`' '*Close Rate:* `0.00003201`\n'
'*Duration:* `1:00:00 (60.0 min)`'
) )
msg_mock.reset_mock() msg_mock.reset_mock()
@ -1911,11 +1911,11 @@ def test_send_msg_sell_notification(default_conf, mocker) -> None:
'*Unrealized Profit:* `-57.41%`\n' '*Unrealized Profit:* `-57.41%`\n'
'*Buy Tag:* `buy_signal1`\n' '*Buy Tag:* `buy_signal1`\n'
'*Sell Reason:* `stop_loss`\n' '*Sell Reason:* `stop_loss`\n'
'*Duration:* `1 day, 2:30:00 (1590.0 min)`\n'
'*Amount:* `1333.33333333`\n' '*Amount:* `1333.33333333`\n'
'*Open Rate:* `0.00007500`\n' '*Open Rate:* `0.00007500`\n'
'*Current Rate:* `0.00003201`\n' '*Current Rate:* `0.00003201`\n'
'*Close Rate:* `0.00003201`' '*Close Rate:* `0.00003201`\n'
'*Duration:* `1 day, 2:30:00 (1590.0 min)`'
) )
# Reset singleton function to avoid random breaks # Reset singleton function to avoid random breaks
telegram._rpc._fiat_converter.convert_amount = old_convamount telegram._rpc._fiat_converter.convert_amount = old_convamount
@ -1982,10 +1982,10 @@ def test_send_msg_sell_fill_notification(default_conf, mocker) -> None:
'*Profit:* `-57.41%`\n' '*Profit:* `-57.41%`\n'
'*Buy Tag:* `buy_signal1`\n' '*Buy Tag:* `buy_signal1`\n'
'*Sell Reason:* `stop_loss`\n' '*Sell Reason:* `stop_loss`\n'
'*Duration:* `1 day, 2:30:00 (1590.0 min)`\n'
'*Amount:* `1333.33333333`\n' '*Amount:* `1333.33333333`\n'
'*Open Rate:* `0.00007500`\n' '*Open Rate:* `0.00007500`\n'
'*Close Rate:* `0.00003201`' '*Close Rate:* `0.00003201`\n'
'*Duration:* `1 day, 2:30:00 (1590.0 min)`'
) )
@ -2081,11 +2081,11 @@ def test_send_msg_sell_notification_no_fiat(default_conf, mocker) -> None:
'*Unrealized Profit:* `-57.41%`\n' '*Unrealized Profit:* `-57.41%`\n'
'*Buy Tag:* `buy_signal1`\n' '*Buy Tag:* `buy_signal1`\n'
'*Sell Reason:* `stop_loss`\n' '*Sell Reason:* `stop_loss`\n'
'*Duration:* `2:35:03 (155.1 min)`\n'
'*Amount:* `1333.33333333`\n' '*Amount:* `1333.33333333`\n'
'*Open Rate:* `0.00007500`\n' '*Open Rate:* `0.00007500`\n'
'*Current Rate:* `0.00003201`\n' '*Current Rate:* `0.00003201`\n'
'*Close Rate:* `0.00003201`' '*Close Rate:* `0.00003201`\n'
'*Duration:* `2:35:03 (155.1 min)`'
) )

View File

@ -4559,6 +4559,8 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None:
trade = Trade.query.first() trade = Trade.query.first()
assert trade assert trade
assert trade.open_order_id is None assert trade.open_order_id is None
assert trade.is_open
print(trade.is_open)
assert trade.amount == 22 assert trade.amount == 22
assert trade.stake_amount == 203.5625 assert trade.stake_amount == 203.5625
assert pytest.approx(trade.open_rate) == 9.252840909090908 assert pytest.approx(trade.open_rate) == 9.252840909090908
@ -4571,6 +4573,284 @@ def test_position_adjust(mocker, default_conf_usdt, fee) -> None:
order = trade.select_order('sell', False) order = trade.select_order('sell', False)
assert order.order_id == '653' assert order.order_id == '653'
def test_position_adjust2(mocker, default_conf_usdt, fee) -> None:
patch_RPCManager(mocker)
patch_exchange(mocker)
patch_wallet(mocker, free=10000)
default_conf_usdt.update({
"position_adjustment_enable": True,
"dry_run": False,
"stake_amount": 10.0,
"dry_run_wallet": 1000.0,
})
freqtrade = FreqtradeBot(default_conf_usdt)
freqtrade.strategy.confirm_trade_entry = MagicMock(return_value=True)
bid = 11
stake_amount = 10
buy_rate_mock = MagicMock(return_value=bid)
mocker.patch.multiple(
'freqtrade.exchange.Exchange',
get_rate=buy_rate_mock,
fetch_ticker=MagicMock(return_value={
'bid': 10,
'ask': 12,
'last': 11
}),
get_min_pair_stake_amount=MagicMock(return_value=1),
get_fee=fee,
)
pair = 'ETH/USDT'
# Initial buy
closed_successful_buy_order = {
'pair': pair,
'ft_pair': pair,
'ft_order_side': 'buy',
'side': 'buy',
'type': 'limit',
'status': 'closed',
'price': bid,
'average': bid,
'cost': bid * stake_amount,
'amount': stake_amount,
'filled': stake_amount,
'ft_is_open': False,
'id': '650',
'order_id': '650'
}
mocker.patch('freqtrade.exchange.Exchange.create_order',
MagicMock(return_value=closed_successful_buy_order))
mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order',
MagicMock(return_value=closed_successful_buy_order))
assert freqtrade.execute_entry(pair, stake_amount)
# Should create an closed trade with an no open order id
# Order is filled and trade is open
orders = Order.query.all()
assert orders
assert len(orders) == 1
trade = Trade.query.first()
assert trade
assert trade.is_open is True
assert trade.open_order_id is None
assert trade.open_rate == 11
assert trade.stake_amount == 110
# Assume it does nothing since order is closed and trade is open
freqtrade.update_closed_trades_without_assigned_fees()
trade = Trade.query.first()
assert trade
assert trade.is_open is True
assert trade.open_order_id is None
assert trade.open_rate == 11
assert trade.stake_amount == 110
assert not trade.fee_updated('buy')
freqtrade.check_handle_timedout()
trade = Trade.query.first()
assert trade
assert trade.is_open is True
assert trade.open_order_id is None
assert trade.open_rate == 11
assert trade.stake_amount == 110
assert not trade.fee_updated('buy')
# First position adjustment buy.
open_dca_order_1 = {
'ft_pair': pair,
'ft_order_side': 'buy',
'side': 'buy',
'type': 'limit',
'status': None,
'price': 9,
'amount': 12,
'cost': 108,
'ft_is_open': True,
'id': '651',
'order_id': '651'
}
mocker.patch('freqtrade.exchange.Exchange.create_order',
MagicMock(return_value=open_dca_order_1))
mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order',
MagicMock(return_value=open_dca_order_1))
assert freqtrade.execute_entry(pair, stake_amount, trade=trade)
orders = Order.query.all()
assert orders
assert len(orders) == 2
trade = Trade.query.first()
assert trade
assert trade.open_order_id == '651'
assert trade.open_rate == 11
assert trade.amount == 10
assert trade.stake_amount == 110
assert not trade.fee_updated('buy')
trades: List[Trade] = Trade.get_open_trades_without_assigned_fees()
assert len(trades) == 1
assert trade.is_open
assert not trade.fee_updated('buy')
order = trade.select_order('buy', False)
assert order
assert order.order_id == '650'
def make_sure_its_651(*args, **kwargs):
if args[0] == '650':
return closed_successful_buy_order
if args[0] == '651':
return open_dca_order_1
return None
# Assume it does nothing since order is still open
fetch_order_mm = MagicMock(side_effect=make_sure_its_651)
mocker.patch('freqtrade.exchange.Exchange.create_order', fetch_order_mm)
mocker.patch('freqtrade.exchange.Exchange.fetch_order', fetch_order_mm)
mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order', fetch_order_mm)
freqtrade.update_closed_trades_without_assigned_fees()
orders = Order.query.all()
assert orders
assert len(orders) == 2
# Assert that the trade is found as open and without fees
trades: List[Trade] = Trade.get_open_trades_without_assigned_fees()
assert len(trades) == 1
# Assert trade is as expected
trade = Trade.query.first()
assert trade
assert trade.open_order_id == '651'
assert trade.open_rate == 11
assert trade.amount == 10
assert trade.stake_amount == 110
assert not trade.fee_updated('buy')
# Make sure the closed order is found as the first order.
order = trade.select_order('buy', False)
assert order.order_id == '650'
# Now close the order so it should update.
closed_dca_order_1 = {
'ft_pair': pair,
'ft_order_side': 'buy',
'side': 'buy',
'type': 'limit',
'status': 'closed',
'price': 9,
'average': 9,
'amount': 12,
'filled': 12,
'cost': 108,
'ft_is_open': False,
'id': '651',
'order_id': '651'
}
mocker.patch('freqtrade.exchange.Exchange.create_order',
MagicMock(return_value=closed_dca_order_1))
mocker.patch('freqtrade.exchange.Exchange.fetch_order',
MagicMock(return_value=closed_dca_order_1))
mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order',
MagicMock(return_value=closed_dca_order_1))
freqtrade.check_handle_timedout()
# Assert trade is as expected (averaged dca)
trade = Trade.query.first()
assert trade
assert trade.open_order_id is None
assert pytest.approx(trade.open_rate) == 9.90909090909
assert trade.amount == 22
assert trade.stake_amount == 218
orders = Order.query.all()
assert orders
assert len(orders) == 2
# Make sure the closed order is found as the second order.
order = trade.select_order('buy', False)
assert order.order_id == '651'
# Assert that the trade is not found as open and without fees
trades: List[Trade] = Trade.get_open_trades_without_assigned_fees()
assert len(trades) == 1
# Add a second DCA
closed_dca_order_2 = {
'ft_pair': pair,
'status': 'closed',
'ft_order_side': 'buy',
'side': 'buy',
'type': 'limit',
'price': 7,
'average': 7,
'amount': 15,
'filled': 15,
'cost': 105,
'ft_is_open': False,
'id': '652',
'order_id': '652'
}
mocker.patch('freqtrade.exchange.Exchange.create_order',
MagicMock(return_value=closed_dca_order_2))
mocker.patch('freqtrade.exchange.Exchange.fetch_order',
MagicMock(return_value=closed_dca_order_2))
mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order',
MagicMock(return_value=closed_dca_order_2))
assert freqtrade.execute_entry(pair, stake_amount, trade=trade)
# Assert trade is as expected (averaged dca)
trade = Trade.query.first()
assert trade
assert trade.open_order_id is None
assert pytest.approx(trade.open_rate) == 8.729729729729
assert trade.amount == 37
assert trade.stake_amount == 323
orders = Order.query.all()
assert orders
assert len(orders) == 3
# Make sure the closed order is found as the second order.
order = trade.select_order('buy', False)
assert order.order_id == '652'
closed_sell_dca_order_1 = {
'ft_pair': pair,
'status': 'closed',
'ft_order_side': 'sell',
'side': 'sell',
'type': 'limit',
'price': 8,
'average': 8,
'amount': 15,
'filled': 15,
'cost': 120,
'ft_is_open': False,
'id': '653',
'order_id': '653'
}
mocker.patch('freqtrade.exchange.Exchange.create_order',
MagicMock(return_value=closed_sell_dca_order_1))
mocker.patch('freqtrade.exchange.Exchange.fetch_order',
MagicMock(return_value=closed_sell_dca_order_1))
mocker.patch('freqtrade.exchange.Exchange.fetch_order_or_stoploss_order',
MagicMock(return_value=closed_sell_dca_order_1))
assert freqtrade.execute_trade_exit(trade=trade, limit=8,
sell_reason=SellCheckTuple(sell_type=SellType.STOP_LOSS),
sub_trade_amt=15)
# Assert trade is as expected (averaged dca)
trade = Trade.query.first()
assert trade
assert trade.open_order_id is None
assert trade.amount == 22
assert trade.stake_amount == 203.5625
assert pytest.approx(trade.open_rate) == 9.252840909090908
orders = Order.query.all()
assert orders
assert len(orders) == 4
# Make sure the closed order is found as the second order.
order = trade.select_order('sell', False)
assert order.order_id == '653'
def test_process_open_trade_positions_exception(mocker, default_conf_usdt, fee, caplog) -> None: def test_process_open_trade_positions_exception(mocker, default_conf_usdt, fee, caplog) -> None:
default_conf_usdt.update({ default_conf_usdt.update({