Rename open_time and close_time to *date

This commit is contained in:
Matthias 2020-06-26 09:19:44 +02:00
parent 415853583b
commit b068e7c564
7 changed files with 38 additions and 37 deletions

View File

@ -16,7 +16,7 @@ from freqtrade.persistence import Trade
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# must align with columns in backtest.py # 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"] "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 = 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', unit='s',
utc=True, utc=True,
infer_datetime_format=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', unit='s',
utc=True, utc=True,
infer_datetime_format=True infer_datetime_format=True
) )
df['profit'] = df['close_rate'] - df['open_rate'] 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 return df
@ -79,9 +79,9 @@ def analyze_trade_parallelism(results: pd.DataFrame, timeframe: str) -> pd.DataF
""" """
from freqtrade.exchange import timeframe_to_minutes from freqtrade.exchange import timeframe_to_minutes
timeframe_min = timeframe_to_minutes(timeframe) 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")) 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] deltas = [len(x) for x in dates]
dates = pd.Series(pd.concat(dates).values, name='date') dates = pd.Series(pd.concat(dates).values, name='date')
df2 = pd.DataFrame(np.repeat(results.values, deltas, axis=0), columns=results.columns) 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) trades: pd.DataFrame = pd.DataFrame([], columns=BT_DATA_COLUMNS)
persistence.init(db_url, clean_open_orders=False) 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", "open_rate", "close_rate", "amount", "duration", "sell_reason",
"fee_open", "fee_close", "open_rate_requested", "close_rate_requested", "fee_open", "fee_close", "open_rate_requested", "close_rate_requested",
"stake_amount", "max_rate", "min_rate", "id", "exchange", "stake_amount", "max_rate", "min_rate", "id", "exchange",
@ -180,8 +180,8 @@ def extract_trades_of_period(dataframe: pd.DataFrame, trades: pd.DataFrame,
else: else:
trades_start = dataframe.iloc[0]['date'] trades_start = dataframe.iloc[0]['date']
trades_stop = dataframe.iloc[-1]['date'] trades_stop = dataframe.iloc[-1]['date']
trades = trades.loc[(trades['open_time'] >= trades_start) & trades = trades.loc[(trades['open_date'] >= trades_start) &
(trades['close_time'] <= trades_stop)] (trades['close_date'] <= trades_stop)]
return trades 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. Adds a column `col_name` with the cumulative profit for the given trades array.
:param df: DataFrame with date index :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 col_name: Column name that will be assigned the results
:param timeframe: Timeframe used during the operations :param timeframe: Timeframe used during the operations
:return: Returns df with one additional column, col_name, containing the cumulative profit. :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 from freqtrade.exchange import timeframe_to_minutes
timeframe_minutes = timeframe_to_minutes(timeframe) timeframe_minutes = timeframe_to_minutes(timeframe)
# Resample to timeframe to make sure trades match candles # 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() )[['profit_percent']].sum()
df.loc[:, col_name] = _trades_sum.cumsum() df.loc[:, col_name] = _trades_sum.cumsum()
# Set first value to 0 # Set first value to 0
@ -248,13 +248,13 @@ def create_cum_profit(df: pd.DataFrame, trades: pd.DataFrame, col_name: str,
return df 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' value_col: str = 'profit_percent'
) -> Tuple[float, pd.Timestamp, pd.Timestamp]: ) -> Tuple[float, pd.Timestamp, pd.Timestamp]:
""" """
Calculate max drawdown and the corresponding close dates Calculate max drawdown and the corresponding close dates
: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 date_col: Column in DataFrame to use for dates (defaults to 'close_time') :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') :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 :return: Tuple (float, highdate, lowdate) with absolute max drawdown, high and low time
:raise: ValueError if trade-dataframe was found empty. :raise: ValueError if trade-dataframe was found empty.

View File

@ -237,7 +237,7 @@ class Edge:
# All returned values are relative, they are defined as ratios. # All returned values are relative, they are defined as ratios.
stake = 0.015 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( result['trade_duration'] = result['trade_duration'].map(
lambda x: int(x.total_seconds() / 60)) lambda x: int(x.total_seconds() / 60))
@ -427,8 +427,8 @@ class Edge:
'stoploss': stoploss, 'stoploss': stoploss,
'profit_ratio': '', 'profit_ratio': '',
'profit_abs': '', 'profit_abs': '',
'open_time': date_column[open_trade_index], 'open_date': date_column[open_trade_index],
'close_time': date_column[exit_index], 'close_date': date_column[exit_index],
'open_index': start_point + open_trade_index, 'open_index': start_point + open_trade_index,
'close_index': start_point + exit_index, 'close_index': start_point + exit_index,
'trade_duration': '', 'trade_duration': '',

View File

