Source code for tradeexecutor.analysis.timemap

"""Break strategy performance by time

- Hour of the day

- Day of the week

"""
from typing import Iterable

import plotly.express as px
import plotly.graph_objects as go

from tradeexecutor.state.position import TradingPosition

DEFAULT_COLOUR_SCHEME = {}

[docs]class ScoringMethod: realised_profitability = "realised_profitability" success_rate = "success_rate" failure_rate = "failure_rate"
CHART_TITLES = { ScoringMethod.realised_profitability: "Realised profitability per opening hour of a position", ScoringMethod.success_rate: "Number of profitable positions per opening hour", ScoringMethod.failure_rate: "Number of unprofitable positions per opening hour", } COLOUR_SCHEHEM_NAMING = { ScoringMethod.success_rate: "Positions", ScoringMethod.failure_rate: "Positions (neg)", ScoringMethod.realised_profitability: "Profitability %", }
[docs]def visualise_weekly_time_heatmap( positions: Iterable[TradingPosition], method: ScoringMethod = ScoringMethod.success_rate, color_continuous_scale: str | None = None, # Reversed, blue = best height=600, ) -> go.Figure: """Create a heatmap of which hours/days are best for trading. - Figyre out best trading hours - Mostly useful for strategies that trade 1h or more frequently :param positions: Any trading positions to consider. We will filter based on method. :param method: Which kind of heatmap to draw. :param color_continuous_scale: The color scheme of the heatmap. :return: Plotly heatmap figure """ # Initialise the grid to 0 values weekday_names = [ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" ] if method == ScoringMethod.realised_profitability: initial_value = 1 else: initial_value = 0 data = {} for day in range(7): data[day] = [initial_value] * 24 # Go through positions and add them a score on the timemap based on the position opening for p in positions: opened_at = p.opened_at weekday = opened_at.weekday() hour = opened_at.hour profit = p.get_unrealised_and_realised_profit_percent() match method: case ScoringMethod.success_rate: if profit > 0: data[weekday][hour] += 1 case ScoringMethod.failure_rate: if profit < 0: data[weekday][hour] -= 1 case ScoringMethod.realised_profitability: # Cumulative profifability for this day data[weekday][hour] *= (1+profit) matrix = [v for v in data.values()] # Normalise -100% to 100% if method == ScoringMethod.realised_profitability: for day in range(7): for hour in range(24): matrix[day][hour] = matrix[day][hour] * 100 - 100 print(matrix) # https://plotly.com/python/heatmaps/ fig = px.imshow( matrix, labels=dict(x="Hour (UTC)", y="Day of week", color=COLOUR_SCHEHEM_NAMING.get(method)), y=weekday_names, x=[f"{h:02d}:00" for h in range(24)], height=height, color_continuous_scale=color_continuous_scale, ) fig.update_xaxes(side="top") fig.update_layout( title=CHART_TITLES.get(method) ) return fig