Merge branch 'develop' into feat/externalsignals
This commit is contained in:
@@ -147,13 +147,16 @@ class FreqtradeBot(LoggingMixin):
|
||||
:return: None
|
||||
"""
|
||||
logger.info('Cleaning up modules ...')
|
||||
try:
|
||||
# Wrap db activities in shutdown to avoid problems if database is gone,
|
||||
# and raises further exceptions.
|
||||
if self.config['cancel_open_orders_on_exit']:
|
||||
self.cancel_all_open_orders()
|
||||
|
||||
if self.config['cancel_open_orders_on_exit']:
|
||||
self.cancel_all_open_orders()
|
||||
self.check_for_open_trades()
|
||||
|
||||
self.check_for_open_trades()
|
||||
|
||||
self.strategy.ft_bot_cleanup()
|
||||
finally:
|
||||
self.strategy.ft_bot_cleanup()
|
||||
|
||||
self.rpc.cleanup()
|
||||
if self.emc:
|
||||
@@ -296,7 +299,7 @@ class FreqtradeBot(LoggingMixin):
|
||||
pair=trade.pair,
|
||||
amount=trade.amount,
|
||||
is_short=trade.is_short,
|
||||
open_date=trade.open_date_utc
|
||||
open_date=trade.date_last_filled_utc
|
||||
)
|
||||
trade.funding_fees = funding_fees
|
||||
else:
|
||||
@@ -741,10 +744,11 @@ class FreqtradeBot(LoggingMixin):
|
||||
fee = self.exchange.get_fee(symbol=pair, taker_or_maker='maker')
|
||||
base_currency = self.exchange.get_pair_base_currency(pair)
|
||||
open_date = datetime.now(timezone.utc)
|
||||
funding_fees = self.exchange.get_funding_fees(
|
||||
pair=pair, amount=amount, is_short=is_short, open_date=open_date)
|
||||
|
||||
# This is a new trade
|
||||
if trade is None:
|
||||
funding_fees = self.exchange.get_funding_fees(
|
||||
pair=pair, amount=amount, is_short=is_short, open_date=open_date)
|
||||
trade = Trade(
|
||||
pair=pair,
|
||||
base_currency=base_currency,
|
||||
@@ -1499,7 +1503,7 @@ class FreqtradeBot(LoggingMixin):
|
||||
pair=trade.pair,
|
||||
amount=trade.amount,
|
||||
is_short=trade.is_short,
|
||||
open_date=trade.open_date_utc,
|
||||
open_date=trade.date_last_filled_utc,
|
||||
)
|
||||
exit_type = 'exit'
|
||||
exit_reason = exit_tag or exit_check.exit_reason
|
||||
|
@@ -686,7 +686,7 @@ class Backtesting:
|
||||
self.futures_data[trade.pair],
|
||||
amount=trade.amount,
|
||||
is_short=trade.is_short,
|
||||
open_date=trade.open_date_utc,
|
||||
open_date=trade.date_last_filled_utc,
|
||||
close_date=exit_candle_time,
|
||||
)
|
||||
|
||||
|
@@ -421,9 +421,10 @@ class Hyperopt:
|
||||
preprocessed = self.backtesting.strategy.advise_all_indicators(data)
|
||||
|
||||
# Trim startup period from analyzed dataframe to get correct dates for output.
|
||||
processed = trim_dataframes(preprocessed, self.timerange, self.backtesting.required_startup)
|
||||
self.min_date, self.max_date = get_timerange(processed)
|
||||
return processed
|
||||
trimmed = trim_dataframes(preprocessed, self.timerange, self.backtesting.required_startup)
|
||||
self.min_date, self.max_date = get_timerange(trimmed)
|
||||
# Real trimming will happen as part of backtesting.
|
||||
return preprocessed
|
||||
|
||||
def prepare_hyperopt_data(self) -> None:
|
||||
HyperoptStateContainer.set_state(HyperoptState.DATALOAD)
|
||||
|
@@ -212,17 +212,18 @@ def migrate_orders_table(engine, table_back_name: str, cols_order: List):
|
||||
ft_fee_base = get_column_def(cols_order, 'ft_fee_base', 'null')
|
||||
average = get_column_def(cols_order, 'average', 'null')
|
||||
stop_price = get_column_def(cols_order, 'stop_price', 'null')
|
||||
funding_fee = get_column_def(cols_order, 'funding_fee', '0.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,
|
||||
stop_price, order_date, order_filled_date, order_update_date, ft_fee_base)
|
||||
stop_price, order_date, order_filled_date, order_update_date, ft_fee_base, funding_fee)
|
||||
select id, ft_trade_id, ft_order_side, ft_pair, ft_is_open, order_id,
|
||||
status, symbol, order_type, side, price, amount, filled, {average} average, remaining,
|
||||
cost, {stop_price} stop_price, order_date, order_filled_date,
|
||||
order_update_date, {ft_fee_base} ft_fee_base
|
||||
order_update_date, {ft_fee_base} ft_fee_base, {funding_fee} funding_fee
|
||||
from {table_back_name}
|
||||
"""))
|
||||
|
||||
@@ -307,9 +308,10 @@ def check_migrate(engine, decl_base, previous_tables) -> None:
|
||||
# Check if migration necessary
|
||||
# Migrates both trades and orders table!
|
||||
# if ('orders' not in previous_tables
|
||||
# or not has_column(cols_orders, 'stop_price')):
|
||||
# or not has_column(cols_orders, 'funding_fee')):
|
||||
migrating = False
|
||||
if not has_column(cols_trades, 'contract_size'):
|
||||
# if not has_column(cols_trades, 'contract_size'):
|
||||
if not has_column(cols_orders, 'funding_fee'):
|
||||
migrating = True
|
||||
logger.info(f"Running database migration for trades - "
|
||||
f"backup: {table_back_name}, {order_table_bak_name}")
|
||||
|
@@ -65,6 +65,8 @@ class Order(_DECL_BASE):
|
||||
order_filled_date = Column(DateTime, nullable=True)
|
||||
order_update_date = Column(DateTime, nullable=True)
|
||||
|
||||
funding_fee = Column(Float, nullable=True)
|
||||
|
||||
ft_fee_base = Column(Float, nullable=True)
|
||||
|
||||
@property
|
||||
@@ -72,6 +74,13 @@ class Order(_DECL_BASE):
|
||||
""" Order-date with UTC timezoneinfo"""
|
||||
return self.order_date.replace(tzinfo=timezone.utc)
|
||||
|
||||
@property
|
||||
def order_filled_utc(self) -> Optional[datetime]:
|
||||
""" last order-date with UTC timezoneinfo"""
|
||||
return (
|
||||
self.order_filled_date.replace(tzinfo=timezone.utc) if self.order_filled_date else None
|
||||
)
|
||||
|
||||
@property
|
||||
def safe_price(self) -> float:
|
||||
return self.average or self.price
|
||||
@@ -119,6 +128,10 @@ class Order(_DECL_BASE):
|
||||
self.ft_is_open = True
|
||||
if self.status in NON_OPEN_EXCHANGE_STATES:
|
||||
self.ft_is_open = False
|
||||
if self.trade:
|
||||
# Assign funding fee up to this point
|
||||
# (represents the funding fee since the last order)
|
||||
self.funding_fee = self.trade.funding_fees
|
||||
if (order.get('filled', 0.0) or 0.0) > 0:
|
||||
self.order_filled_date = datetime.now(timezone.utc)
|
||||
self.order_update_date = datetime.now(timezone.utc)
|
||||
@@ -179,6 +192,10 @@ class Order(_DECL_BASE):
|
||||
self.remaining = 0
|
||||
self.status = 'closed'
|
||||
self.ft_is_open = False
|
||||
# Assign funding fees to Order.
|
||||
# Assumes backtesting will use date_last_filled_utc to calculate future funding fees.
|
||||
self.funding_fee = trade.funding_fees
|
||||
|
||||
if (self.ft_order_side == trade.entry_side):
|
||||
trade.open_rate = self.price
|
||||
trade.recalc_trade_from_orders()
|
||||
@@ -346,6 +363,15 @@ class LocalTrade():
|
||||
else:
|
||||
return self.amount
|
||||
|
||||
@property
|
||||
def date_last_filled_utc(self) -> datetime:
|
||||
""" Date of the last filled order"""
|
||||
orders = self.select_filled_orders()
|
||||
if not orders:
|
||||
return self.open_date_utc
|
||||
return max([self.open_date_utc,
|
||||
max(o.order_filled_utc for o in orders if o.order_filled_utc)])
|
||||
|
||||
@property
|
||||
def open_date_utc(self):
|
||||
return self.open_date.replace(tzinfo=timezone.utc)
|
||||
@@ -843,10 +869,14 @@ class LocalTrade():
|
||||
close_profit = 0.0
|
||||
close_profit_abs = 0.0
|
||||
profit = None
|
||||
for o in self.orders:
|
||||
# Reset funding fees
|
||||
self.funding_fees = 0.0
|
||||
funding_fees = 0.0
|
||||
ordercount = len(self.orders) - 1
|
||||
for i, o in enumerate(self.orders):
|
||||
if o.ft_is_open or not o.filled:
|
||||
continue
|
||||
|
||||
funding_fees += (o.funding_fee or 0.0)
|
||||
tmp_amount = FtPrecise(o.safe_amount_after_fee)
|
||||
tmp_price = FtPrecise(o.safe_price)
|
||||
|
||||
@@ -861,7 +891,11 @@ class LocalTrade():
|
||||
avg_price = current_stake / current_amount
|
||||
|
||||
if is_exit:
|
||||
# Process partial exits
|
||||
# Process exits
|
||||
if i == ordercount and is_closing:
|
||||
# Apply funding fees only to the last closing order
|
||||
self.funding_fees = funding_fees
|
||||
|
||||
exit_rate = o.safe_price
|
||||
exit_amount = o.safe_amount_after_fee
|
||||
profit = self.calc_profit(rate=exit_rate, amount=exit_amount,
|
||||
@@ -871,6 +905,7 @@ class LocalTrade():
|
||||
exit_rate, amount=exit_amount, open_rate=avg_price)
|
||||
else:
|
||||
total_stake = total_stake + self._calc_open_trade_value(tmp_amount, price)
|
||||
self.funding_fees = funding_fees
|
||||
|
||||
if close_profit:
|
||||
self.close_profit = close_profit
|
||||
|
@@ -261,11 +261,15 @@ class RPC:
|
||||
profit_str += f" ({fiat_profit:.2f})"
|
||||
fiat_profit_sum = fiat_profit if isnan(fiat_profit_sum) \
|
||||
else fiat_profit_sum + fiat_profit
|
||||
open_order = (trade.select_order_by_order_id(
|
||||
trade.open_order_id) if trade.open_order_id else None)
|
||||
|
||||
detail_trade = [
|
||||
f'{trade.id} {direction_str}',
|
||||
trade.pair + ('*' if (trade.open_order_id is not None
|
||||
and trade.close_rate_requested is None) else '')
|
||||
+ ('**' if (trade.close_rate_requested is not None) else ''),
|
||||
trade.pair + ('*' if (open_order
|
||||
and open_order.ft_order_side == trade.entry_side) else '')
|
||||
+ ('**' if (open_order and
|
||||
open_order.ft_order_side == trade.exit_side is not None) else ''),
|
||||
shorten_date(arrow.get(trade.open_date).humanize(only_distance=True)),
|
||||
profit_str
|
||||
]
|
||||
|
Reference in New Issue
Block a user