Merge branch 'develop' into feat/short

This commit is contained in:
Matthias
2022-02-11 17:02:04 +01:00
63 changed files with 1158 additions and 349 deletions

View File

@@ -132,9 +132,12 @@ class Order(_DECL_BASE):
order_date = Column(DateTime, nullable=True, default=datetime.utcnow)
order_filled_date = Column(DateTime, nullable=True)
order_update_date = Column(DateTime, nullable=True)
leverage = Column(Float, nullable=True, default=1.0)
@property
def order_date_utc(self):
return self.order_date.replace(tzinfo=timezone.utc)
def __repr__(self):
return (f'Order(id={self.id}, order_id={self.order_id}, trade_id={self.ft_trade_id}, '
@@ -170,6 +173,35 @@ class Order(_DECL_BASE):
self.order_filled_date = datetime.now(timezone.utc)
self.order_update_date = datetime.now(timezone.utc)
def to_json(self) -> Dict[str, Any]:
return {
'amount': self.amount,
'average': round(self.average, 8) if self.average else 0,
'cost': self.cost if self.cost else 0,
'filled': self.filled,
'ft_order_side': self.ft_order_side,
'is_open': self.ft_is_open,
'order_date': self.order_date.strftime(DATETIME_PRINT_FORMAT)
if self.order_date else None,
'order_timestamp': int(self.order_date.replace(
tzinfo=timezone.utc).timestamp() * 1000) if self.order_date else None,
'order_filled_date': self.order_filled_date.strftime(DATETIME_PRINT_FORMAT)
if self.order_filled_date else None,
'order_filled_timestamp': int(self.order_filled_date.replace(
tzinfo=timezone.utc).timestamp() * 1000) if self.order_filled_date else None,
'order_type': self.order_type,
'pair': self.ft_pair,
'price': self.price,
'remaining': self.remaining,
'status': self.status,
}
def close_bt_order(self, close_date: datetime):
self.order_filled_date = close_date
self.filled = self.amount
self.status = 'closed'
self.ft_is_open = False
@staticmethod
def update_orders(orders: List['Order'], order: Dict[str, Any]):
"""
@@ -390,6 +422,16 @@ class LocalTrade():
)
def to_json(self) -> Dict[str, Any]:
filled_orders = self.select_filled_orders()
filled_entries = []
filled_exits = []
if len(filled_orders) > 0:
for order in filled_orders:
if order.ft_order_side == 'buy':
filled_entries.append(order.to_json())
if order.ft_order_side == 'sell':
filled_exits.append(order.to_json())
return {
'trade_id': self.id,
'pair': self.pair,
@@ -460,6 +502,8 @@ class LocalTrade():
'trading_mode': self.trading_mode,
'funding_fees': self.funding_fees,
'open_order_id': self.open_order_id,
'filled_entry_orders': filled_entries,
'filled_exit_orders': filled_exits,
}
@staticmethod
@@ -794,8 +838,8 @@ class LocalTrade():
return float(f"{profit_ratio:.8f}")
def recalc_trade_from_orders(self):
# We need at least 2 orders for averaging amounts and rates.
if len(self.orders) < 2:
# We need at least 2 entry orders for averaging amounts and rates.
if len(self.select_filled_orders('buy')) < 2:
# Just in case, still recalc open trade value
self.recalc_open_trade_value()
return
@@ -825,14 +869,27 @@ class LocalTrade():
if self.stop_loss_pct is not None and self.open_rate is not None:
self.adjust_stop_loss(self.open_rate, self.stop_loss_pct)
def select_order(self, order_side: str, is_open: Optional[bool]) -> Optional[Order]:
def select_order_by_order_id(self, order_id: str) -> Optional[Order]:
"""
Finds order object by Order id.
:param order_id: Exchange order id
"""
for o in self.orders:
if o.order_id == order_id:
return o
return None
def select_order(
self, order_side: str = None, is_open: Optional[bool] = None) -> Optional[Order]:
"""
Finds latest order for this orderside and status
:param order_side: Side of the order (either 'buy' or 'sell')
:param is_open: Only search for open orders?
:return: latest Order object if it exists, else None
"""
orders = [o for o in self.orders if o.side == order_side]
orders = self.orders
if order_side:
orders = [o for o in self.orders if o.side == order_side]
if is_open is not None:
orders = [o for o in orders if o.ft_is_open == is_open]
if len(orders) > 0:
@@ -840,14 +897,14 @@ class LocalTrade():
else:
return None
def select_filled_orders(self, order_side: str) -> List['Order']:
def select_filled_orders(self, order_side: Optional[str] = None) -> List['Order']:
"""
Finds filled orders for this orderside.
:param order_side: Side of the order (either 'buy' or 'sell')
:param order_side: Side of the order (either 'buy', 'sell', or None)
:return: array of Order objects
"""
return [o for o in self.orders if o.ft_order_side == order_side and
o.ft_is_open is False and
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
(o.filled or 0) > 0 and
o.status in NON_OPEN_EXCHANGE_STATES]