@ -39,8 +39,8 @@ class BacktestResult(NamedTuple):
pair: str pair: str
profit_percent: float profit_percent: float
profit_abs: float profit_abs: float
open_time: datetime open_date: datetime
close_time: datetime close_date: datetime
open_index: int open_index: int
close_index: int close_index: int
trade_duration: float trade_duration: float
@ -248,8 +248,8 @@ class Backtesting:
return BacktestResult(pair=pair, return BacktestResult(pair=pair,
profit_percent=trade.calc_profit_ratio(rate=closerate), profit_percent=trade.calc_profit_ratio(rate=closerate),
profit_abs=trade.calc_profit(rate=closerate), profit_abs=trade.calc_profit(rate=closerate),
open_time=buy_row.date, open_date=buy_row.date,
close_time=sell_row.date, close_date=sell_row.date,
trade_duration=trade_dur, trade_duration=trade_dur,
open_index=buy_row.Index, open_index=buy_row.Index,
close_index=sell_row.Index, close_index=sell_row.Index,
@ -264,8 +264,8 @@ class Backtesting:
bt_res = BacktestResult(pair=pair, bt_res = BacktestResult(pair=pair,
profit_percent=trade.calc_profit_ratio(rate=sell_row.open), profit_percent=trade.calc_profit_ratio(rate=sell_row.open),
profit_abs=trade.calc_profit(rate=sell_row.open), profit_abs=trade.calc_profit(rate=sell_row.open),
open_time=buy_row.date, open_date=buy_row.date,
close_time=sell_row.date, close_date=sell_row.date,
trade_duration=int(( trade_duration=int((
sell_row.date - buy_row.date).total_seconds() // 60), sell_row.date - buy_row.date).total_seconds() // 60),
open_index=buy_row.Index, open_index=buy_row.Index,
@ -358,8 +358,8 @@ class Backtesting:
if trade_entry: if trade_entry:
logger.debug(f"{pair} - Locking pair till " logger.debug(f"{pair} - Locking pair till "
f"close_time={trade_entry.close_time}") f"close_date={trade_entry.close_date}")
lock_pair_until[pair] = trade_entry.close_time lock_pair_until[pair] = trade_entry.close_date
trades.append(trade_entry) trades.append(trade_entry)
else: else:
# Set lock_pair_until to end of testing period if trade could not be closed # 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, stats = generate_backtest_stats(self.config, data, all_results,
min_date=min_date, max_date=max_date) min_date=min_date, max_date=max_date)
show_backtest_results(self.config, stats) 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)

View File

@ -43,7 +43,7 @@ class SharpeHyperOptLossDaily(IHyperOptLoss):
normalize=True) normalize=True)
sum_daily = ( 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) {"profit_percent_after_slippage": sum}).reindex(t_index).fillna(0)
) )

View File

@ -45,7 +45,7 @@ class SortinoHyperOptLossDaily(IHyperOptLoss):
normalize=True) normalize=True)
sum_daily = ( 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) {"profit_percent_after_slippage": sum}).reindex(t_index).fillna(0)
) )

View File

@ -52,8 +52,8 @@ def backtest_result_to_list(results: DataFrame) -> List[List]:
:param results: Dataframe containing results for one strategy :param results: Dataframe containing results for one strategy
:return: List of Lists containing the trades :return: List of Lists containing the trades
""" """
return [[t.pair, t.profit_percent, t.open_time.timestamp(), return [[t.pair, t.profit_percent, t.open_date.timestamp(),
t.close_time.timestamp(), t.open_index - 1, t.trade_duration, 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] t.open_rate, t.close_rate, t.open_at_end, t.sell_reason.value]
for index, t in results.iterrows()] 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: def text_table_add_metrics(strategy_results: Dict) -> str:
if len(strategy_results['trades']) > 0: 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 = [ metrics = [
('Total trades', strategy_results['total_trades']), ('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']), ('First trade Pair', min_trade['pair']),
('Backtesting from', strategy_results['backtest_start'].strftime(DATETIME_PRINT_FORMAT)), ('Backtesting from', strategy_results['backtest_start'].strftime(DATETIME_PRINT_FORMAT)),
('Backtesting to', strategy_results['backtest_end'].strftime(DATETIME_PRINT_FORMAT)), ('Backtesting to', strategy_results['backtest_end'].strftime(DATETIME_PRINT_FORMAT)),

View File

@ -63,7 +63,7 @@ def init_plotscript(config):
exportfilename=config.get('exportfilename'), exportfilename=config.get('exportfilename'),
no_trades=no_trades no_trades=no_trades
) )
trades = trim_dataframe(trades, timerange, 'open_time') trades = trim_dataframe(trades, timerange, 'open_date')
return {"ohlcv": data, return {"ohlcv": data,
"trades": trades, "trades": trades,
@ -166,7 +166,7 @@ def plot_trades(fig, trades: pd.DataFrame) -> make_subplots:
f"{row['sell_reason']}, {row['duration']} min", f"{row['sell_reason']}, {row['duration']} min",
axis=1) axis=1)
trade_buys = go.Scatter( trade_buys = go.Scatter(
x=trades["open_time"], x=trades["open_date"],
y=trades["open_rate"], y=trades["open_rate"],
mode='markers', mode='markers',
name='Trade buy', name='Trade buy',
@ -181,7 +181,7 @@ def plot_trades(fig, trades: pd.DataFrame) -> make_subplots:
) )
trade_sells = go.Scatter( 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"], y=trades.loc[trades['profit_percent'] > 0, "close_rate"],
text=trades.loc[trades['profit_percent'] > 0, "desc"], text=trades.loc[trades['profit_percent'] > 0, "desc"],
mode='markers', mode='markers',
@ -194,7 +194,7 @@ def plot_trades(fig, trades: pd.DataFrame) -> make_subplots:
) )
) )
trade_sells_loss = go.Scatter( 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"], y=trades.loc[trades['profit_percent'] <= 0, "close_rate"],
text=trades.loc[trades['profit_percent'] <= 0, "desc"], text=trades.loc[trades['profit_percent'] <= 0, "desc"],
mode='markers', 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. # 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. # Also, If only one open pair is left, then the profit-generation would fail.
trades = trades[(trades['pair'].isin(plot_elements["pairs"])) trades = trades[(trades['pair'].isin(plot_elements["pairs"]))
& (~trades['close_time'].isnull()) & (~trades['close_date'].isnull())
] ]
if len(trades) == 0: if len(trades) == 0:
raise OperationalException("No trades found, cannot generate Profit-plot without " raise OperationalException("No trades found, cannot generate Profit-plot without "