Changed exit_tag to be represented as sell_reason

This commit is contained in:
theluxaz 2021-10-20 01:26:15 +03:00
parent 5ecdd1d112
commit 1fdc4425dd
6 changed files with 37 additions and 62 deletions

View File

@ -1150,6 +1150,7 @@ class FreqtradeBot(LoggingMixin):
trade.close_rate_requested = limit
trade.sell_reason = sell_reason.sell_reason
if(exit_tag is not None):
trade.sell_reason = exit_tag
trade.exit_tag = exit_tag
# In case of market sell orders the order can be closed immediately
if order.get('status', 'unknown') in ('closed', 'expired'):
@ -1191,8 +1192,8 @@ class FreqtradeBot(LoggingMixin):
'current_rate': current_rate,
'profit_amount': profit_trade,
'profit_ratio': profit_ratio,
'buy_tag': trade.buy_tag,
'sell_reason': trade.sell_reason,
'exit_tag': trade.exit_tag,
'open_date': trade.open_date,
'close_date': trade.close_date or datetime.utcnow(),
'stake_currency': self.config['stake_currency'],
@ -1235,8 +1236,8 @@ class FreqtradeBot(LoggingMixin):
'current_rate': current_rate,
'profit_amount': profit_trade,
'profit_ratio': profit_ratio,
'buy_tag': trade.buy_tag,
'sell_reason': trade.sell_reason,
'exit_tag': trade.exit_tag,
'open_date': trade.open_date,
'close_date': trade.close_date or datetime.now(timezone.utc),
'stake_currency': self.config['stake_currency'],

View File

