Merge branch 'develop' into feat/short
This commit is contained in:
@@ -191,19 +191,22 @@ def drop_orders_table(engine, table_back_name: str):
|
||||
connection.execute(text("drop table orders"))
|
||||
|
||||
|
||||
def migrate_orders_table(engine, table_back_name: str, cols: List):
|
||||
def migrate_orders_table(engine, table_back_name: str, cols_order: List):
|
||||
|
||||
ft_fee_base = get_column_def(cols_order, 'ft_fee_base', 'null')
|
||||
|
||||
# let SQLAlchemy create the schema as required
|
||||
leverage = get_column_def(cols, 'leverage', '1.0')
|
||||
leverage = get_column_def(cols_order, 'leverage', '1.0')
|
||||
# sqlite does not support literals for booleans
|
||||
with engine.begin() as connection:
|
||||
connection.execute(text(f"""
|
||||
insert into orders ( id, ft_trade_id, ft_order_side, ft_pair, ft_is_open, order_id,
|
||||
status, symbol, order_type, side, price, amount, filled, average, remaining, cost,
|
||||
order_date, order_filled_date, order_update_date, leverage)
|
||||
order_date, order_filled_date, order_update_date, ft_fee_base, leverage)
|
||||
select id, ft_trade_id, ft_order_side, ft_pair, ft_is_open, order_id,
|
||||
status, symbol, order_type, side, price, amount, filled, null average, remaining, cost,
|
||||
order_date, order_filled_date, order_update_date, {leverage} leverage
|
||||
order_date, order_filled_date, order_update_date, {ft_fee_base} ft_fee_base,
|
||||
{leverage} leverage
|
||||
from {table_back_name}
|
||||
"""))
|
||||
|
||||
@@ -222,22 +225,22 @@ def check_migrate(engine, decl_base, previous_tables) -> None:
|
||||
inspector = inspect(engine)
|
||||
|
||||
cols = inspector.get_columns('trades')
|
||||
cols_orders = inspector.get_columns('orders')
|
||||
tabs = get_table_names_for_table(inspector, 'trades')
|
||||
cols_order = inspector.get_columns('orders')
|
||||
table_back_name = get_backup_name(tabs, 'trades_bak')
|
||||
order_tabs = get_table_names_for_table(inspector, 'orders')
|
||||
order_table_bak_name = get_backup_name(order_tabs, 'orders_bak')
|
||||
|
||||
# Check if migration necessary
|
||||
# Migrates both trades and orders table!
|
||||
if not has_column(cols, 'enter_tag'):
|
||||
# if not has_column(cols, 'buy_tag'):
|
||||
if ('orders' not in previous_tables
|
||||
or not has_column(cols_orders, 'ft_fee_base')
|
||||
or not has_column(cols_orders, 'leverage')):
|
||||
logger.info(f"Running database migration for trades - "
|
||||
f"backup: {table_back_name}, {order_table_bak_name}")
|
||||
migrate_trades_and_orders_table(
|
||||
decl_base, inspector, engine, table_back_name, cols, order_table_bak_name, cols_order)
|
||||
# Reread columns - the above recreated the table!
|
||||
inspector = inspect(engine)
|
||||
cols = inspector.get_columns('trades')
|
||||
decl_base, inspector, engine, table_back_name, cols, order_table_bak_name, cols_orders)
|
||||
|
||||
if 'orders' not in previous_tables and 'trades' in previous_tables:
|
||||
logger.info('Moving open orders to Orders table.')
|
||||
|
@@ -17,7 +17,6 @@ from freqtrade.constants import DATETIME_PRINT_FORMAT, NON_OPEN_EXCHANGE_STATES
|
||||
from freqtrade.enums import SellType, TradingMode
|
||||
from freqtrade.exceptions import DependencyException, OperationalException
|
||||
from freqtrade.leverage import interest
|
||||
from freqtrade.misc import safe_value_fallback
|
||||
from freqtrade.persistence.migrations import check_migrate
|
||||
|
||||
|
||||
@@ -117,14 +116,15 @@ class Order(_DECL_BASE):
|
||||
|
||||
trade = relationship("Trade", back_populates="orders")
|
||||
|
||||
ft_order_side = Column(String(25), nullable=False)
|
||||
ft_pair = Column(String(25), nullable=False)
|
||||
# order_side can only be 'buy', 'sell' or 'stoploss'
|
||||
ft_order_side: str = Column(String(25), nullable=False)
|
||||
ft_pair: str = Column(String(25), nullable=False)
|
||||
ft_is_open = Column(Boolean, nullable=False, default=True, index=True)
|
||||
|
||||
order_id = Column(String(255), nullable=False, index=True)
|
||||
status = Column(String(255), nullable=True)
|
||||
symbol = Column(String(25), nullable=True)
|
||||
order_type = Column(String(50), nullable=True)
|
||||
order_type: str = Column(String(50), nullable=True)
|
||||
side = Column(String(25), nullable=True)
|
||||
price = Column(Float, nullable=True)
|
||||
average = Column(Float, nullable=True)
|
||||
@@ -137,10 +137,29 @@ class Order(_DECL_BASE):
|
||||
order_update_date = Column(DateTime, nullable=True)
|
||||
leverage = Column(Float, nullable=True, default=1.0)
|
||||
|
||||
ft_fee_base = Column(Float, nullable=True)
|
||||
|
||||
@property
|
||||
def order_date_utc(self):
|
||||
def order_date_utc(self) -> datetime:
|
||||
""" Order-date with UTC timezoneinfo"""
|
||||
return self.order_date.replace(tzinfo=timezone.utc)
|
||||
|
||||
@property
|
||||
def safe_price(self) -> float:
|
||||
return self.average or self.price
|
||||
|
||||
@property
|
||||
def safe_filled(self) -> float:
|
||||
return self.filled or self.amount or 0.0
|
||||
|
||||
@property
|
||||
def safe_fee_base(self) -> float:
|
||||
return self.ft_fee_base or 0.0
|
||||
|
||||
@property
|
||||
def safe_amount_after_fee(self) -> float:
|
||||
return self.safe_filled - self.safe_fee_base
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
return (f'Order(id={self.id}, order_id={self.order_id}, trade_id={self.ft_trade_id}, '
|
||||
@@ -584,50 +603,46 @@ class LocalTrade():
|
||||
f"Trailing stoploss saved us: "
|
||||
f"{float(self.stop_loss) - float(self.initial_stop_loss):.8f}.")
|
||||
|
||||
def update(self, order: Dict) -> None:
|
||||
def update_trade(self, order: Order) -> None:
|
||||
"""
|
||||
Updates this entity with amount and actual open/close rates.
|
||||
:param order: order retrieved by exchange.fetch_order()
|
||||
:return: None
|
||||
"""
|
||||
order_type = order['type']
|
||||
|
||||
if 'is_short' in order and order['side'] == 'sell':
|
||||
# Only set's is_short on opening trades, ignores non-shorts
|
||||
self.is_short = order['is_short']
|
||||
|
||||
# Ignore open and cancelled orders
|
||||
if order['status'] == 'open' or safe_value_fallback(order, 'average', 'price') is None:
|
||||
if order.status == 'open' or order.safe_price is None:
|
||||
return
|
||||
|
||||
logger.info('Updating trade (id=%s) ...', self.id)
|
||||
logger.info(f'Updating trade (id={self.id}) ...')
|
||||
|
||||
if order_type in ('market', 'limit') and self.enter_side == order['side']:
|
||||
if order.ft_order_side == self.enter_side:
|
||||
# Update open rate and actual amount
|
||||
self.open_rate = float(safe_value_fallback(order, 'average', 'price'))
|
||||
self.amount = float(safe_value_fallback(order, 'filled', 'amount'))
|
||||
if 'leverage' in order:
|
||||
self.leverage = order['leverage']
|
||||
self.open_rate = order.safe_price
|
||||
self.amount = order.safe_amount_after_fee
|
||||
# if 'leverage' in order:
|
||||
# TODO-lev: order.leverage is not properly filled on the order object!
|
||||
# self.leverage = order.leverage
|
||||
if self.is_open:
|
||||
payment = "SELL" if self.is_short else "BUY"
|
||||
logger.info(f'{order_type.upper()}_{payment} has been fulfilled for {self}.')
|
||||
logger.info(f'{order.order_type.upper()}_{payment} has been fulfilled for {self}.')
|
||||
self.open_order_id = None
|
||||
self.recalc_trade_from_orders()
|
||||
elif order_type in ('market', 'limit') and self.exit_side == order['side']:
|
||||
elif order.ft_order_side == self.exit_side:
|
||||
if self.is_open:
|
||||
payment = "BUY" if self.is_short else "SELL"
|
||||
# * On margin shorts, you buy a little bit more than the amount (amount + interest)
|
||||
logger.info(f'{order_type.upper()}_{payment} has been fulfilled for {self}.')
|
||||
self.close(safe_value_fallback(order, 'average', 'price'))
|
||||
elif order_type in ('stop_loss_limit', 'stop-loss', 'stop-loss-limit', 'stop'):
|
||||
logger.info(f'{order.order_type.upper()}_{payment} has been fulfilled for {self}.')
|
||||
self.close(order.safe_price)
|
||||
elif order.ft_order_side == 'stoploss':
|
||||
self.stoploss_order_id = None
|
||||
self.close_rate_requested = self.stop_loss
|
||||
self.sell_reason = SellType.STOPLOSS_ON_EXCHANGE.value
|
||||
if self.is_open:
|
||||
logger.info(f'{order_type.upper()} is hit for {self}.')
|
||||
self.close(safe_value_fallback(order, 'average', 'price'))
|
||||
logger.info(f'{order.order_type.upper()} is hit for {self}.')
|
||||
self.close(order.safe_price)
|
||||
else:
|
||||
raise ValueError(f'Unknown order type: {order_type}')
|
||||
raise ValueError(f'Unknown order type: {order.order_type}')
|
||||
Trade.commit()
|
||||
|
||||
def close(self, rate: float, *, show_msg: bool = True) -> None:
|
||||
@@ -857,7 +872,7 @@ class LocalTrade():
|
||||
(o.status not in NON_OPEN_EXCHANGE_STATES)):
|
||||
continue
|
||||
|
||||
tmp_amount = o.amount
|
||||
tmp_amount = o.safe_amount_after_fee
|
||||
tmp_price = o.average or o.price
|
||||
if o.filled is not None:
|
||||
tmp_amount = o.filled
|
||||
|
Reference in New Issue
Block a user