Merge branch 'entry_exit_date_print' of github.com:froggleston/freqtrade into entry_exit_date_print

This commit is contained in:
froggleston
2022-11-26 16:59:27 +00:00
10 changed files with 76 additions and 62 deletions

View File

@@ -20,7 +20,7 @@ class Bybit(Exchange):
"""
_ft_has: Dict = {
"ohlcv_candle_limit": 200,
"ohlcv_candle_limit": 1000,
"ccxt_futures_name": "linear",
"ohlcv_has_history": False,
}

View File

@@ -191,10 +191,10 @@ class FreqtradeBot(LoggingMixin):
# Check whether markets have to be reloaded and reload them when it's needed
self.exchange.reload_markets()
self.update_closed_trades_without_assigned_fees()
self.update_trades_without_assigned_fees()
# Query trades from persistence layer
trades = Trade.get_open_trades()
trades: List[Trade] = Trade.get_open_trades()
self.active_pair_whitelist = self._refresh_active_whitelist(trades)
@@ -354,7 +354,7 @@ class FreqtradeBot(LoggingMixin):
if self.trading_mode == TradingMode.FUTURES:
self._schedule.run_pending()
def update_closed_trades_without_assigned_fees(self) -> None:
def update_trades_without_assigned_fees(self) -> None:
"""
Update closed trades without close fees assigned.
Only acts when Orders are in the database, otherwise the last order-id is unknown.
@@ -381,15 +381,16 @@ class FreqtradeBot(LoggingMixin):
trades = Trade.get_open_trades_without_assigned_fees()
for trade in trades:
if trade.is_open and not trade.fee_updated(trade.entry_side):
order = trade.select_order(trade.entry_side, False)
open_order = trade.select_order(trade.entry_side, True)
if order and open_order is None:
logger.info(
f"Updating {trade.entry_side}-fee on trade {trade}"
f"for order {order.order_id}."
)
self.update_trade_state(trade, order.order_id, send_msg=False)
with self._exit_lock:
if trade.is_open and not trade.fee_updated(trade.entry_side):
order = trade.select_order(trade.entry_side, False)
open_order = trade.select_order(trade.entry_side, True)
if order and open_order is None:
logger.info(
f"Updating {trade.entry_side}-fee on trade {trade}"
f"for order {order.order_id}."
)
self.update_trade_state(trade, order.order_id, send_msg=False)
def handle_insufficient_funds(self, trade: Trade):
"""
@@ -826,6 +827,8 @@ class FreqtradeBot(LoggingMixin):
co = self.exchange.cancel_stoploss_order_with_result(
trade.stoploss_order_id, trade.pair, trade.amount)
trade.update_order(co)
# Reset stoploss order id.
trade.stoploss_order_id = None
except InvalidOrderException:
logger.exception(f"Could not cancel stoploss order {trade.stoploss_order_id}")
return trade
@@ -982,7 +985,7 @@ class FreqtradeBot(LoggingMixin):
# SELL / exit positions / close trades logic and methods
#
def exit_positions(self, trades: List[Any]) -> int:
def exit_positions(self, trades: List[Trade]) -> int:
"""
Tries to execute exit orders for open trades (positions)
"""
@@ -1010,7 +1013,7 @@ class FreqtradeBot(LoggingMixin):
def handle_trade(self, trade: Trade) -> bool:
"""
Sells/exits_short the current pair if the threshold is reached and updates the trade record.
Exits the current pair if the threshold is reached and updates the trade record.
:return: True if trade has been sold/exited_short, False otherwise
"""
if not trade.is_open:
@@ -1167,7 +1170,6 @@ class FreqtradeBot(LoggingMixin):
if self.create_stoploss_order(trade=trade, stop_price=trade.stoploss_or_liquidation):
return False
else:
trade.stoploss_order_id = None
logger.warning('Stoploss order was cancelled, but unable to recreate one.')
# Finally we check if stoploss on exchange should be moved up because of trailing.

View File

@@ -17,6 +17,7 @@ from freqtrade.enums import HyperoptState
from freqtrade.exceptions import OperationalException
from freqtrade.misc import deep_merge_dicts, round_coin_value, round_dict, safe_value_fallback2
from freqtrade.optimize.hyperopt_epoch_filters import hyperopt_filter_epochs
from freqtrade.optimize.optimize_reports import generate_wins_draws_losses
logger = logging.getLogger(__name__)
@@ -325,8 +326,10 @@ class HyperoptTools():
# New mode, using backtest result for metrics
trials['results_metrics.winsdrawslosses'] = trials.apply(
lambda x: f"{x['results_metrics.wins']} {x['results_metrics.draws']:>4} "
f"{x['results_metrics.losses']:>4}", axis=1)
lambda x: generate_wins_draws_losses(
x['results_metrics.wins'], x['results_metrics.draws'],
x['results_metrics.losses']
), axis=1)
trials = trials[['Best', 'current_epoch', 'results_metrics.total_trades',
'results_metrics.winsdrawslosses',
@@ -337,7 +340,7 @@ class HyperoptTools():
'loss', 'is_initial_point', 'is_random', 'is_best']]
trials.columns = [
'Best', 'Epoch', 'Trades', ' Win Draw Loss', 'Avg profit',
'Best', 'Epoch', 'Trades', ' Win Draw Loss Win%', 'Avg profit',
'Total profit', 'Profit', 'Avg duration', 'max_drawdown', 'max_drawdown_account',
'max_drawdown_abs', 'Objective', 'is_initial_point', 'is_random', 'is_best'
]
@@ -467,9 +470,9 @@ class HyperoptTools():
base_metrics = ['Best', 'current_epoch', 'results_metrics.total_trades',
'results_metrics.profit_mean', 'results_metrics.profit_median',
'results_metrics.profit_total',
'Stake currency',
'results_metrics.profit_total', 'Stake currency',
'results_metrics.profit_total_abs', 'results_metrics.holding_avg',
'results_metrics.trade_count_long', 'results_metrics.trade_count_short',
'loss', 'is_initial_point', 'is_best']
perc_multi = 100
@@ -477,7 +480,9 @@ class HyperoptTools():
trials = trials[base_metrics + param_metrics]
base_columns = ['Best', 'Epoch', 'Trades', 'Avg profit', 'Median profit', 'Total profit',
'Stake currency', 'Profit', 'Avg duration', 'Objective',
'Stake currency', 'Profit', 'Avg duration',
'Trade count long', 'Trade count short',
'Objective',
'is_initial_point', 'is_best']
param_columns = list(results[0]['params_dict'].keys())
trials.columns = base_columns + param_columns

View File

@@ -86,7 +86,7 @@ def _get_line_header(first_column: str, stake_currency: str,
'Win Draw Loss Win%']
def _generate_wins_draws_losses(wins, draws, losses):
def generate_wins_draws_losses(wins, draws, losses):
if wins > 0 and losses == 0:
wl_ratio = '100'
elif wins == 0:
@@ -600,7 +600,7 @@ def text_table_bt_results(pair_results: List[Dict[str, Any]], stake_currency: st
output = [[
t['key'], t['trades'], t['profit_mean_pct'], t['profit_sum_pct'], t['profit_total_abs'],
t['profit_total_pct'], t['duration_avg'],
_generate_wins_draws_losses(t['wins'], t['draws'], t['losses'])
generate_wins_draws_losses(t['wins'], t['draws'], t['losses'])
] for t in pair_results]
# Ignore type as floatfmt does allow tuples but mypy does not know that
return tabulate(output, headers=headers,
@@ -626,7 +626,7 @@ def text_table_exit_reason(exit_reason_stats: List[Dict[str, Any]], stake_curren
output = [[
t.get('exit_reason', t.get('sell_reason')), t['trades'],
_generate_wins_draws_losses(t['wins'], t['draws'], t['losses']),
generate_wins_draws_losses(t['wins'], t['draws'], t['losses']),
t['profit_mean_pct'], t['profit_sum_pct'],
round_coin_value(t['profit_total_abs'], stake_currency, False),
t['profit_total_pct'],
@@ -656,7 +656,7 @@ def text_table_tags(tag_type: str, tag_results: List[Dict[str, Any]], stake_curr
t['profit_total_abs'],
t['profit_total_pct'],
t['duration_avg'],
_generate_wins_draws_losses(
generate_wins_draws_losses(
t['wins'],
t['draws'],
t['losses'])] for t in tag_results]
@@ -715,7 +715,7 @@ def text_table_strategy(strategy_results, stake_currency: str) -> str:
output = [[
t['key'], t['trades'], t['profit_mean_pct'], t['profit_sum_pct'], t['profit_total_abs'],
t['profit_total_pct'], t['duration_avg'],
_generate_wins_draws_losses(t['wins'], t['draws'], t['losses']), drawdown]
generate_wins_draws_losses(t['wins'], t['draws'], t['losses']), drawdown]
for t, drawdown in zip(strategy_results, drawdown)]
# Ignore type as floatfmt does allow tuples but mypy does not know that
return tabulate(output, headers=headers,

View File

@@ -789,17 +789,18 @@ class RPC:
if not order_type:
order_type = self._freqtrade.strategy.order_types.get(
'force_entry', self._freqtrade.strategy.order_types['entry'])
if self._freqtrade.execute_entry(pair, stake_amount, price,
ordertype=order_type, trade=trade,
is_short=is_short,
enter_tag=enter_tag,
leverage_=leverage,
):
Trade.commit()
trade = Trade.get_trades([Trade.is_open.is_(True), Trade.pair == pair]).first()
return trade
else:
raise RPCException(f'Failed to enter position for {pair}.')
with self._freqtrade._exit_lock:
if self._freqtrade.execute_entry(pair, stake_amount, price,
ordertype=order_type, trade=trade,
is_short=is_short,
enter_tag=enter_tag,
leverage_=leverage,
):
Trade.commit()
trade = Trade.get_trades([Trade.is_open.is_(True), Trade.pair == pair]).first()
return trade
else:
raise RPCException(f'Failed to enter position for {pair}.')
def _rpc_delete(self, trade_id: int) -> Dict[str, Union[str, int]]:
"""