|
|
|
|
@ -16,6 +16,8 @@ from pathlib import Path
|
|
|
|
|
from v2realbot.config import WEB_API_KEY, DATA_DIR, MEDIA_DIRECTORY
|
|
|
|
|
from v2realbot.enums.enums import RecordType, StartBarAlign, Mode, Account, OrderSide
|
|
|
|
|
from io import BytesIO
|
|
|
|
|
from v2realbot.utils.historicals import get_historical_bars
|
|
|
|
|
from alpaca.data.timeframe import TimeFrame, TimeFrameUnit
|
|
|
|
|
# Assuming Trade, TradeStatus, TradeDirection, TradeStoplossType classes are defined elsewhere
|
|
|
|
|
|
|
|
|
|
def generate_trading_report_image(runner_ids: list = None, batch_id: str = None, stream: bool = False):
|
|
|
|
|
@ -35,7 +37,13 @@ def generate_trading_report_image(runner_ids: list = None, batch_id: str = None,
|
|
|
|
|
return -1, f"no batch {batch_id} found"
|
|
|
|
|
|
|
|
|
|
trades = []
|
|
|
|
|
cnt_max = len(runner_ids)
|
|
|
|
|
cnt = 0
|
|
|
|
|
#zatim zjistujeme start a end z min a max dni - jelikoz muze byt i seznam runner_ids a nejenom batch
|
|
|
|
|
end_date = None
|
|
|
|
|
start_date = None
|
|
|
|
|
for id in runner_ids:
|
|
|
|
|
cnt += 1
|
|
|
|
|
#get runner
|
|
|
|
|
res, sada =cs.get_archived_runner_header_byID(id)
|
|
|
|
|
if res != 0:
|
|
|
|
|
@ -45,8 +53,11 @@ def generate_trading_report_image(runner_ids: list = None, batch_id: str = None,
|
|
|
|
|
print("archrunner")
|
|
|
|
|
print(sada)
|
|
|
|
|
|
|
|
|
|
if cnt == 1:
|
|
|
|
|
start_date = sada.bt_from if sada.mode in [Mode.BT,Mode.PREP] else sada.started
|
|
|
|
|
if cnt == cnt_max:
|
|
|
|
|
end_date = sada.bt_to if sada.mode in [Mode.BT or Mode.PREP] else sada.stopped
|
|
|
|
|
# Parse trades
|
|
|
|
|
#trades = [Trade(**trade_dict) for trade_dict in set.metrics["prescr_trades"]]
|
|
|
|
|
|
|
|
|
|
trades_dicts = sada.metrics["prescr_trades"]
|
|
|
|
|
|
|
|
|
|
@ -58,6 +69,27 @@ def generate_trading_report_image(runner_ids: list = None, batch_id: str = None,
|
|
|
|
|
|
|
|
|
|
print(trades)
|
|
|
|
|
|
|
|
|
|
symbol = sada.symbol
|
|
|
|
|
#hour bars for backtested period
|
|
|
|
|
print(start_date,end_date)
|
|
|
|
|
bars= get_historical_bars(symbol, start_date, end_date, TimeFrame.Hour)
|
|
|
|
|
print("bars for given period",bars)
|
|
|
|
|
"""Bars a dictionary with the following keys:
|
|
|
|
|
* high: A list of high prices
|
|
|
|
|
* low: A list of low prices
|
|
|
|
|
* volume: A list of volumes
|
|
|
|
|
* close: A list of close prices
|
|
|
|
|
* hlcc4: A list of HLCC4 indicators
|
|
|
|
|
* open: A list of open prices
|
|
|
|
|
* time: A list of times in UTC (ISO 8601 format)
|
|
|
|
|
* trades: A list of number of trades
|
|
|
|
|
* resolution: A list of resolutions (all set to 'D')
|
|
|
|
|
* confirmed: A list of booleans (all set to True)
|
|
|
|
|
* vwap: A list of VWAP indicator
|
|
|
|
|
* updated: A list of booleans (all set to True)
|
|
|
|
|
* index: A list of integers (from 0 to the length of the list of daily bars)
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
# Filter to only use trades with status 'CLOSED'
|
|
|
|
|
closed_trades = [trade for trade in trades if trade.status == TradeStatus.CLOSED]
|
|
|
|
|
|
|
|
|
|
@ -83,7 +115,7 @@ def generate_trading_report_image(runner_ids: list = None, batch_id: str = None,
|
|
|
|
|
long_profits = [trade.profit for trade in closed_trades if trade.direction == TradeDirection.LONG and trade.profit is not None]
|
|
|
|
|
short_profits = [trade.profit for trade in closed_trades if trade.direction == TradeDirection.SHORT and trade.profit is not None]
|
|
|
|
|
|
|
|
|
|
# # Setting up dark mode for the plots
|
|
|
|
|
# Setting up dark mode for the plots
|
|
|
|
|
plt.style.use('dark_background')
|
|
|
|
|
|
|
|
|
|
# Optionally, you can further customize colors, labels, and axes
|
|
|
|
|
@ -104,45 +136,44 @@ def generate_trading_report_image(runner_ids: list = None, batch_id: str = None,
|
|
|
|
|
}
|
|
|
|
|
plt.rcParams.update(params)
|
|
|
|
|
|
|
|
|
|
#NEW LOOK
|
|
|
|
|
# # Set the style to dark mode with custom settings
|
|
|
|
|
|
|
|
|
|
#Custom dark theme similar to the provided image
|
|
|
|
|
# dark_finance_theme = {
|
|
|
|
|
# 'background': '#1a1a1a', # Very dark (almost black) background
|
|
|
|
|
# 'text': '#eaeaea', # Light grey text for readability
|
|
|
|
|
# 'grid': '#333333', # Dark grey grid lines
|
|
|
|
|
# 'accent': '#2e91e5', # Bright blue accent for main elements
|
|
|
|
|
# 'secondary': '#e15f99', # Secondary pink/magenta color for highlights
|
|
|
|
|
# 'highlight': '#fcba03', # Gold-like color for special highlights
|
|
|
|
|
# }
|
|
|
|
|
|
|
|
|
|
# # Apply the theme settings
|
|
|
|
|
# plt.style.use('dark_background')
|
|
|
|
|
# plt.rcParams.update({
|
|
|
|
|
# 'figure.facecolor': dark_finance_theme['background'],
|
|
|
|
|
# 'axes.facecolor': dark_finance_theme['background'],
|
|
|
|
|
# 'axes.edgecolor': dark_finance_theme['text'],
|
|
|
|
|
# 'axes.labelcolor': dark_finance_theme['text'],
|
|
|
|
|
# 'axes.titlesize': 12,
|
|
|
|
|
# 'axes.labelsize': 10,
|
|
|
|
|
# 'xtick.color': dark_finance_theme['text'],
|
|
|
|
|
# 'xtick.labelsize': 8,
|
|
|
|
|
# 'ytick.color': dark_finance_theme['text'],
|
|
|
|
|
# 'ytick.labelsize': 8,
|
|
|
|
|
# 'grid.color': dark_finance_theme['grid'],
|
|
|
|
|
# 'grid.linestyle': '-',
|
|
|
|
|
# 'grid.linewidth': 0.6,
|
|
|
|
|
# 'legend.facecolor': dark_finance_theme['background'],
|
|
|
|
|
# 'legend.edgecolor': dark_finance_theme['background'],
|
|
|
|
|
# 'legend.fontsize': 10,
|
|
|
|
|
# 'text.color': dark_finance_theme['text'],
|
|
|
|
|
# 'lines.color': dark_finance_theme['accent'],
|
|
|
|
|
# 'patch.edgecolor': dark_finance_theme['accent'],
|
|
|
|
|
# })
|
|
|
|
|
|
|
|
|
|
# # Define a custom dark theme color palette
|
|
|
|
|
# dark_theme_colors = {
|
|
|
|
|
# 'background': '#1c1c1c', # Dark gray
|
|
|
|
|
# 'text': '#d6d6d6', # Light gray for a subtle contrast
|
|
|
|
|
# 'grid': '#414141', # Slightly lighter gray than background for grid
|
|
|
|
|
# 'highlight': '#3498db', # Bright blue for highlights (max/min points, etc.)
|
|
|
|
|
# 'warning': '#e74c3c', # Red color for warnings or important highlights
|
|
|
|
|
# 'neutral': '#7f8c8d', # Neutral color for less important elements
|
|
|
|
|
# }
|
|
|
|
|
|
|
|
|
|
# # Customize the color scheme
|
|
|
|
|
# params = {
|
|
|
|
|
# 'figure.facecolor': dark_theme_colors['background'],
|
|
|
|
|
# 'axes.titlesize': 10,
|
|
|
|
|
# 'axes.labelsize': 9,
|
|
|
|
|
# 'xtick.labelsize': 9,
|
|
|
|
|
# 'ytick.labelsize': 9,
|
|
|
|
|
# 'axes.labelcolor': dark_theme_colors['text'],
|
|
|
|
|
# 'axes.facecolor': dark_theme_colors['background'],
|
|
|
|
|
# 'axes.grid': False, # Control grid visibility
|
|
|
|
|
# 'axes.edgecolor': dark_theme_colors['text'],
|
|
|
|
|
# 'xtick.color': dark_theme_colors['text'],
|
|
|
|
|
# 'ytick.color': dark_theme_colors['text'],
|
|
|
|
|
# 'text.color': dark_theme_colors['text'],
|
|
|
|
|
# 'legend.facecolor': dark_theme_colors['background'],
|
|
|
|
|
# 'legend.edgecolor': dark_theme_colors['text'],
|
|
|
|
|
# 'legend.fontsize': 8,
|
|
|
|
|
# 'legend.title_fontsize': 9,
|
|
|
|
|
# }
|
|
|
|
|
|
|
|
|
|
# # Apply the custom color scheme
|
|
|
|
|
# plt.rcParams.update(params)
|
|
|
|
|
|
|
|
|
|
# Create a combined figure for all plots
|
|
|
|
|
fig, axs = plt.subplots(3, 4, figsize=(11, 7))
|
|
|
|
|
# Create a combined figure for all plots 11,7 ideal na 3,4
|
|
|
|
|
fig, axs = plt.subplots(3, 4, figsize=(12, 7))
|
|
|
|
|
|
|
|
|
|
#TITLE
|
|
|
|
|
title = ""
|
|
|
|
|
@ -229,43 +260,7 @@ def generate_trading_report_image(runner_ids: list = None, batch_id: str = None,
|
|
|
|
|
place_annotation(axs[0, 3], 0, long_count, offset)
|
|
|
|
|
place_annotation(axs[0, 3], 1, short_count, offset)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#Cumulative profit - bud 1 den nebo vice dni
|
|
|
|
|
if len(runner_ids)== 1:
|
|
|
|
|
if cumulative_profits.size > 0:
|
|
|
|
|
# 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_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')
|
|
|
|
|
axs[1, 3].xaxis.set_major_formatter(mdates.DateFormatter('%d', tz=zoneNY))
|
|
|
|
|
|
|
|
|
|
#PLOT 5 - Heatman (exit time)
|
|
|
|
|
# Creating a DataFrame for the heatmap
|
|
|
|
|
heatmap_data_list = []
|
|
|
|
|
for trade in trades:
|
|
|
|
|
@ -281,7 +276,7 @@ def generate_trading_report_image(runner_ids: list = None, batch_id: str = None,
|
|
|
|
|
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
|
|
|
|
|
# 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')
|
|
|
|
|
@ -294,15 +289,15 @@ def generate_trading_report_image(runner_ids: list = None, batch_id: str = None,
|
|
|
|
|
transform=axs[1, 0].transAxes)
|
|
|
|
|
axs[1, 0].set_title('Heatmap of Profits (based on Exit time)')
|
|
|
|
|
|
|
|
|
|
# Plot 9: Profit/Loss Distribution Histogram
|
|
|
|
|
# Plot 6: Profit/Loss Distribution Histogram
|
|
|
|
|
sns.histplot(profits, bins=30, ax=axs[1, 1], kde=True, color='skyblue')
|
|
|
|
|
axs[1, 1].set_title('Profit/Loss Distribution')
|
|
|
|
|
axs[1, 1].set_xlabel('Profit/Loss')
|
|
|
|
|
axs[1, 1].set_ylabel('Frequency')
|
|
|
|
|
|
|
|
|
|
# Plot 5
|
|
|
|
|
# - pro 1 den: Position Size Distribution
|
|
|
|
|
# - pro vice dnu: Trade Duration vs. Profit/Loss
|
|
|
|
|
# Plot 7
|
|
|
|
|
# - for 1 den: Position Size Distribution
|
|
|
|
|
# - for more days: Trade Duration vs. Profit/Loss
|
|
|
|
|
if len(runner_ids) == 1:
|
|
|
|
|
|
|
|
|
|
sizes = [trade.size for trade in closed_trades if trade.size is not None]
|
|
|
|
|
@ -331,7 +326,7 @@ def generate_trading_report_image(runner_ids: list = None, batch_id: str = None,
|
|
|
|
|
##trade_volumes.append(trade.size) # or any other measure of trade size
|
|
|
|
|
trade_types.append('Long' if trade.direction == TradeDirection.LONG else 'Short')
|
|
|
|
|
|
|
|
|
|
# Plot 8: Trade Duration vs. Profit/Loss
|
|
|
|
|
# Trade Duration vs. Profit/Loss
|
|
|
|
|
scatter_data = pd.DataFrame({
|
|
|
|
|
'Duration': trade_durations,
|
|
|
|
|
'Profit': trade_profits,
|
|
|
|
|
@ -345,7 +340,91 @@ def generate_trading_report_image(runner_ids: list = None, batch_id: str = None,
|
|
|
|
|
axs[1, 2].set_ylabel('Profit/Loss')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Plot 6: Daily Relative Profit Chart
|
|
|
|
|
#Plot 8 Cumulative profit - bud 1 den nebo vice dni + pridame pod to vyvoj ceny
|
|
|
|
|
# Extract the closing prices and times
|
|
|
|
|
closing_prices = bars['close']
|
|
|
|
|
#times = bars['time'] # Assuming this is a list of pandas Timestamp objects
|
|
|
|
|
times = pd.to_datetime(bars['time']) # Ensure this is a Pandas datetime series
|
|
|
|
|
# # Plot the closing prices over time
|
|
|
|
|
# axs[0, 4].plot(times, closing_prices, color='blue')
|
|
|
|
|
# axs[0, 4].tick_params(axis='x', rotation=45) # Rotate date labels if necessar
|
|
|
|
|
# axs[0, 4].xaxis.set_major_formatter(mdates.DateFormatter('%H', tz=zoneNY))
|
|
|
|
|
|
|
|
|
|
if len(runner_ids)== 1:
|
|
|
|
|
if cumulative_profits.size > 0:
|
|
|
|
|
# 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)
|
|
|
|
|
|
|
|
|
|
#Plot Cumulative Profit Over Time with Max Profit Point on the primary y-axis
|
|
|
|
|
# Create a secondary y-axis for the closing prices
|
|
|
|
|
ax2 = axs[1, 3].twinx()
|
|
|
|
|
ax2.plot(times, closing_prices, label='Closing Price', color='orange')
|
|
|
|
|
ax2.set_ylabel('Closing Price', color='orange')
|
|
|
|
|
ax2.tick_params(axis='y', labelcolor='orange')
|
|
|
|
|
|
|
|
|
|
# Set the limits for the x-axis to cover the full range of 'times'
|
|
|
|
|
axs[1, 3].set_xlim(times.min(), times.max())
|
|
|
|
|
sns.lineplot(x=exit_times, y=cumulative_profits, ax=axs[1, 3], color='limegreen')
|
|
|
|
|
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')
|
|
|
|
|
axs[1, 3].set_xlabel('Time')
|
|
|
|
|
axs[1, 3].set_ylabel('Cumulative Profit', color='limegreen')
|
|
|
|
|
axs[1, 3].tick_params(axis='y', labelcolor='limegreen')
|
|
|
|
|
axs[1, 3].xaxis.set_major_formatter(mdates.DateFormatter('%H', tz=zoneNY))
|
|
|
|
|
# Add legends to the plot
|
|
|
|
|
# lines, labels = axs[1, 3].get_legend_handles_labels()
|
|
|
|
|
# lines2, labels2 = ax2.get_legend_handles_labels()
|
|
|
|
|
# axs[1, 3].legend(lines + lines2, labels + labels2, loc='upper left')
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
# # Set the limits for the x-axis to cover the full range of 'times'
|
|
|
|
|
# axs[1, 3].set_xlim(times.min(), times.max())
|
|
|
|
|
|
|
|
|
|
sorted_trades = sorted([trade for trade in trades if trade.status == TradeStatus.CLOSED],
|
|
|
|
|
key=lambda x: x.exit_time)
|
|
|
|
|
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]
|
|
|
|
|
|
|
|
|
|
# Create a secondary y-axis for the closing prices
|
|
|
|
|
ax2 = axs[1, 3].twinx()
|
|
|
|
|
ax2.plot(times, closing_prices, label='Closing Price', color='orange')
|
|
|
|
|
ax2.set_ylabel('Closing Price', color='orange')
|
|
|
|
|
ax2.tick_params(axis='y', labelcolor='orange')
|
|
|
|
|
|
|
|
|
|
axs[1, 3].set_xlim(times.min(), times.max())
|
|
|
|
|
# Plot Cumulative Profit Over Time on the primary y-axis
|
|
|
|
|
axs[1, 3].plot(exit_times_sorted, cumulative_profits_sorted, label='Cumulative Profit', color='blue')
|
|
|
|
|
axs[1, 3].set_xlabel('Time')
|
|
|
|
|
axs[1, 3].set_ylabel('Cumulative Profit', color='blue')
|
|
|
|
|
axs[1, 3].tick_params(axis='y', labelcolor='blue')
|
|
|
|
|
|
|
|
|
|
# Format dates on the x-axis
|
|
|
|
|
axs[1, 3].xaxis.set_major_formatter(mdates.DateFormatter('%d.%m.', tz=zoneNY))
|
|
|
|
|
axs[1, 3].tick_params(axis='x', rotation=45) # Rotate date labels if necessary
|
|
|
|
|
|
|
|
|
|
# Set the title
|
|
|
|
|
axs[1, 3].set_title('Cumulative Profit and Closing Price Over Time')
|
|
|
|
|
|
|
|
|
|
# Add legends to the plot
|
|
|
|
|
# axs[1, 3].legend(loc='upper left')
|
|
|
|
|
# ax2.legend(loc='upper right')
|
|
|
|
|
|
|
|
|
|
# Plot 9
|
|
|
|
|
# - for 1 day: Daily Relative Profit Chart
|
|
|
|
|
# - for more days: Heatmap of Profits (based on Entry time)
|
|
|
|
|
if len(runner_ids) == 1:
|
|
|
|
|
daily_rel_profits = [trade.rel_profit for trade in closed_trades if trade.rel_profit is not None]
|
|
|
|
|
sns.lineplot(x=range(len(daily_rel_profits)), y=daily_rel_profits, ax=axs[2, 0])
|
|
|
|
|
@ -365,13 +444,13 @@ def generate_trading_report_image(runner_ids: list = None, batch_id: str = None,
|
|
|
|
|
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
|
|
|
|
|
# Heatmap of Profits
|
|
|
|
|
sns.heatmap(heatmap_pivot, cmap='viridis', ax=axs[2, 0])
|
|
|
|
|
axs[2, 0].set_title('Heatmap of Profits (based on Entry time)')
|
|
|
|
|
axs[2, 0].set_xlabel('Hour of Day')
|
|
|
|
|
axs[2, 0].set_ylabel('Day')
|
|
|
|
|
|
|
|
|
|
# Plot 8: Profits Based on Hour of the Day (Entry)
|
|
|
|
|
# Plot 10: Profits Based on Hour of the Day (Entry)
|
|
|
|
|
entry_hours = [trade.entry_time.hour for trade in closed_trades if trade.entry_time is not None]
|
|
|
|
|
profits_by_hour = {}
|
|
|
|
|
for hour, trade in zip(entry_hours, closed_trades):
|
|
|
|
|
@ -396,7 +475,7 @@ def generate_trading_report_image(runner_ids: list = None, batch_id: str = None,
|
|
|
|
|
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
|
|
|
|
|
# Plot 11: 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]
|
|
|
|
|
profits_by_hour = {}
|
|
|
|
|
for hour, trade in zip(exit_hours, closed_trades):
|
|
|
|
|
@ -421,7 +500,7 @@ def generate_trading_report_image(runner_ids: list = None, batch_id: str = None,
|
|
|
|
|
transform=axs[2, 2].transAxes)
|
|
|
|
|
axs[2, 2].set_title('Profits by Hour of Day (Exit)')
|
|
|
|
|
|
|
|
|
|
# Calculate profits by day of the week
|
|
|
|
|
# Plot 12: 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
|
|
|
|
|
|
|
|
|
|
for trade in trades:
|
|
|
|
|
@ -459,7 +538,7 @@ def generate_trading_report_image(runner_ids: list = None, batch_id: str = None,
|
|
|
|
|
# Example usage
|
|
|
|
|
# trades = [list of Trade objects]
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
id_list = ["c3e31cb5-ddf9-467e-a932-2118f6844355"]
|
|
|
|
|
generate_trading_report_image(runner_ids=id_list)
|
|
|
|
|
# batch_id = "90973e57"
|
|
|
|
|
# generate_trading_report_image(batch_id=batch_id)
|
|
|
|
|
# id_list = ["e8938b2e-8462-441a-8a82-d823c6a025cb"]
|
|
|
|
|
# generate_trading_report_image(runner_ids=id_list)
|
|
|
|
|
batch_id = "90973e57"
|
|
|
|
|
generate_trading_report_image(batch_id=batch_id)
|
|
|
|
|
|