Added changed to persistance/migrations
This commit is contained in:
parent
69e81100e4
commit
20dcd9a1a2
@ -47,6 +47,13 @@ def migrate_trades_table(decl_base, inspector, engine, table_back_name: str, col
|
|||||||
min_rate = get_column_def(cols, 'min_rate', 'null')
|
min_rate = get_column_def(cols, 'min_rate', 'null')
|
||||||
close_reason = get_column_def(cols, 'close_reason', 'null')
|
close_reason = get_column_def(cols, 'close_reason', 'null')
|
||||||
strategy = get_column_def(cols, 'strategy', 'null')
|
strategy = get_column_def(cols, 'strategy', 'null')
|
||||||
|
|
||||||
|
leverage = get_column_def(cols, 'leverage', '0.0')
|
||||||
|
borrowed = get_column_def(cols, 'borrowed', '0.0')
|
||||||
|
borrowed_currency = get_column_def(cols, 'borrowed_currency', 'null')
|
||||||
|
interest_rate = get_column_def(cols, 'interest_rate', '0.0')
|
||||||
|
min_stoploss = get_column_def(cols, 'min_stoploss', 'null')
|
||||||
|
is_short = get_column_def(cols, 'is_short', 'False')
|
||||||
# If ticker-interval existed use that, else null.
|
# If ticker-interval existed use that, else null.
|
||||||
if has_column(cols, 'ticker_interval'):
|
if has_column(cols, 'ticker_interval'):
|
||||||
timeframe = get_column_def(cols, 'timeframe', 'ticker_interval')
|
timeframe = get_column_def(cols, 'timeframe', 'ticker_interval')
|
||||||
@ -81,7 +88,8 @@ def migrate_trades_table(decl_base, inspector, engine, table_back_name: str, col
|
|||||||
stop_loss, stop_loss_pct, initial_stop_loss, initial_stop_loss_pct,
|
stop_loss, stop_loss_pct, initial_stop_loss, initial_stop_loss_pct,
|
||||||
stoploss_order_id, stoploss_last_update,
|
stoploss_order_id, stoploss_last_update,
|
||||||
max_rate, min_rate, close_reason, close_order_status, strategy,
|
max_rate, min_rate, close_reason, close_order_status, strategy,
|
||||||
timeframe, open_trade_value, close_profit_abs
|
timeframe, open_trade_value, close_profit_abs,
|
||||||
|
leverage, borrowed, borrowed_currency, interest_rate, min_stoploss, is_short
|
||||||
)
|
)
|
||||||
select id, lower(exchange),
|
select id, lower(exchange),
|
||||||
case
|
case
|
||||||
@ -104,11 +112,13 @@ def migrate_trades_table(decl_base, inspector, engine, table_back_name: str, col
|
|||||||
{max_rate} max_rate, {min_rate} min_rate, {close_reason} close_reason,
|
{max_rate} max_rate, {min_rate} min_rate, {close_reason} close_reason,
|
||||||
{close_order_status} close_order_status,
|
{close_order_status} close_order_status,
|
||||||
{strategy} strategy, {timeframe} timeframe,
|
{strategy} strategy, {timeframe} timeframe,
|
||||||
{open_trade_value} open_trade_value, {close_profit_abs} close_profit_abs
|
{open_trade_value} open_trade_value, {close_profit_abs} close_profit_abs,
|
||||||
|
{leverage} leverage, {borrowed} borrowed, {borrowed_currency} borrowed_currency,
|
||||||
|
{interest_rate} interest_rate, {min_stoploss} min_stoploss, {is_short} is_short
|
||||||
from {table_back_name}
|
from {table_back_name}
|
||||||
"""))
|
"""))
|
||||||
|
|
||||||
|
#TODO: Does leverage go in here?
|
||||||
def migrate_open_orders_to_trades(engine):
|
def migrate_open_orders_to_trades(engine):
|
||||||
with engine.begin() as connection:
|
with engine.begin() as connection:
|
||||||
connection.execute(text("""
|
connection.execute(text("""
|
||||||
@ -141,10 +151,10 @@ def migrate_orders_table(decl_base, inspector, engine, table_back_name: str, col
|
|||||||
connection.execute(text(f"""
|
connection.execute(text(f"""
|
||||||
insert into orders ( id, ft_trade_id, ft_order_side, ft_pair, ft_is_open, order_id,
|
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,
|
status, symbol, order_type, side, price, amount, filled, average, remaining, cost,
|
||||||
order_date, order_filled_date, order_update_date)
|
order_date, order_filled_date, order_update_date, leverage)
|
||||||
select id, ft_trade_id, ft_order_side, ft_pair, ft_is_open, order_id,
|
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,
|
status, symbol, order_type, side, price, amount, filled, null average, remaining, cost,
|
||||||
order_date, order_filled_date, order_update_date
|
order_date, order_filled_date, order_update_date, leverage
|
||||||
from {table_back_name}
|
from {table_back_name}
|
||||||
"""))
|
"""))
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ class Order(_DECL_BASE):
|
|||||||
order_filled_date = Column(DateTime, nullable=True)
|
order_filled_date = Column(DateTime, nullable=True)
|
||||||
order_update_date = Column(DateTime, nullable=True)
|
order_update_date = Column(DateTime, nullable=True)
|
||||||
|
|
||||||
leverage = Column(Float, nullable=True)
|
leverage = Column(Float, nullable=True, default=0.0)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return (f'Order(id={self.id}, order_id={self.order_id}, trade_id={self.ft_trade_id}, '
|
return (f'Order(id={self.id}, order_id={self.order_id}, trade_id={self.ft_trade_id}, '
|
||||||
@ -262,16 +262,28 @@ class LocalTrade():
|
|||||||
strategy: str = ''
|
strategy: str = ''
|
||||||
timeframe: Optional[int] = None
|
timeframe: Optional[int] = None
|
||||||
|
|
||||||
#Margin trading properties
|
# Margin trading properties
|
||||||
leverage: Optional[float] = None
|
leverage: Optional[float] = 0.0
|
||||||
borrowed: float = 0
|
borrowed: float = 0.0
|
||||||
borrowed_currency: float = None
|
borrowed_currency: float = None
|
||||||
interest_rate: float = 0
|
interest_rate: float = 0.0
|
||||||
min_stoploss: float = None
|
min_stoploss: float = None
|
||||||
isShort: boolean = False
|
is_short: bool = False
|
||||||
#End of margin trading properties
|
# End of margin trading properties
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
|
lev = kwargs.get('leverage')
|
||||||
|
bor = kwargs.get('borrowed')
|
||||||
|
amount = kwargs.get('amount')
|
||||||
|
if lev and bor:
|
||||||
|
# TODO: should I raise an error?
|
||||||
|
raise OperationalException('Cannot pass both borrowed and leverage to Trade')
|
||||||
|
elif lev:
|
||||||
|
self.amount = amount * lev
|
||||||
|
self.borrowed = amount * (lev-1)
|
||||||
|
elif bor:
|
||||||
|
self.lev = (bor + amount)/amount
|
||||||
|
|
||||||
for key in kwargs:
|
for key in kwargs:
|
||||||
setattr(self, key, kwargs[key])
|
setattr(self, key, kwargs[key])
|
||||||
self.recalc_open_trade_value()
|
self.recalc_open_trade_value()
|
||||||
@ -398,8 +410,8 @@ class LocalTrade():
|
|||||||
return
|
return
|
||||||
|
|
||||||
new_loss = float(current_price * (1 - abs(stoploss)))
|
new_loss = float(current_price * (1 - abs(stoploss)))
|
||||||
#TODO: Could maybe move this if into the new stoploss if branch
|
# TODO: Could maybe move this if into the new stoploss if branch
|
||||||
if (self.min_stoploss): #If trading on margin, don't set the stoploss below the liquidation price
|
if (self.min_stoploss): # If trading on margin, don't set the stoploss below the liquidation price
|
||||||
new_loss = min(self.min_stoploss, new_loss)
|
new_loss = min(self.min_stoploss, new_loss)
|
||||||
|
|
||||||
# no stop loss assigned yet
|
# no stop loss assigned yet
|
||||||
@ -411,7 +423,8 @@ class LocalTrade():
|
|||||||
|
|
||||||
# evaluate if the stop loss needs to be updated
|
# evaluate if the stop loss needs to be updated
|
||||||
else:
|
else:
|
||||||
if (new_loss > self.stop_loss and not self.isShort) or (new_loss < self.stop_loss and self.isShort): # stop losses only walk up, never down!, #TODO: But adding more to a margin account would create a lower liquidation price, decreasing the minimum stoploss
|
# stop losses only walk up, never down!, #TODO: But adding more to a margin account would create a lower liquidation price, decreasing the minimum stoploss
|
||||||
|
if (new_loss > self.stop_loss and not self.is_short) or (new_loss < self.stop_loss and self.is_short):
|
||||||
logger.debug(f"{self.pair} - Adjusting stoploss...")
|
logger.debug(f"{self.pair} - Adjusting stoploss...")
|
||||||
self._set_new_stoploss(new_loss, stoploss)
|
self._set_new_stoploss(new_loss, stoploss)
|
||||||
else:
|
else:
|
||||||
@ -430,14 +443,14 @@ class LocalTrade():
|
|||||||
Determines if the trade is an opening (long buy or short sell) trade
|
Determines if the trade is an opening (long buy or short sell) trade
|
||||||
:param side (string): the side (buy/sell) that order happens on
|
:param side (string): the side (buy/sell) that order happens on
|
||||||
"""
|
"""
|
||||||
return (side == 'buy' and not self.isShort) or (side == 'sell' and self.isShort)
|
return (side == 'buy' and not self.is_short) or (side == 'sell' and self.is_short)
|
||||||
|
|
||||||
def is_closing_trade(self, side) -> bool:
|
def is_closing_trade(self, side) -> bool:
|
||||||
"""
|
"""
|
||||||
Determines if the trade is an closing (long sell or short buy) trade
|
Determines if the trade is an closing (long sell or short buy) trade
|
||||||
:param side (string): the side (buy/sell) that order happens on
|
:param side (string): the side (buy/sell) that order happens on
|
||||||
"""
|
"""
|
||||||
return (side == 'sell' and not self.isShort) or (side == 'buy' and self.isShort)
|
return (side == 'sell' and not self.is_short) or (side == 'buy' and self.is_short)
|
||||||
|
|
||||||
def update(self, order: Dict) -> None:
|
def update(self, order: Dict) -> None:
|
||||||
"""
|
"""
|
||||||
@ -458,14 +471,14 @@ class LocalTrade():
|
|||||||
self.amount = float(safe_value_fallback(order, 'filled', 'amount'))
|
self.amount = float(safe_value_fallback(order, 'filled', 'amount'))
|
||||||
self.recalc_open_trade_value()
|
self.recalc_open_trade_value()
|
||||||
if self.is_open:
|
if self.is_open:
|
||||||
payment = "SELL" if self.isShort else "BUY"
|
payment = "SELL" if self.is_short else "BUY"
|
||||||
logger.info(f'{order_type.upper()}_{payment} order has been fulfilled for {self}.')
|
logger.info(f'{order_type.upper()}_{payment} order has been fulfilled for {self}.')
|
||||||
self.open_order_id = None
|
self.open_order_id = None
|
||||||
elif order_type in ('market', 'limit') and self.isClosingTrade(order['side']):
|
elif order_type in ('market', 'limit') and self.isClosingTrade(order['side']):
|
||||||
if self.is_open:
|
if self.is_open:
|
||||||
payment = "BUY" if self.isShort else "SELL"
|
payment = "BUY" if self.is_short else "SELL"
|
||||||
logger.info(f'{order_type.upper()}_{payment} order has been fulfilled for {self}.')
|
logger.info(f'{order_type.upper()}_{payment} order has been fulfilled for {self}.')
|
||||||
self.close(safe_value_fallback(order, 'average', 'price')) #TODO: Double check this
|
self.close(safe_value_fallback(order, 'average', 'price')) # TODO: Double check this
|
||||||
elif order_type in ('stop_loss_limit', 'stop-loss', 'stop-loss-limit', 'stop'):
|
elif order_type in ('stop_loss_limit', 'stop-loss', 'stop-loss-limit', 'stop'):
|
||||||
self.stoploss_order_id = None
|
self.stoploss_order_id = None
|
||||||
self.close_rate_requested = self.stop_loss
|
self.close_rate_requested = self.stop_loss
|
||||||
@ -534,12 +547,11 @@ class LocalTrade():
|
|||||||
"""
|
"""
|
||||||
open_trade = Decimal(self.amount) * Decimal(self.open_rate)
|
open_trade = Decimal(self.amount) * Decimal(self.open_rate)
|
||||||
fees = open_trade * Decimal(self.fee_open)
|
fees = open_trade * Decimal(self.fee_open)
|
||||||
if (self.isShort):
|
if (self.is_short):
|
||||||
return float(open_trade - fees)
|
return float(open_trade - fees)
|
||||||
else:
|
else:
|
||||||
return float(open_trade + fees)
|
return float(open_trade + fees)
|
||||||
|
|
||||||
|
|
||||||
def recalc_open_trade_value(self) -> None:
|
def recalc_open_trade_value(self) -> None:
|
||||||
"""
|
"""
|
||||||
Recalculate open_trade_value.
|
Recalculate open_trade_value.
|
||||||
@ -562,8 +574,9 @@ class LocalTrade():
|
|||||||
|
|
||||||
close_trade = Decimal(self.amount) * Decimal(rate or self.close_rate) # type: ignore
|
close_trade = Decimal(self.amount) * Decimal(rate or self.close_rate) # type: ignore
|
||||||
fees = close_trade * Decimal(fee or self.fee_close)
|
fees = close_trade * Decimal(fee or self.fee_close)
|
||||||
interest = ((self.interest_rate * Decimal(borrowed or self.borrowed)) * (datetime.utcnow() - self.open_date).days) or 0 #Interest/day * num of days
|
interest = ((self.interest_rate * Decimal(borrowed or self.borrowed)) *
|
||||||
if (self.isShort):
|
(datetime.utcnow() - self.open_date).days) or 0 # Interest/day * num of days
|
||||||
|
if (self.is_short):
|
||||||
return float(close_trade + fees + interest)
|
return float(close_trade + fees + interest)
|
||||||
else:
|
else:
|
||||||
return float(close_trade - fees - interest)
|
return float(close_trade - fees - interest)
|
||||||
@ -583,7 +596,7 @@ class LocalTrade():
|
|||||||
fee=(fee or self.fee_close)
|
fee=(fee or self.fee_close)
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.isShort:
|
if self.is_short:
|
||||||
profit = self.open_trade_value - close_trade_value
|
profit = self.open_trade_value - close_trade_value
|
||||||
else:
|
else:
|
||||||
profit = close_trade_value - self.open_trade_value
|
profit = close_trade_value - self.open_trade_value
|
||||||
@ -604,7 +617,7 @@ class LocalTrade():
|
|||||||
)
|
)
|
||||||
if self.open_trade_value == 0.0:
|
if self.open_trade_value == 0.0:
|
||||||
return 0.0
|
return 0.0
|
||||||
if self.isShort:
|
if self.is_short:
|
||||||
profit_ratio = (close_trade_value / self.open_trade_value) - 1
|
profit_ratio = (close_trade_value / self.open_trade_value) - 1
|
||||||
else:
|
else:
|
||||||
profit_ratio = (self.open_trade_value / close_trade_value) - 1
|
profit_ratio = (self.open_trade_value / close_trade_value) - 1
|
||||||
@ -657,7 +670,7 @@ class LocalTrade():
|
|||||||
sel_trades = [trade for trade in sel_trades if trade.close_date
|
sel_trades = [trade for trade in sel_trades if trade.close_date
|
||||||
and trade.close_date > close_date]
|
and trade.close_date > close_date]
|
||||||
|
|
||||||
return sel_trades #TODO: What is sel_trades does it mean sell_trades? If so, update this for margin
|
return sel_trades # TODO: What is sel_trades does it mean sell_trades? If so, update this for margin
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def close_bt_trade(trade):
|
def close_bt_trade(trade):
|
||||||
@ -758,26 +771,16 @@ class Trade(_DECL_BASE, LocalTrade):
|
|||||||
strategy = Column(String(100), nullable=True)
|
strategy = Column(String(100), nullable=True)
|
||||||
timeframe = Column(Integer, nullable=True)
|
timeframe = Column(Integer, nullable=True)
|
||||||
|
|
||||||
#Margin trading properties
|
# Margin trading properties
|
||||||
leverage = Column(Float, nullable=True)
|
leverage = Column(Float, nullable=True, default=0.0)
|
||||||
borrowed = Column(Float, nullable=False, default=0.0)
|
borrowed = Column(Float, nullable=False, default=0.0)
|
||||||
borrowed_currency = Column(Float, nullable=True)
|
borrowed_currency = Column(Float, nullable=True)
|
||||||
interest_rate = Column(Float, nullable=False, default=0.0)
|
interest_rate = Column(Float, nullable=False, default=0.0)
|
||||||
min_stoploss = Column(Float, nullable=True)
|
min_stoploss = Column(Float, nullable=True)
|
||||||
isShort = Column(Boolean, nullable=False, default=False)
|
is_short = Column(Boolean, nullable=False, default=False)
|
||||||
#End of margin trading properties
|
# End of margin trading properties
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
lev = kwargs.get('leverage')
|
|
||||||
bor = kwargs.get('borrowed')
|
|
||||||
amount = kwargs.get('amount')
|
|
||||||
if lev and bor:
|
|
||||||
raise OperationalException('Cannot pass both borrowed and leverage to Trade') #TODO: should I raise an error?
|
|
||||||
elif lev:
|
|
||||||
self.amount = amount * lev
|
|
||||||
self.borrowed = amount * (lev-1)
|
|
||||||
elif bor:
|
|
||||||
self.lev = (bor + amount)/amount
|
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.recalc_open_trade_value()
|
self.recalc_open_trade_value()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user