diff --git a/v2realbot/controller/services.py b/v2realbot/controller/services.py index 8665d88..6962aee 100644 --- a/v2realbot/controller/services.py +++ b/v2realbot/controller/services.py @@ -336,8 +336,11 @@ def capsule(target: object, db: object, inter_batch_params: dict = None): db.runners.remove(i) #vytvoreni report image pro RUNNER try: - generate_trading_report_image(runner_ids=[str(i.id)]) - print("DAILY REPORT IMAGE CREATED") + res, val = generate_trading_report_image(runner_ids=[str(i.id)]) + if res == 0: + print("DAILY REPORT IMAGE CREATED") + else: + print(f"Daily report ERROR - {val}") except Exception as e: print("Nepodarilo se vytvorit report image", str(e)+format_exc()) @@ -510,8 +513,12 @@ def batch_run_manager(id: UUID, runReq: RunRequest, rundays: list[RunDay]): #vytvoreni report image pro batch try: - generate_trading_report_image(batch_id=batch_id) - print("BATCH REPORT IMAGE CREATED") + res, val = generate_trading_report_image(batch_id=batch_id) + if res == 0: + print("BATCH REPORT CREATED") + else: + print(f"BATCH REPORT ERROR - {val}") + except Exception as e: print("Nepodarilo se vytvorit report image", str(e)+format_exc()) diff --git a/v2realbot/reporting/metricstoolsimage.py b/v2realbot/reporting/metricstoolsimage.py index d4cadf5..228564d 100644 --- a/v2realbot/reporting/metricstoolsimage.py +++ b/v2realbot/reporting/metricstoolsimage.py @@ -51,9 +51,9 @@ def generate_trading_report_image(runner_ids: list = None, batch_id: str = None, trades_dicts = sada.metrics["prescr_trades"] for trade_dict in trades_dicts: - trade_dict['last_update'] = datetime.fromtimestamp(trade_dict.get('last_update')).astimezone(zoneNY) - trade_dict['entry_time'] = datetime.fromtimestamp(trade_dict.get('entry_time')).astimezone(zoneNY) - trade_dict['exit_time'] = datetime.fromtimestamp(trade_dict.get('exit_time')).astimezone(zoneNY) + trade_dict['last_update'] = datetime.fromtimestamp(trade_dict.get('last_update')).astimezone(zoneNY) if trade_dict['last_update'] is not None else None + trade_dict['entry_time'] = datetime.fromtimestamp(trade_dict.get('entry_time')).astimezone(zoneNY) if trade_dict['entry_time'] is not None else None + trade_dict['exit_time'] = datetime.fromtimestamp(trade_dict.get('exit_time')).astimezone(zoneNY) if trade_dict['exit_time'] is not None else None trades.append(Trade(**trade_dict)) print(trades) @@ -61,10 +61,15 @@ def generate_trading_report_image(runner_ids: list = None, batch_id: str = None, # Filter to only use trades with status 'CLOSED' closed_trades = [trade for trade in trades if trade.status == TradeStatus.CLOSED] + if len(closed_trades) == 0: + return -1, "image generation no closed trades" + # Data extraction for the plots exit_times = [trade.exit_time for trade in closed_trades if trade.exit_time is not None] - cumulative_profits = [trade.profit_sum for trade in closed_trades if trade.profit_sum is not None] + ##cumulative_profits = [trade.profit_sum for trade in closed_trades if trade.profit_sum is not None] + profits = [trade.profit for trade in closed_trades if trade.profit is not None] + cumulative_profits = np.cumsum(profits) wins = [trade.profit for trade in closed_trades if trade.profit > 0] losses = [trade.profit for trade in closed_trades if trade.profit < 0] @@ -190,27 +195,35 @@ def generate_trading_report_image(runner_ids: list = None, batch_id: str = None, #Cumulative profit - bud 1 den nebo vice dni if len(runner_ids)== 1: - # Plot 3: Cumulative Profit Over Time with Max Profit Point - max_profit_time = exit_times[np.argmax(cumulative_profits)] - max_profit = max(cumulative_profits) - min_profit_time = exit_times[np.argmin(cumulative_profits)] - min_profit = min(cumulative_profits) - sns.lineplot(x=exit_times, y=cumulative_profits, label='Cumulative Profit', ax=axs[1, 3]) - axs[1, 3].scatter(max_profit_time, max_profit, color='green', label='Max Profit') - axs[1, 3].scatter(min_profit_time, min_profit, color='red', label='Min Profit') - # Format dates on the x-axis - axs[1, 3].xaxis.set_major_formatter(mdates.DateFormatter('%H', tz=zoneNY)) - axs[1, 3].set_title('Cumulative Profit Over Time') - axs[1, 3].legend() + if cumulative_profits: + # Plot 3: Cumulative Profit Over Time with Max Profit Point + max_profit_time = exit_times[np.argmax(cumulative_profits)] + max_profit = max(cumulative_profits) + min_profit_time = exit_times[np.argmin(cumulative_profits)] + min_profit = min(cumulative_profits) + sns.lineplot(x=exit_times, y=cumulative_profits, label='Cumulative Profit', ax=axs[1, 3]) + axs[1, 3].scatter(max_profit_time, max_profit, color='green', label='Max Profit') + axs[1, 3].scatter(min_profit_time, min_profit, color='red', label='Min Profit') + # Format dates on the x-axis + axs[1, 3].xaxis.set_major_formatter(mdates.DateFormatter('%H', tz=zoneNY)) + axs[1, 3].set_title('Cumulative Profit Over Time') + axs[1, 3].legend() + else: + # Handle the case where cumulative_profits is empty + axs[1, 3].text(0.5, 0.5, 'No profit data available', + horizontalalignment='center', + verticalalignment='center', + transform=axs[1, 3].transAxes) + axs[1, 3].set_title('Cumulative Profit Over Time') else: # Calculate cumulative profit # Additional Plot: Cumulative Profit Over Time # Sort trades by exit time sorted_trades = sorted([trade for trade in trades if trade.status == TradeStatus.CLOSED], key=lambda x: x.exit_time) - cumulative_profits = np.cumsum([trade.profit for trade in sorted_trades]) - exit_times_sorted = [trade.exit_time for trade in sorted_trades] - axs[1, 3].plot(exit_times_sorted, cumulative_profits, color='blue') + cumulative_profits_sorted = np.cumsum([trade.profit for trade in sorted_trades]) + exit_times_sorted = [trade.exit_time for trade in sorted_trades if trade.exit_time is not None] + axs[1, 3].plot(exit_times_sorted, cumulative_profits_sorted, color='blue') axs[1, 3].set_title('Cumulative Profit Over Time') axs[1, 3].set_xlabel('Time') axs[1, 3].set_ylabel('Cumulative Profit') @@ -226,15 +239,23 @@ def generate_trading_report_image(runner_ids: list = None, batch_id: str = None, profit = trade.profit heatmap_data_list.append({'Day': day, 'Hour': hour, 'Profit': profit}) - heatmap_data = pd.DataFrame(heatmap_data_list) - heatmap_data = heatmap_data.groupby(['Day', 'Hour']).sum().reset_index() - heatmap_pivot = heatmap_data.pivot(index='Day', columns='Hour', values='Profit') + try: + heatmap_data = pd.DataFrame(heatmap_data_list) + heatmap_data = heatmap_data.groupby(['Day', 'Hour']).sum().reset_index() + heatmap_pivot = heatmap_data.pivot(index='Day', columns='Hour', values='Profit') - # Plot 3: Heatmap of Profits - sns.heatmap(heatmap_pivot, cmap='viridis', ax=axs[1, 0]) - axs[1, 0].set_title('Heatmap of Profits (based on Exit time)') - axs[1, 0].set_xlabel('Hour of Day') - axs[1, 0].set_ylabel('Day') + # Plot 3: Heatmap of Profits + sns.heatmap(heatmap_pivot, cmap='viridis', ax=axs[1, 0]) + axs[1, 0].set_title('Heatmap of Profits (based on Exit time)') + axs[1, 0].set_xlabel('Hour of Day') + axs[1, 0].set_ylabel('Day') + except KeyError: + # Handle the case where there is no data + axs[1, 0].text(0.5, 0.5, 'No data available', + horizontalalignment='center', + verticalalignment='center', + transform=axs[1, 0].transAxes) + axs[1, 0].set_title('Heatmap of Profits (based on Exit time)') # Plot 9: Profit/Loss Distribution Histogram sns.histplot(profits, bins=30, ax=axs[1, 1], kde=True, color='skyblue') @@ -248,9 +269,17 @@ def generate_trading_report_image(runner_ids: list = None, batch_id: str = None, if len(runner_ids) == 1: sizes = [trade.size for trade in closed_trades if trade.size is not None] - size_counts = {size: sizes.count(size) for size in set(sizes)} - sns.barplot(x=list(size_counts.keys()), y=list(size_counts.values()), ax=axs[1, 2]) - axs[1, 2].set_title('Position Size Distribution') + if sizes: + size_counts = {size: sizes.count(size) for size in set(sizes)} + sns.barplot(x=list(size_counts.keys()), y=list(size_counts.values()), ax=axs[1, 2]) + axs[1, 2].set_title('Position Size Distribution') + else: + # Handle the case where there is no data + axs[1, 2].text(0.5, 0.5, 'No data available', + horizontalalignment='center', + verticalalignment='center', + transform=axs[1, 2].transAxes) + axs[1, 2].set_title('Position Size Distribution') else: trade_durations = [] trade_profits = [] @@ -317,10 +346,18 @@ def generate_trading_report_image(runner_ids: list = None, batch_id: str = None, sorted_hours = sorted(profits_by_hour.keys()) sorted_profits = [profits_by_hour[hour] for hour in sorted_hours] - sns.barplot(x=sorted_hours, y=sorted_profits, ax=axs[2, 1]) - axs[2, 1].set_title('Profits by Hour of Day (Entry)') - axs[2, 1].set_xlabel('Hour of Day') - axs[2, 1].set_ylabel('Profit') + if sorted_profits: + sns.barplot(x=sorted_hours, y=sorted_profits, ax=axs[2, 1]) + axs[2, 1].set_title('Profits by Hour of Day (Entry)') + axs[2, 1].set_xlabel('Hour of Day') + axs[2, 1].set_ylabel('Profit') + else: + # Handle the case where sorted_profits is empty + axs[2, 1].text(0.5, 0.5, 'No data available', + horizontalalignment='center', + verticalalignment='center', + transform=axs[2, 1].transAxes) + axs[2, 1].set_title('Profits by Hour of Day (Entry)') # Plot 9: Profits Based on Hour of the Day - based on Exit exit_hours = [trade.exit_time.hour for trade in closed_trades if trade.exit_time is not None] @@ -334,10 +371,18 @@ def generate_trading_report_image(runner_ids: list = None, batch_id: str = None, sorted_hours = sorted(profits_by_hour.keys()) sorted_profits = [profits_by_hour[hour] for hour in sorted_hours] - sns.barplot(x=sorted_hours, y=sorted_profits, ax=axs[2, 2]) - axs[2, 2].set_title('Profits by Hour of Day (Exit)') - axs[2, 2].set_xlabel('Hour of Day') - axs[2, 2].set_ylabel('Profit') + if sorted_profits: + sns.barplot(x=sorted_hours, y=sorted_profits, ax=axs[2, 2]) + axs[2, 2].set_title('Profits by Hour of Day (Exit)') + axs[2, 2].set_xlabel('Hour of Day') + axs[2, 2].set_ylabel('Profit') + else: + # Handle the case where sorted_profits is empty + axs[2, 2].text(0.5, 0.5, 'No data available', + horizontalalignment='center', + verticalalignment='center', + transform=axs[2, 2].transAxes) + axs[2, 2].set_title('Profits by Hour of Day (Exit)') # Calculate profits by day of the week day_of_week_profits = {i: 0 for i in range(7)} # Dictionary to store profits for each day of the week @@ -365,6 +410,7 @@ def generate_trading_report_image(runner_ids: list = None, batch_id: str = None, if stream is False: plt.savefig(image_path) plt.close() + return 0, None else: # Return the image as a BytesIO stream img_stream = BytesIO() diff --git a/v2realbot/static/index.html b/v2realbot/static/index.html index 63f9e6d..4bc7555 100644 --- a/v2realbot/static/index.html +++ b/v2realbot/static/index.html @@ -279,8 +279,15 @@ -
- +