Added sell_tag and buy/sell telegram performance functions
This commit is contained in:
@@ -82,7 +82,7 @@ def _generate_result_line(result: DataFrame, starting_balance: int, first_column
|
||||
'profit_sum_pct': round(profit_sum * 100.0, 2),
|
||||
'profit_total_abs': result['profit_abs'].sum(),
|
||||
'profit_total': profit_total,
|
||||
'profit_total_pct': round(profit_total * 100.0, 2),
|
||||
'profit_total_pct': round(profit_sum * 100.0, 2),
|
||||
'duration_avg': str(timedelta(
|
||||
minutes=round(result['trade_duration'].mean()))
|
||||
) if not result.empty else '0:00',
|
||||
@@ -126,6 +126,92 @@ def generate_pair_metrics(data: Dict[str, Dict], stake_currency: str, starting_b
|
||||
tabular_data.append(_generate_result_line(results, starting_balance, 'TOTAL'))
|
||||
return tabular_data
|
||||
|
||||
def generate_tag_metrics(tag_type:str, data: Dict[str, Dict], stake_currency: str, starting_balance: int,
|
||||
results: DataFrame, skip_nan: bool = False) -> List[Dict]:
|
||||
"""
|
||||
Generates and returns a list of metrics for the given tag trades and the results dataframe
|
||||
:param data: Dict of <pair: dataframe> containing data that was used during backtesting.
|
||||
:param stake_currency: stake-currency - used to correctly name headers
|
||||
:param starting_balance: Starting balance
|
||||
:param results: Dataframe containing the backtest results
|
||||
:param skip_nan: Print "left open" open trades
|
||||
:return: List of Dicts containing the metrics per pair
|
||||
"""
|
||||
|
||||
tabular_data = []
|
||||
|
||||
# for tag, count in results[tag_type].value_counts().iteritems():
|
||||
# result = results.loc[results[tag_type] == tag]
|
||||
#
|
||||
# profit_mean = result['profit_ratio'].mean()
|
||||
# profit_sum = result['profit_ratio'].sum()
|
||||
# profit_total = profit_sum / max_open_trades
|
||||
#
|
||||
# tabular_data.append(
|
||||
# {
|
||||
# 'sell_reason': tag,
|
||||
# 'trades': count,
|
||||
# 'wins': len(result[result['profit_abs'] > 0]),
|
||||
# 'draws': len(result[result['profit_abs'] == 0]),
|
||||
# 'losses': len(result[result['profit_abs'] < 0]),
|
||||
# 'profit_mean': profit_mean,
|
||||
# 'profit_mean_pct': round(profit_mean * 100, 2),
|
||||
# 'profit_sum': profit_sum,
|
||||
# 'profit_sum_pct': round(profit_sum * 100, 2),
|
||||
# 'profit_total_abs': result['profit_abs'].sum(),
|
||||
# 'profit_total': profit_total,
|
||||
# 'profit_total_pct': round(profit_total * 100, 2),
|
||||
# }
|
||||
# )
|
||||
#
|
||||
# tabular_data = []
|
||||
|
||||
for tag, count in results[tag_type].value_counts().iteritems():
|
||||
result = results[results[tag_type] == tag]
|
||||
if skip_nan and result['profit_abs'].isnull().all():
|
||||
continue
|
||||
|
||||
tabular_data.append(_generate_tag_result_line(result, starting_balance, tag))
|
||||
|
||||
# Sort by total profit %:
|
||||
tabular_data = sorted(tabular_data, key=lambda k: k['profit_total_abs'], reverse=True)
|
||||
|
||||
# Append Total
|
||||
tabular_data.append(_generate_result_line(results, starting_balance, 'TOTAL'))
|
||||
return tabular_data
|
||||
|
||||
def _generate_tag_result_line(result: DataFrame, starting_balance: int, first_column: str) -> Dict:
|
||||
"""
|
||||
Generate one result dict, with "first_column" as key.
|
||||
"""
|
||||
profit_sum = result['profit_ratio'].sum()
|
||||
# (end-capital - starting capital) / starting capital
|
||||
profit_total = result['profit_abs'].sum() / starting_balance
|
||||
|
||||
return {
|
||||
'key': first_column,
|
||||
'trades': len(result),
|
||||
'profit_mean': result['profit_ratio'].mean() if len(result) > 0 else 0.0,
|
||||
'profit_mean_pct': result['profit_ratio'].mean() * 100.0 if len(result) > 0 else 0.0,
|
||||
'profit_sum': profit_sum,
|
||||
'profit_sum_pct': round(profit_sum * 100.0, 2),
|
||||
'profit_total_abs': result['profit_abs'].sum(),
|
||||
'profit_total': profit_total,
|
||||
'profit_total_pct': round(profit_total * 100.0, 2),
|
||||
'duration_avg': str(timedelta(
|
||||
minutes=round(result['trade_duration'].mean()))
|
||||
) if not result.empty else '0:00',
|
||||
# 'duration_max': str(timedelta(
|
||||
# minutes=round(result['trade_duration'].max()))
|
||||
# ) if not result.empty else '0:00',
|
||||
# 'duration_min': str(timedelta(
|
||||
# minutes=round(result['trade_duration'].min()))
|
||||
# ) if not result.empty else '0:00',
|
||||
'wins': len(result[result['profit_abs'] > 0]),
|
||||
'draws': len(result[result['profit_abs'] == 0]),
|
||||
'losses': len(result[result['profit_abs'] < 0]),
|
||||
}
|
||||
|
||||
|
||||
def generate_sell_reason_stats(max_open_trades: int, results: DataFrame) -> List[Dict]:
|
||||
"""
|
||||
@@ -313,6 +399,13 @@ def generate_strategy_stats(btdata: Dict[str, DataFrame],
|
||||
pair_results = generate_pair_metrics(btdata, stake_currency=stake_currency,
|
||||
starting_balance=starting_balance,
|
||||
results=results, skip_nan=False)
|
||||
buy_tag_results = generate_tag_metrics("buy_tag",btdata, stake_currency=stake_currency,
|
||||
starting_balance=starting_balance,
|
||||
results=results, skip_nan=False)
|
||||
sell_tag_results = generate_tag_metrics("sell_tag",btdata, stake_currency=stake_currency,
|
||||
starting_balance=starting_balance,
|
||||
results=results, skip_nan=False)
|
||||
|
||||
sell_reason_stats = generate_sell_reason_stats(max_open_trades=max_open_trades,
|
||||
results=results)
|
||||
left_open_results = generate_pair_metrics(btdata, stake_currency=stake_currency,
|
||||
@@ -336,6 +429,8 @@ def generate_strategy_stats(btdata: Dict[str, DataFrame],
|
||||
'best_pair': best_pair,
|
||||
'worst_pair': worst_pair,
|
||||
'results_per_pair': pair_results,
|
||||
'results_per_buy_tag': buy_tag_results,
|
||||
'results_per_sell_tag': sell_tag_results,
|
||||
'sell_reason_summary': sell_reason_stats,
|
||||
'left_open_trades': left_open_results,
|
||||
'total_trades': len(results),
|
||||
@@ -504,6 +599,27 @@ def text_table_sell_reason(sell_reason_stats: List[Dict[str, Any]], stake_curren
|
||||
] for t in sell_reason_stats]
|
||||
return tabulate(output, headers=headers, tablefmt="orgtbl", stralign="right")
|
||||
|
||||
def text_table_tags(tag_type:str, tag_results: List[Dict[str, Any]], stake_currency: str) -> str:
|
||||
"""
|
||||
Generates and returns a text table for the given backtest data and the results dataframe
|
||||
:param pair_results: List of Dictionaries - one entry per pair + final TOTAL row
|
||||
:param stake_currency: stake-currency - used to correctly name headers
|
||||
:return: pretty printed table with tabulate as string
|
||||
"""
|
||||
|
||||
headers = _get_line_header("TAG", stake_currency)
|
||||
floatfmt = _get_line_floatfmt(stake_currency)
|
||||
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'])
|
||||
] for t in tag_results]
|
||||
# Ignore type as floatfmt does allow tuples but mypy does not know that
|
||||
return tabulate(output, headers=headers,
|
||||
floatfmt=floatfmt, tablefmt="orgtbl", stralign="right")
|
||||
|
||||
|
||||
|
||||
|
||||
def text_table_strategy(strategy_results, stake_currency: str) -> str:
|
||||
"""
|
||||
@@ -624,12 +740,24 @@ def show_backtest_result(strategy: str, results: Dict[str, Any], stake_currency:
|
||||
print(' BACKTESTING REPORT '.center(len(table.splitlines()[0]), '='))
|
||||
print(table)
|
||||
|
||||
|
||||
table = text_table_tags("buy_tag", results['results_per_buy_tag'], stake_currency=stake_currency)
|
||||
|
||||
if isinstance(table, str) and len(table) > 0:
|
||||
print(' BUY TAG STATS '.center(len(table.splitlines()[0]), '='))
|
||||
print(table)
|
||||
|
||||
|
||||
table = text_table_sell_reason(sell_reason_stats=results['sell_reason_summary'],
|
||||
stake_currency=stake_currency)
|
||||
if isinstance(table, str) and len(table) > 0:
|
||||
print(' SELL REASON STATS '.center(len(table.splitlines()[0]), '='))
|
||||
print(table)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
table = text_table_bt_results(results['left_open_trades'], stake_currency=stake_currency)
|
||||
if isinstance(table, str) and len(table) > 0:
|
||||
print(' LEFT OPEN TRADES REPORT '.center(len(table.splitlines()[0]), '='))
|
||||
@@ -640,8 +768,16 @@ def show_backtest_result(strategy: str, results: Dict[str, Any], stake_currency:
|
||||
print(' SUMMARY METRICS '.center(len(table.splitlines()[0]), '='))
|
||||
print(table)
|
||||
|
||||
table = text_table_tags("sell_tag",results['results_per_sell_tag'], stake_currency=stake_currency)
|
||||
|
||||
if isinstance(table, str) and len(table) > 0:
|
||||
print(' SELL TAG STATS '.center(len(table.splitlines()[0]), '='))
|
||||
print(table)
|
||||
|
||||
if isinstance(table, str) and len(table) > 0:
|
||||
print('=' * len(table.splitlines()[0]))
|
||||
|
||||
|
||||
print()
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user