diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index ecedc55db..f174b8ea9 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -16,7 +16,7 @@ from freqtrade.persistence import Trade logger = logging.getLogger(__name__) # must align with columns in backtest.py -BT_DATA_COLUMNS = ["pair", "profit_percent", "open_time", "close_time", "index", "duration", +BT_DATA_COLUMNS = ["pair", "profit_percent", "open_date", "close_date", "index", "duration", "open_rate", "close_rate", "open_at_end", "sell_reason"] @@ -54,18 +54,18 @@ def load_backtest_data(filename: Union[Path, str]) -> pd.DataFrame: df = pd.DataFrame(data, columns=BT_DATA_COLUMNS) - df['open_time'] = pd.to_datetime(df['open_time'], + df['open_date'] = pd.to_datetime(df['open_date'], unit='s', utc=True, infer_datetime_format=True ) - df['close_time'] = pd.to_datetime(df['close_time'], + df['close_date'] = pd.to_datetime(df['close_date'], unit='s', utc=True, infer_datetime_format=True ) df['profit'] = df['close_rate'] - df['open_rate'] - df = df.sort_values("open_time").reset_index(drop=True) + df = df.sort_values("open_date").reset_index(drop=True) return df @@ -79,9 +79,9 @@ def analyze_trade_parallelism(results: pd.DataFrame, timeframe: str) -> pd.DataF """ from freqtrade.exchange import timeframe_to_minutes timeframe_min = timeframe_to_minutes(timeframe) - dates = [pd.Series(pd.date_range(row[1].open_time, row[1].close_time, + dates = [pd.Series(pd.date_range(row[1]['open_date'], row[1]['close_date'], freq=f"{timeframe_min}min")) - for row in results[['open_time', 'close_time']].iterrows()] + for row in results[['open_date', 'close_date']].iterrows()] deltas = [len(x) for x in dates] dates = pd.Series(pd.concat(dates).values, name='date') df2 = pd.DataFrame(np.repeat(results.values, deltas, axis=0), columns=results.columns) @@ -116,7 +116,7 @@ def load_trades_from_db(db_url: str) -> pd.DataFrame: trades: pd.DataFrame = pd.DataFrame([], columns=BT_DATA_COLUMNS) persistence.init(db_url, clean_open_orders=False) - columns = ["pair", "open_time", "close_time", "profit", "profit_percent", + columns = ["pair", "open_date", "close_date", "profit", "profit_percent", "open_rate", "close_rate", "amount", "duration", "sell_reason", "fee_open", "fee_close", "open_rate_requested", "close_rate_requested", "stake_amount", "max_rate", "min_rate", "id", "exchange", @@ -180,8 +180,8 @@ def extract_trades_of_period(dataframe: pd.DataFrame, trades: pd.DataFrame, else: trades_start = dataframe.iloc[0]['date'] trades_stop = dataframe.iloc[-1]['date'] - trades = trades.loc[(trades['open_time'] >= trades_start) & - (trades['close_time'] <= trades_stop)] + trades = trades.loc[(trades['open_date'] >= trades_start) & + (trades['close_date'] <= trades_stop)] return trades @@ -227,7 +227,7 @@ def create_cum_profit(df: pd.DataFrame, trades: pd.DataFrame, col_name: str, """ Adds a column `col_name` with the cumulative profit for the given trades array. :param df: DataFrame with date index - :param trades: DataFrame containing trades (requires columns close_time and profit_percent) + :param trades: DataFrame containing trades (requires columns close_date and profit_percent) :param col_name: Column name that will be assigned the results :param timeframe: Timeframe used during the operations :return: Returns df with one additional column, col_name, containing the cumulative profit. @@ -238,7 +238,7 @@ def create_cum_profit(df: pd.DataFrame, trades: pd.DataFrame, col_name: str, from freqtrade.exchange import timeframe_to_minutes timeframe_minutes = timeframe_to_minutes(timeframe) # Resample to timeframe to make sure trades match candles - _trades_sum = trades.resample(f'{timeframe_minutes}min', on='close_time' + _trades_sum = trades.resample(f'{timeframe_minutes}min', on='close_date' )[['profit_percent']].sum() df.loc[:, col_name] = _trades_sum.cumsum() # Set first value to 0 @@ -248,13 +248,13 @@ def create_cum_profit(df: pd.DataFrame, trades: pd.DataFrame, col_name: str, return df -def calculate_max_drawdown(trades: pd.DataFrame, *, date_col: str = 'close_time', +def calculate_max_drawdown(trades: pd.DataFrame, *, date_col: str = 'close_date', value_col: str = 'profit_percent' ) -> Tuple[float, pd.Timestamp, pd.Timestamp]: """ Calculate max drawdown and the corresponding close dates - :param trades: DataFrame containing trades (requires columns close_time and profit_percent) - :param date_col: Column in DataFrame to use for dates (defaults to 'close_time') + :param trades: DataFrame containing trades (requires columns close_date and profit_percent) + :param date_col: Column in DataFrame to use for dates (defaults to 'close_date') :param value_col: Column in DataFrame to use for values (defaults to 'profit_percent') :return: Tuple (float, highdate, lowdate) with absolute max drawdown, high and low time :raise: ValueError if trade-dataframe was found empty. diff --git a/freqtrade/edge/edge_positioning.py b/freqtrade/edge/edge_positioning.py index dd2f44f23..169732314 100644 --- a/freqtrade/edge/edge_positioning.py +++ b/freqtrade/edge/edge_positioning.py @@ -237,7 +237,7 @@ class Edge: # All returned values are relative, they are defined as ratios. stake = 0.015 - result['trade_duration'] = result['close_time'] - result['open_time'] + result['trade_duration'] = result['close_date'] - result['open_date'] result['trade_duration'] = result['trade_duration'].map( lambda x: int(x.total_seconds() / 60)) @@ -427,8 +427,8 @@ class Edge: 'stoploss': stoploss, 'profit_ratio': '', 'profit_abs': '', - 'open_time': date_column[open_trade_index], - 'close_time': date_column[exit_index], + 'open_date': date_column[open_trade_index], + 'close_date': date_column[exit_index], 'open_index': start_point + open_trade_index, 'close_index': start_point + exit_index, 'trade_duration': '', diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index e4df80a82..4197ec087 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -39,8 +39,8 @@ class BacktestResult(NamedTuple): pair: str profit_percent: float profit_abs: float - open_time: datetime - close_time: datetime + open_date: datetime + close_date: datetime open_index: int close_index: int trade_duration: float @@ -248,8 +248,8 @@ class Backtesting: return BacktestResult(pair=pair, profit_percent=trade.calc_profit_ratio(rate=closerate), profit_abs=trade.calc_profit(rate=closerate), - open_time=buy_row.date, - close_time=sell_row.date, + open_date=buy_row.date, + close_date=sell_row.date, trade_duration=trade_dur, open_index=buy_row.Index, close_index=sell_row.Index, @@ -264,8 +264,8 @@ class Backtesting: bt_res = BacktestResult(pair=pair, profit_percent=trade.calc_profit_ratio(rate=sell_row.open), profit_abs=trade.calc_profit(rate=sell_row.open), - open_time=buy_row.date, - close_time=sell_row.date, + open_date=buy_row.date, + close_date=sell_row.date, trade_duration=int(( sell_row.date - buy_row.date).total_seconds() // 60), open_index=buy_row.Index, @@ -358,8 +358,8 @@ class Backtesting: if trade_entry: logger.debug(f"{pair} - Locking pair till " - f"close_time={trade_entry.close_time}") - lock_pair_until[pair] = trade_entry.close_time + f"close_date={trade_entry.close_date}") + lock_pair_until[pair] = trade_entry.close_date trades.append(trade_entry) else: # Set lock_pair_until to end of testing period if trade could not be closed @@ -421,4 +421,5 @@ class Backtesting: stats = generate_backtest_stats(self.config, data, all_results, min_date=min_date, max_date=max_date) show_backtest_results(self.config, stats) - store_backtest_stats(self.config['exportfilename'], stats) + if self.config.get('export', False): + store_backtest_stats(self.config['exportfilename'], stats) diff --git a/freqtrade/optimize/hyperopt_loss_sharpe_daily.py b/freqtrade/optimize/hyperopt_loss_sharpe_daily.py index e4cd1d749..bcba73a7f 100644 --- a/freqtrade/optimize/hyperopt_loss_sharpe_daily.py +++ b/freqtrade/optimize/hyperopt_loss_sharpe_daily.py @@ -43,7 +43,7 @@ class SharpeHyperOptLossDaily(IHyperOptLoss): normalize=True) sum_daily = ( - results.resample(resample_freq, on='close_time').agg( + results.resample(resample_freq, on='close_date').agg( {"profit_percent_after_slippage": sum}).reindex(t_index).fillna(0) ) diff --git a/freqtrade/optimize/hyperopt_loss_sortino_daily.py b/freqtrade/optimize/hyperopt_loss_sortino_daily.py index cd6a8bcc2..3b099a253 100644 --- a/freqtrade/optimize/hyperopt_loss_sortino_daily.py +++ b/freqtrade/optimize/hyperopt_loss_sortino_daily.py @@ -45,7 +45,7 @@ class SortinoHyperOptLossDaily(IHyperOptLoss): normalize=True) sum_daily = ( - results.resample(resample_freq, on='close_time').agg( + results.resample(resample_freq, on='close_date').agg( {"profit_percent_after_slippage": sum}).reindex(t_index).fillna(0) ) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 3c0bfcb96..63c2d2022 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -52,8 +52,8 @@ def backtest_result_to_list(results: DataFrame) -> List[List]: :param results: Dataframe containing results for one strategy :return: List of Lists containing the trades """ - return [[t.pair, t.profit_percent, t.open_time.timestamp(), - t.close_time.timestamp(), t.open_index - 1, t.trade_duration, + return [[t.pair, t.profit_percent, t.open_date.timestamp(), + t.open_date.timestamp(), t.open_index - 1, t.trade_duration, t.open_rate, t.close_rate, t.open_at_end, t.sell_reason.value] for index, t in results.iterrows()] @@ -350,10 +350,10 @@ def text_table_strategy(strategy_results, stake_currency: str) -> str: def text_table_add_metrics(strategy_results: Dict) -> str: if len(strategy_results['trades']) > 0: - min_trade = min(strategy_results['trades'], key=lambda x: x['open_time']) + min_trade = min(strategy_results['trades'], key=lambda x: x['open_date']) metrics = [ ('Total trades', strategy_results['total_trades']), - ('First trade', min_trade['open_time'].strftime(DATETIME_PRINT_FORMAT)), + ('First trade', min_trade['open_date'].strftime(DATETIME_PRINT_FORMAT)), ('First trade Pair', min_trade['pair']), ('Backtesting from', strategy_results['backtest_start'].strftime(DATETIME_PRINT_FORMAT)), ('Backtesting to', strategy_results['backtest_end'].strftime(DATETIME_PRINT_FORMAT)), diff --git a/freqtrade/plot/plotting.py b/freqtrade/plot/plotting.py index e8b0b4938..6d50defaf 100644 --- a/freqtrade/plot/plotting.py +++ b/freqtrade/plot/plotting.py @@ -63,7 +63,7 @@ def init_plotscript(config): exportfilename=config.get('exportfilename'), no_trades=no_trades ) - trades = trim_dataframe(trades, timerange, 'open_time') + trades = trim_dataframe(trades, timerange, 'open_date') return {"ohlcv": data, "trades": trades, @@ -166,7 +166,7 @@ def plot_trades(fig, trades: pd.DataFrame) -> make_subplots: f"{row['sell_reason']}, {row['duration']} min", axis=1) trade_buys = go.Scatter( - x=trades["open_time"], + x=trades["open_date"], y=trades["open_rate"], mode='markers', name='Trade buy', @@ -181,7 +181,7 @@ def plot_trades(fig, trades: pd.DataFrame) -> make_subplots: ) trade_sells = go.Scatter( - x=trades.loc[trades['profit_percent'] > 0, "close_time"], + x=trades.loc[trades['profit_percent'] > 0, "close_date"], y=trades.loc[trades['profit_percent'] > 0, "close_rate"], text=trades.loc[trades['profit_percent'] > 0, "desc"], mode='markers', @@ -194,7 +194,7 @@ def plot_trades(fig, trades: pd.DataFrame) -> make_subplots: ) ) trade_sells_loss = go.Scatter( - x=trades.loc[trades['profit_percent'] <= 0, "close_time"], + x=trades.loc[trades['profit_percent'] <= 0, "close_date"], y=trades.loc[trades['profit_percent'] <= 0, "close_rate"], text=trades.loc[trades['profit_percent'] <= 0, "desc"], mode='markers', @@ -506,7 +506,7 @@ def plot_profit(config: Dict[str, Any]) -> None: # Remove open pairs - we don't know the profit yet so can't calculate profit for these. # Also, If only one open pair is left, then the profit-generation would fail. trades = trades[(trades['pair'].isin(plot_elements["pairs"])) - & (~trades['close_time'].isnull()) + & (~trades['close_date'].isnull()) ] if len(trades) == 0: raise OperationalException("No trades found, cannot generate Profit-plot without "