@ -360,11 +360,10 @@ class Backtesting:
if sell.sell_flag:
trade.close_date = sell_candle_time
if(sell_row[EXIT_TAG_IDX] is not None):
trade.exit_tag = sell_row[EXIT_TAG_IDX]
else:
trade.exit_tag = None
trade.sell_reason = sell.sell_reason
if(sell_row[EXIT_TAG_IDX] is not None):
trade.sell_reason = sell_row[EXIT_TAG_IDX]
trade.exit_tag = sell_row[EXIT_TAG_IDX]
trade_dur = int((trade.close_date_utc - trade.open_date_utc).total_seconds() // 60)
closerate = self._get_close_rate(sell_row, trade, sell, trade_dur)

View File

@ -387,8 +387,6 @@ def generate_strategy_stats(btdata: Dict[str, DataFrame],
buy_tag_results = generate_tag_metrics("buy_tag", starting_balance=starting_balance,
results=results, skip_nan=False)
exit_tag_results = generate_tag_metrics("exit_tag", starting_balance=starting_balance,
results=results, skip_nan=False)
sell_reason_stats = generate_sell_reason_stats(max_open_trades=max_open_trades,
results=results)
@ -414,7 +412,6 @@ def generate_strategy_stats(btdata: Dict[str, DataFrame],
'worst_pair': worst_pair,
'results_per_pair': pair_results,
'results_per_buy_tag': buy_tag_results,
'results_per_exit_tag': exit_tag_results,
'sell_reason_summary': sell_reason_stats,
'left_open_trades': left_open_results,
'total_trades': len(results),
@ -744,15 +741,6 @@ def show_backtest_result(strategy: str, results: Dict[str, Any], stake_currency:
print(' BUY TAG STATS '.center(len(table.splitlines()[0]), '='))
print(table)
table = text_table_tags(
"exit_tag",
results['results_per_exit_tag'],
stake_currency=stake_currency)
if isinstance(table, str) and len(table) > 0:
print(' SELL 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:

View File

@ -325,7 +325,6 @@ class LocalTrade():
'profit_pct': round(self.close_profit * 100, 2) if self.close_profit else None,
'profit_abs': self.close_profit_abs,
# +str(self.sell_reason) ## CHANGE TO BUY TAG IF NEEDED
'sell_reason': (f' ({self.sell_reason})' if self.sell_reason else ''),
'exit_tag': (f' ({self.exit_tag})' if self.exit_tag else ''),
'sell_order_status': self.sell_order_status,
@ -904,15 +903,15 @@ class Trade(_DECL_BASE, LocalTrade):
]
@staticmethod
def get_exit_tag_performance(pair: str) -> List[Dict[str, Any]]:
def get_sell_reason_performance(pair: str) -> List[Dict[str, Any]]:
"""
Returns List of dicts containing all Trades, based on exit tag performance
Returns List of dicts containing all Trades, based on sell reason performance
Can either be average for all pairs or a specific pair provided
NOTE: Not supported in Backtesting.
"""
if(pair is not None):
tag_perf = Trade.query.with_entities(
Trade.exit_tag,
Trade.sell_reason,
func.sum(Trade.close_profit).label('profit_sum'),
func.sum(Trade.close_profit_abs).label('profit_sum_abs'),
func.count(Trade.pair).label('count')
@ -922,29 +921,29 @@ class Trade(_DECL_BASE, LocalTrade):
.all()
else:
tag_perf = Trade.query.with_entities(
Trade.exit_tag,
Trade.sell_reason,
func.sum(Trade.close_profit).label('profit_sum'),
func.sum(Trade.close_profit_abs).label('profit_sum_abs'),
func.count(Trade.pair).label('count')
).filter(Trade.is_open.is_(False))\
.group_by(Trade.exit_tag) \
.group_by(Trade.sell_reason) \
.order_by(desc('profit_sum_abs')) \
.all()
return [
{
'exit_tag': exit_tag if exit_tag is not None else "Other",
'sell_reason': sell_reason if sell_reason is not None else "Other",
'profit': profit,
'profit_abs': profit_abs,
'count': count
}
for exit_tag, profit, profit_abs, count in tag_perf
for sell_reason, profit, profit_abs, count in tag_perf
]
@staticmethod
def get_mix_tag_performance(pair: str) -> List[Dict[str, Any]]:
"""
Returns List of dicts containing all Trades, based on buy_tag + exit_tag performance
Returns List of dicts containing all Trades, based on buy_tag + sell_reason performance
Can either be average for all pairs or a specific pair provided
NOTE: Not supported in Backtesting.
"""
@ -952,7 +951,7 @@ class Trade(_DECL_BASE, LocalTrade):
tag_perf = Trade.query.with_entities(
Trade.id,
Trade.buy_tag,
Trade.exit_tag,
Trade.sell_reason,
func.sum(Trade.close_profit).label('profit_sum'),
func.sum(Trade.close_profit_abs).label('profit_sum_abs'),
func.count(Trade.pair).label('count')
@ -965,7 +964,7 @@ class Trade(_DECL_BASE, LocalTrade):
tag_perf = Trade.query.with_entities(
Trade.id,
Trade.buy_tag,
Trade.exit_tag,
Trade.sell_reason,
func.sum(Trade.close_profit).label('profit_sum'),
func.sum(Trade.close_profit_abs).label('profit_sum_abs'),
func.count(Trade.pair).label('count')
@ -975,12 +974,12 @@ class Trade(_DECL_BASE, LocalTrade):
.all()
return_list = []
for id, buy_tag, exit_tag, profit, profit_abs, count in tag_perf:
for id, buy_tag, sell_reason, profit, profit_abs, count in tag_perf:
buy_tag = buy_tag if buy_tag is not None else "Other"
exit_tag = exit_tag if exit_tag is not None else "Other"
sell_reason = sell_reason if sell_reason is not None else "Other"
if(exit_tag is not None and buy_tag is not None):
mix_tag = buy_tag + " " + exit_tag
if(sell_reason is not None and buy_tag is not None):
mix_tag = buy_tag + " " + sell_reason
i = 0
if not any(item["mix_tag"] == mix_tag for item in return_list):
return_list.append({'mix_tag': mix_tag,
@ -990,8 +989,6 @@ class Trade(_DECL_BASE, LocalTrade):
else:
while i < len(return_list):
if return_list[i]["mix_tag"] == mix_tag:
print("item below")
print(return_list[i])
return_list[i] = {
'mix_tag': mix_tag,
'profit': profit + return_list[i]["profit"],

View File

@ -161,6 +161,8 @@ class RPC:
current_rate = NAN
else:
current_rate = trade.close_rate
buy_tag = trade.buy_tag
current_profit = trade.calc_profit_ratio(current_rate)
current_profit_abs = trade.calc_profit(current_rate)
current_profit_fiat: Optional[float] = None
@ -191,6 +193,7 @@ class RPC:
profit_pct=round(current_profit * 100, 2),
profit_abs=current_profit_abs,
profit_fiat=current_profit_fiat,
buy_tag=buy_tag,
stoploss_current_dist=stoploss_current_dist,
stoploss_current_dist_ratio=round(stoploss_current_dist_ratio, 8),
@ -696,19 +699,19 @@ class RPC:
[x.update({'profit': round(x['profit'] * 100, 2)}) for x in buy_tags]
return buy_tags
def _rpc_exit_tag_performance(self, pair: str) -> List[Dict[str, Any]]:
def _rpc_sell_reason_performance(self, pair: str) -> List[Dict[str, Any]]:
"""
Handler for sell tag performance.
Handler for sell reason performance.
Shows a performance statistic from finished trades
"""
exit_tags = Trade.get_exit_tag_performance(pair)
sell_reasons = Trade.get_sell_reason_performance(pair)
# Round and convert to %
[x.update({'profit': round(x['profit'] * 100, 2)}) for x in exit_tags]
return exit_tags
[x.update({'profit': round(x['profit'] * 100, 2)}) for x in sell_reasons]
return sell_reasons
def _rpc_mix_tag_performance(self, pair: str) -> List[Dict[str, Any]]:
"""
Handler for mix tag performance.
Handler for mix tag (buy_tag + exit_tag) performance.
Shows a performance statistic from finished trades
"""
mix_tags = Trade.get_mix_tag_performance(pair)

View File

@ -156,7 +156,7 @@ class Telegram(RPCHandler):
CommandHandler('delete', self._delete_trade),
CommandHandler('performance', self._performance),
CommandHandler('buys', self._buy_tag_performance),
CommandHandler('sells', self._exit_tag_performance),
CommandHandler('sells', self._sell_reason_performance),
CommandHandler('mix_tags', self._mix_tag_performance),
CommandHandler('stats', self._stats),
CommandHandler('daily', self._daily),
@ -244,8 +244,8 @@ class Telegram(RPCHandler):
msg['duration'] = msg['close_date'].replace(
microsecond=0) - msg['open_date'].replace(microsecond=0)
msg['duration_min'] = msg['duration'].total_seconds() / 60
msg['tags'] = self._get_tags_string(msg)
msg['buy_tag'] = msg['buy_tag'] if "buy_tag" in msg.keys() else None
msg['emoji'] = self._get_sell_emoji(msg)
# Check if all sell properties are available.
@ -261,7 +261,7 @@ class Telegram(RPCHandler):
message = ("{emoji} *{exchange}:* Selling {pair} (#{trade_id})\n"
"*Profit:* `{profit_percent:.2f}%{profit_extra}`\n"
"{tags}"
"*Buy Tag:* `{buy_tag}`\n"
"*Sell Reason:* `{sell_reason}`\n"
"*Duration:* `{duration} ({duration_min:.1f} min)`\n"
"*Amount:* `{amount:.8f}`\n"
@ -357,18 +357,6 @@ class Telegram(RPCHandler):
else:
return "\N{CROSS MARK}"
def _get_tags_string(self, msg):
"""
Get string lines for buy/sell tags to display when a sell is made
"""
tag_lines = ""
if ("buy_tag" in msg.keys() and msg['buy_tag'] is not None):
tag_lines += ("*Buy Tag:* `{buy_tag}`\n").format(msg['buy_tag'])
if ("exit_tag" in msg.keys() and msg['exit_tag'] is not None):
tag_lines += ("*Sell Tag:* `{exit_tag}`\n").format(msg['exit_tag'])
return tag_lines
@authorized_only
def _status(self, update: Update, context: CallbackContext) -> None:
"""
@ -401,7 +389,6 @@ class Telegram(RPCHandler):
"*Current Pair:* {pair}",
"*Amount:* `{amount} ({stake_amount} {base_currency})`",
"*Buy Tag:* `{buy_tag}`" if r['buy_tag'] else "",
"*Sell Tag:* `{exit_tag}`" if r['exit_tag'] else "",
"*Open Rate:* `{open_rate:.8f}`",
"*Close Rate:* `{close_rate}`" if r['close_rate'] else "",
"*Current Rate:* `{current_rate:.8f}`",
@ -925,7 +912,7 @@ class Telegram(RPCHandler):
self._send_msg(str(e))
@authorized_only
def _exit_tag_performance(self, update: Update, context: CallbackContext) -> None:
def _sell_reason_performance(self, update: Update, context: CallbackContext) -> None:
"""
Handler for /sells.
Shows a performance statistic from finished trades
@ -938,11 +925,11 @@ class Telegram(RPCHandler):
if context.args:
pair = context.args[0]
trades = self._rpc._rpc_exit_tag_performance(pair)
output = "<b>Sell Tag Performance:</b>\n"
trades = self._rpc._rpc_sell_reason_performance(pair)
output = "<b>Sell Reason Performance:</b>\n"
for i, trade in enumerate(trades):
stat_line = (
f"{i+1}.\t <code>{trade['exit_tag']}\t"
f"{i+1}.\t <code>{trade['sell_reason']}\t"
f"{round_coin_value(trade['profit_abs'], self._config['stake_currency'])} "
f"({trade['profit']:.2f}%) "
f"({trade['count']})</code>\n")
@ -954,7 +941,7 @@ class Telegram(RPCHandler):
output += stat_line
self._send_msg(output, parse_mode=ParseMode.HTML,
reload_able=True, callback_path="update_exit_tag_performance",
reload_able=True, callback_path="update_sell_reason_performance",
query=update.callback_query)
except RPCException as e:
self._send_msg(str(e))