def create_returns_bar_chart(returns: QFSeries, frequency: Frequency = Frequency.YEARLY, title: str = None) -> BarChart: """ Constructs a new returns bar chart based on the returns specified. By default a new annual returns bar chart will be created. Parameters ---------- returns: QFSeries The returns series to use in the chart. frequency: Frequency frequency of the returns after aggregation title: optional title for the chart Returns -------- BarChart """ colors = Chart.get_axes_colors() # Calculate data. aggregate_returns = get_aggregate_returns(returns, frequency, multi_index=True) data_series = QFSeries(aggregate_returns.sort_index(ascending=True)) chart = BarChart(Orientation.Horizontal, align="center") chart.add_decorator(DataElementDecorator(data_series, key="data_element")) chart.add_decorator(BarValuesDecorator(data_series)) # Format the x-axis so that its labels are shown as a percentage. chart.add_decorator(AxesFormatterDecorator(x_major=PercentageFormatter())) # Format Y axis to make sure we have a tick for each year or 2 years if len(data_series) > 10: y_labels = data_series[data_series.index % 2 == 1].index else: y_labels = data_series.index chart.add_decorator( AxisTickLabelsDecorator(labels=y_labels, axis=Axis.Y, tick_values=y_labels)) # Add an average line. avg_line = VerticalLineDecorator(aggregate_returns.values.mean(), color=colors[1], key="avg_line", linestyle="--", alpha=0.8) chart.add_decorator(avg_line) # Add a legend. legend = LegendDecorator(key="legend_decorator") legend.add_entry(avg_line, "Mean") chart.add_decorator(legend) # Add a title. if title is None: title = str(frequency).capitalize() + " Returns" title = TitleDecorator(title, key="title_decorator") chart.add_decorator(title) chart.add_decorator(AxesLabelDecorator("Returns", "Year")) return chart
def create_dot_plot(series1: QFSeries, series2: QFSeries, x_label: str, y_label: str, start_x: float = None, end_x: float = None) -> LineChart: """Create a dot linechart. Parameters ----------- series1: QFSeries series2: QFSeries x_label: str y_label: str start_x: float end_x: float Returns -------- LineChart """ # Combine the series. combined = pd.concat([series1, series2], axis=1) combined_series = QFSeries(data=combined.iloc[:, 0].values, index=combined.iloc[:, 1].values) # Create a new line chart. line_chart = LineChart(start_x=start_x, end_x=end_x) line_chart.tick_fontweight = "bold" line_chart.tick_color = "black" # Add the data. data_element = DataElementDecorator(combined_series, marker="o") line_chart.add_decorator(data_element) # Add a title. title_decorator = TitleDecorator("US Beveridge Curve", key="title") line_chart.add_decorator(title_decorator) # Add axes labels. axes_label_decorator = AxesLabelDecorator(x_label=x_label, y_label=y_label) line_chart.add_decorator(axes_label_decorator) # Emphasise the last point. # This series has many NaNs, we want to retrieve the last non-NaN point. no_nans = combined_series.dropna() point_to_emphasise = (no_nans.index[len(no_nans) - 1], no_nans.values[len(no_nans) - 1]) point_emphasis_decorator = PointEmphasisDecorator(data_element, point_to_emphasise, color="#CC1414", decimal_points=1, label_format="") line_chart.add_decorator(point_emphasis_decorator) # Create a legend. legend_decorator = LegendDecorator() last_date = series1.dropna().index.max() legend_decorator.add_entry( point_emphasis_decorator, "Latest ({:g}, {:g}) [{}]".format(point_to_emphasise[0], point_to_emphasise[1], last_date.strftime("%b %y"))) line_chart.add_decorator(legend_decorator) return line_chart
def create_rolling_chart_using_benchmark(series: Union[QFSeries, List[QFSeries]], benchmark_series: QFSeries, func: RollingWindowFunction, func_name: str, window_size: int = 126, step: int = 20, oos_date: str = None) -> LineChart: """ Creates a new line chart and adds the rolling window for each of the specified series to it. The `func` function is fed data for each window and whatever it returns is added to the resulting rolled series. For example: .. code-block::python create_rolling_chart_using_benchmark([strategy1_tms, strategy2_tms], benchmark_tms lambda a, b: beta_and_alpha(PricesSeries(a), PricesSeries(b))[0], "Sharpe Ratio", oos_date=oos_date) The example above will return beta of every rolling window Parameters ---------- series: QFSeries, List[QFSeries] One or more series to apply the rolling window transformation on add to the resulting chart. benchmark_series: QFSeries benchmark for every series passed as a first argument func: RollingWindowFunction Called for each window. Takes two arguments (series_window, benchmark_window). Returns a float. func_name: str Used in the title to specify the function that was called. window_size: int step: int determines by how many steps we shift the rolling window oos_date: str only the OOS date of the first series in the list will be taken into account Returns ------- LineChart """ chart = LineChart() # Add a legend. legend = LegendDecorator() chart.add_decorator(legend) series_list = series if isinstance(series_list, QFSeries): series_list = [series_list] assert isinstance(series_list, list) for tms in series_list: rolling = tms.rolling_window_with_benchmark(benchmark_series, window_size, func, step=step) rolling_element = DataElementDecorator(rolling) chart.add_decorator(rolling_element) legend.add_entry(rolling_element, tms.name) # Add title chart.add_decorator( TitleDecorator("Rolling {} (window: {}, step: {}, BM: {}) ".format( func_name, window_size, step, benchmark_series.name))) # Add OOS line. new_oos_date = series_list[0].index.asof(pandas.to_datetime(oos_date)) line = VerticalLineDecorator(new_oos_date, color='orange', linestyle="dashed") chart.add_decorator(line) return chart
def create_skewness_chart(series: QFSeries, title: str = None) -> LineChart: """ Creates a new line chart showing the skewness of the distribution. It plots original series together with another series which contains sorted absolute value of the returns Parameters ---------- series ``QFSeries`` to plot on the chart. title title of the graph, specify ``None`` if you don't want the chart to show a title. Returns ------- The constructed ``LineChart``. """ original_price_series = series.to_prices(1) # Construct a series with returns sorted by their amplitude returns_series = series.to_simple_returns() abs_returns_series = returns_series.abs() returns_df = pd.concat([returns_series, abs_returns_series], axis=1, keys=['simple', 'abs']) sorted_returns_df = returns_df.sort_values(by='abs') skewness_series = SimpleReturnsSeries( index=returns_series.index, data=sorted_returns_df['simple'].values) skewed_price_series = skewness_series.to_prices(1) # Create a new Line Chart. line_chart = LineChart(start_x=series.index[0], rotate_x_axis=True) # Add original series to the chart original_series_element = DataElementDecorator(original_price_series) line_chart.add_decorator(original_series_element) skewed_series_element = DataElementDecorator(skewed_price_series) line_chart.add_decorator(skewed_series_element) # Add a point at the end point = (skewed_price_series.index[-1], skewed_price_series[-1]) point_emphasis = PointEmphasisDecorator(skewed_series_element, point, font_size=9) line_chart.add_decorator(point_emphasis) # Create a title. if title is not None: title_decorator = TitleDecorator(title, "title") line_chart.add_decorator(title_decorator) # Add a legend. legend_decorator = LegendDecorator(key='legend') legend_decorator.add_entry(original_series_element, 'Chronological returns') legend_decorator.add_entry(skewed_series_element, 'Returns sorted by magnitude') line_chart.add_decorator(legend_decorator) line_chart.add_decorator(AxesLabelDecorator(y_label="Profit/Loss")) return line_chart
def create_returns_similarity(strategy: QFSeries, benchmark: QFSeries, mean_normalization: bool = True, std_normalization: bool = True, frequency: Frequency = None) -> KDEChart: """ Creates a new returns similarity chart. The frequency is determined by the specified returns series. Parameters ---------- strategy The strategy series to plot. benchmark The benchmark series to plot. mean_normalization Whether to perform mean normalization on the series data. std_normalization Whether to perform variance normalization on the series data. frequency: Returns can be aggregated in to specific frequency before plotting the chart Returns ------- A newly created KDEChart instance. """ chart = KDEChart() colors = Chart.get_axes_colors() if frequency is not None: aggregate_strategy = get_aggregate_returns( strategy.to_simple_returns(), frequency) aggregate_benchmark = get_aggregate_returns( benchmark.to_simple_returns(), frequency) else: aggregate_strategy = strategy.to_simple_returns() aggregate_benchmark = benchmark.to_simple_returns() scaled_strategy = preprocessing.scale(aggregate_strategy, with_mean=mean_normalization, with_std=std_normalization) strategy_data_element = DataElementDecorator(scaled_strategy, bw="scott", shade=True, label=strategy.name, color=colors[0]) chart.add_decorator(strategy_data_element) scaled_benchmark = preprocessing.scale(aggregate_benchmark, with_mean=mean_normalization, with_std=std_normalization) benchmark_data_element = DataElementDecorator(scaled_benchmark, bw="scott", shade=True, label=benchmark.name, color=colors[1]) chart.add_decorator(benchmark_data_element) # Add a title. title = _get_title(mean_normalization, std_normalization, frequency) title_decorator = TitleDecorator(title, key="title") chart.add_decorator(title_decorator) chart.add_decorator(AxesLabelDecorator("Returns", "Similarity")) return chart
def __init__(self, strategy_tms, rotate_x_axis=False): super().__init__(rotate_x_axis=rotate_x_axis) self.add_decorator(DataElementDecorator(strategy_tms))
def historical_out_of_sample_performance_chart(self) -> LineChart: analysed_tms = self.model.input_data.analysed_tms frequency = self.model.input_data.frequency fund_cumulative_rets = analysed_tms.to_prices( initial_price=1.0, frequency=frequency) - 1 # type: PricesSeries fit_cumulative_rets = self.model.fitted_tms.to_prices( initial_price=1.0, frequency=frequency) - 1 # type: PricesSeries live_start_date = self.model.oos_start_date in_sample_fund_tms = fund_cumulative_rets.loc[:live_start_date] in_sample_fit_tms = fit_cumulative_rets.loc[:live_start_date] out_of_sample_fund_tms = fund_cumulative_rets.loc[live_start_date:] out_of_sample_fit_tms = fit_cumulative_rets.loc[live_start_date:] colors = Chart.get_axes_colors() in_sample_fund_data_elem = DataElementDecorator(in_sample_fund_tms, color=colors[0]) out_of_sample_fund_data_elem = DataElementDecorator( out_of_sample_fund_tms, color=colors[0]) in_sample_fit_data_elem = DataElementDecorator(in_sample_fit_tms, color=colors[1]) out_of_sample_fit_data_elem = DataElementDecorator( out_of_sample_fit_tms, color=colors[1]) legend_decorator = LegendDecorator( legend_placement=Location.LOWER_RIGHT) legend_decorator.add_entry(in_sample_fund_data_elem, self._get_security_name(analysed_tms.name)) legend_decorator.add_entry(in_sample_fit_data_elem, 'Fit') is_vs_oos_performance_chart = LineChart() is_vs_oos_performance_chart.add_decorator(in_sample_fund_data_elem) is_vs_oos_performance_chart.add_decorator(out_of_sample_fund_data_elem) is_vs_oos_performance_chart.add_decorator(in_sample_fit_data_elem) is_vs_oos_performance_chart.add_decorator(out_of_sample_fit_data_elem) is_vs_oos_performance_chart.add_decorator( AxesFormatterDecorator(y_major=PercentageFormatter())) is_vs_oos_performance_chart.add_decorator( AxesLabelDecorator(y_label="Cumulative return [%]")) is_vs_oos_performance_chart.add_decorator(legend_decorator) is_vs_oos_performance_chart.add_decorator( TextDecorator("In Sample ", x=DataCoordinate(live_start_date), y=AxesCoordinate(0.99), verticalalignment='top', horizontalalignment='right')) is_vs_oos_performance_chart.add_decorator( TextDecorator(" Out Of Sample", x=DataCoordinate(live_start_date), y=AxesCoordinate(0.99), verticalalignment='top', horizontalalignment='left')) last_date = fund_cumulative_rets.index[-1] is_vs_oos_performance_chart.add_decorator( VerticalSpanDecorator(x_min=live_start_date, x_max=last_date)) return is_vs_oos_performance_chart