Replace open_order_id property by open_orders in Trade model, first test update

This commit is contained in:
axel
2023-06-13 02:11:34 -04:00
parent 502090c199
commit 4874d10455
3 changed files with 62 additions and 18 deletions
+24 -1
View File
@@ -281,6 +281,7 @@ def fix_old_dry_orders(engine):
).values(ft_is_open=False) ).values(ft_is_open=False)
connection.execute(stmt) connection.execute(stmt)
# OLD
stmt = update(Order).where( stmt = update(Order).where(
Order.ft_is_open.is_(True), Order.ft_is_open.is_(True),
tuple_(Order.ft_trade_id, Order.order_id).not_in( tuple_(Order.ft_trade_id, Order.order_id).not_in(
@@ -294,6 +295,28 @@ def fix_old_dry_orders(engine):
).values(ft_is_open=False) ).values(ft_is_open=False)
connection.execute(stmt) connection.execute(stmt)
# Update current Order where
# -current Order is open
# -current Order trade_id not equal to current Trade.id
# -current Order not stoploss
# -order_id not equal to current Trade.stoploss_order_id
# -current Order is dry
# NEW WIP
stmt = update(Order).where(
Order.ft_is_open.is_(True),
Order.ft_trade_id.not_in(
select(Trade.id).where(Trade.open_orders_count.is_not(0))
),
Order.order_id.not_in(
select(Trade.open_orders).filter(Order.order_id).first()
),
Order.ft_order_side != 'stoploss',
Order.order_id.like('dry%')
).values(ft_is_open=False)
connection.execute(stmt)
def check_migrate(engine, decl_base, previous_tables) -> None: def check_migrate(engine, decl_base, previous_tables) -> None:
""" """
@@ -340,7 +363,7 @@ def check_migrate(engine, decl_base, previous_tables) -> None:
"start with a fresh database.") "start with a fresh database.")
set_sqlite_to_wal(engine) set_sqlite_to_wal(engine)
fix_old_dry_orders(engine) # fix_old_dry_orders(engine) # TODO Fix that
if migrating: if migrating:
logger.info("Database migration finished.") logger.info("Database migration finished.")
+33 -12
View File
@@ -9,6 +9,7 @@ from typing import Any, ClassVar, Dict, List, Optional, Sequence, cast
from sqlalchemy import (Enum, Float, ForeignKey, Integer, ScalarResult, Select, String, from sqlalchemy import (Enum, Float, ForeignKey, Integer, ScalarResult, Select, String,
UniqueConstraint, desc, func, select) UniqueConstraint, desc, func, select)
from sqlalchemy.ext.hybrid import hybrid_property
from sqlalchemy.orm import Mapped, lazyload, mapped_column, relationship, validates from sqlalchemy.orm import Mapped, lazyload, mapped_column, relationship, validates
from freqtrade.constants import (CUSTOM_TAG_MAX_LENGTH, DATETIME_PRINT_FORMAT, MATH_CLOSE_PREC, from freqtrade.constants import (CUSTOM_TAG_MAX_LENGTH, DATETIME_PRINT_FORMAT, MATH_CLOSE_PREC,
@@ -327,7 +328,7 @@ class LocalTrade():
amount_requested: Optional[float] = None amount_requested: Optional[float] = None
open_date: datetime open_date: datetime
close_date: Optional[datetime] = None close_date: Optional[datetime] = None
open_order_id: Optional[str] = None open_orders: List[Order] = []
# absolute value of the stop loss # absolute value of the stop loss
stop_loss: float = 0.0 stop_loss: float = 0.0
# percentage value of the stop loss # percentage value of the stop loss
@@ -468,6 +469,14 @@ class LocalTrade():
except IndexError: except IndexError:
return '' return ''
@hybrid_property
def open_orders_count(self) -> int:
return len(self.open_orders)
@hybrid_property
def open_orders_ids(self) -> list:
return [open_order.order_id for open_order in self.open_orders]
def __init__(self, **kwargs): def __init__(self, **kwargs):
for key in kwargs: for key in kwargs:
setattr(self, key, kwargs[key]) setattr(self, key, kwargs[key])
@@ -680,12 +689,21 @@ class LocalTrade():
if self.is_open: if self.is_open:
payment = "SELL" if self.is_short else "BUY" payment = "SELL" if self.is_short else "BUY"
logger.info(f'{order.order_type.upper()}_{payment} has been fulfilled for {self}.') logger.info(f'{order.order_type.upper()}_{payment} has been fulfilled for {self}.')
# TODO WIP but to rm if useless
# condition to avoid reset value when updating fees (new)
# if order.order_id in self.open_orders_ids:
# self.open_order_id = None
# else:
# logger.warning(
# f'Got different open_order_id {self.open_order_id} != {order.order_id}')
# TODO validate if this is still relevant
# 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: # else:
logger.warning( # logger.warning(
f'Got different open_order_id {self.open_order_id} != {order.order_id}') # 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:
@@ -693,11 +711,11 @@ class LocalTrade():
# * On margin shorts, you buy a little bit more than the amount (amount + interest) # * On margin shorts, you buy a little bit more than the amount (amount + interest)
logger.info(f'{order.order_type.upper()}_{payment} has been fulfilled for {self}.') logger.info(f'{order.order_type.upper()}_{payment} has been fulfilled for {self}.')
# 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: # else:
logger.warning( # logger.warning(
f'Got different open_order_id {self.open_order_id} != {order.order_id}') # f'Got different open_order_id {self.open_order_id} != {order.order_id}')
elif order.ft_order_side == 'stoploss' and order.status not in ('open', ): elif order.ft_order_side == 'stoploss' and order.status not in ('open', ):
self.stoploss_order_id = None self.stoploss_order_id = None
@@ -1244,7 +1262,6 @@ class Trade(ModelBase, LocalTrade):
open_date: Mapped[datetime] = mapped_column( open_date: Mapped[datetime] = mapped_column(
nullable=False, default=datetime.utcnow) # type: ignore nullable=False, default=datetime.utcnow) # type: ignore
close_date: Mapped[Optional[datetime]] = mapped_column() # type: ignore close_date: Mapped[Optional[datetime]] = mapped_column() # type: ignore
open_order_id: Mapped[Optional[str]] = mapped_column(String(255), nullable=True) # type: ignore
# absolute value of the stop loss # absolute value of the stop loss
stop_loss: Mapped[float] = mapped_column(Float(), nullable=True, default=0.0) # type: ignore stop_loss: Mapped[float] = mapped_column(Float(), nullable=True, default=0.0) # type: ignore
# percentage value of the stop loss # percentage value of the stop loss
@@ -1296,6 +1313,10 @@ class Trade(ModelBase, LocalTrade):
funding_fees: Mapped[Optional[float]] = mapped_column( funding_fees: Mapped[Optional[float]] = mapped_column(
Float(), nullable=True, default=None) # type: ignore Float(), nullable=True, default=None) # type: ignore
@hybrid_property
def open_orders(self):
return [order for order in self.orders if order.ft_is_open]
def __init__(self, **kwargs): def __init__(self, **kwargs):
super().__init__(**kwargs) super().__init__(**kwargs)
self.realized_profit = 0 self.realized_profit = 0
+5 -5
View File
@@ -437,15 +437,15 @@ def test_update_limit_order(fee, caplog, limit_buy_order_usdt, limit_sell_order_
leverage=lev, leverage=lev,
trading_mode=trading_mode trading_mode=trading_mode
) )
assert trade.open_order_id is None assert trade.open_orders_count == 0
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 = enter_order['id'] trade.open_orders.append(enter_order)
oobj = Order.parse_from_ccxt_object(enter_order, 'ADA/USDT', entry_side) oobj = Order.parse_from_ccxt_object(enter_order, 'ADA/USDT', entry_side)
trade.orders.append(oobj) trade.orders.append(oobj)
trade.update_trade(oobj) trade.update_trade(oobj)
assert trade.open_order_id is None assert trade.open_orders_count == 0
assert trade.open_rate == open_rate assert trade.open_rate == open_rate
assert trade.close_profit is None assert trade.close_profit is None
assert trade.close_date is None assert trade.close_date is None
@@ -456,13 +456,13 @@ def test_update_limit_order(fee, caplog, limit_buy_order_usdt, limit_sell_order_
caplog) caplog)
caplog.clear() caplog.clear()
trade.open_order_id = enter_order['id'] trade.open_orders.append(enter_order)
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.orders.append(oobj) trade.orders.append(oobj)
trade.update_trade(oobj) trade.update_trade(oobj)
assert trade.open_order_id is None assert trade.open_orders_count == 0
assert trade.close_rate == close_rate assert trade.close_rate == close_rate
assert pytest.approx(trade.close_profit) == profit assert pytest.approx(trade.close_profit) == profit
assert trade.close_date is not None assert trade.close_date is not None