def plot(self, figsize: Tuple[int, int] = (15, 8), date_range: Optional[Union[Tuple[str, str], Tuple[np.datetime64, np.datetime64]]] = None, sampling_frequency: str = None, title: str = 'Price / Volume') -> None: ''' Plot a candlestick or line plot depending on whether we have ohlc data or just close prices Args: figsize: Size of the figure (default (15,8)) date_range: A tuple of strings or numpy datetimes for plotting a smaller sample of the data, e.g. ("2018-01-01", "2018-01-06") sampling_frequency: Downsample before plotting. See pandas frequency strings for possible values. title: Title of the graph, default "Price / Volume" ''' if date_range and isinstance(date_range[0], str): date_range = strtup2date(date_range) data: Union[TradeBarSeries, TimeSeries] if self.has_ohlc(): data = TradeBarSeries('price', self.timestamps, self.o, self.h, self.l, self.c, self.v, self.vwap) else: data = TimeSeries('price', self.timestamps, self.c) subplot = Subplot(data) plot = Plot([subplot], figsize=figsize, date_range=date_range, sampling_frequency=sampling_frequency, title=title) plot.draw()
def plot_2d(self, x: str, y: str = 'all', plot_type: str = 'line', figsize: Tuple[float, float] = (15, 8), marker: str = 'X', marker_size: int = 50, marker_color: str = 'r', xlim: Tuple[float, float] = None, hspace: float = None) -> None: """Creates a 2D plot of the optimization output for plotting 1 parameter and costs. Args: x: Name of the parameter to plot on the x axis, corresponding to the same name in the generator. y: Can be one of: "cost" The name of another cost variable corresponding to the output from the cost function "all", which creates a subplot for cost plus all other costs plot_type: line or scatter (default line) figsize: Figure size marker: Adds a marker to each point in x, y to show the actual data used for interpolation. You can set this to None to turn markers off. hspace: Vertical space between subplots """ if len(self.experiments) == 0: return if not has_display(): return # Get rid of nans since matplotlib does not like them experiments = [experiment for experiment in self.experiments if experiment.valid()] if xlim: experiments = [experiment for experiment in experiments if experiment.suggestion[x] >= xlim[0] and experiment.suggestion[x] <= xlim[1]] xvalues = [experiment.suggestion[x] for experiment in experiments] yvalues = [] if y == 'all': yvalues.append(('cost', np.array([experiment.cost for experiment in experiments]))) other_cost_keys = experiments[0].other_costs.keys() for key in other_cost_keys: yvalues.append((key, np.array([experiment.other_costs[key] for experiment in experiments]))) elif y == 'cost': yvalues.append(('cost', np.array([experiment.cost for experiment in experiments]))) else: yvalues.append((y, np.array([experiment.other_costs[y] for experiment in experiments]))) xarray = np.array(xvalues) x_sort_indices = np.argsort(xarray) xarray = xarray[x_sort_indices] subplots = [] for tup in yvalues: name = tup[0] yarray = tup[1] yarray = yarray[x_sort_indices] disp = LinePlotAttributes(marker=marker, marker_size=marker_size, marker_color=marker_color) subplots.append( Subplot(data_list=[XYData(name, xarray, yarray, display_attributes=disp)], xlabel=x, ylabel=name, xlim=xlim)) plot = Plot(subplots, figsize=figsize, title='Optimizer 1D Test') plot.draw()
def plot_return_metrics( metrics: Mapping[str, Any], title: str = None) -> Optional[Tuple[mpl_fig.Figure, mpl.axes.Axes]]: ''' Plot equity, rolling drawdowns and and a boxplot of annual returns given the output of compute_return_metrics. ''' timestamps = metrics['timestamps'] equity = metrics['equity'] equity = TimeSeries('equity', timestamps=timestamps, values=equity) mdd_date, mdd_start = metrics['mdd_start'], metrics['mdd_date'] mdd_date_3yr, mdd_start_3yr = metrics['mdd_start_3yr'], metrics[ 'mdd_date_3yr'] drawdown_lines = [ DateLine(name='max dd', date=mdd_start, color='red'), DateLine(date=mdd_date, color='red'), DateLine(name='3y dd', date=mdd_start_3yr, color='orange'), DateLine(date=mdd_date_3yr, color='orange') ] equity_subplot = Subplot(equity, ylabel='Equity', height_ratio=0.6, log_y=True, y_tick_format='${x:,.0f}', date_lines=drawdown_lines, horizontal_lines=[ HorizontalLine(metrics['starting_equity'], color='black') ]) rolling_dd = TimeSeries('drawdowns', timestamps=metrics['rolling_dd'][0], values=metrics['rolling_dd'][1]) zero_line = HorizontalLine(y=0, color='black') dd_subplot = Subplot(rolling_dd, ylabel='Drawdowns', height_ratio=0.2, date_lines=drawdown_lines, horizontal_lines=[zero_line]) years = metrics['bucketed_returns'][0] ann_rets = metrics['bucketed_returns'][1] ann_ret = BucketedValues('annual returns', bucket_names=years, bucket_values=ann_rets) ann_ret_subplot = Subplot(ann_ret, ylabel='Annual Returns', height_ratio=0.2, horizontal_lines=[zero_line]) plt = Plot([equity_subplot, dd_subplot, ann_ret_subplot], title=title) return plt.draw()
def plot(self, contract_groups: Sequence[ContractGroup] = None, primary_indicators: Sequence[str] = None, primary_indicators_dual_axis: Sequence[str] = None, secondary_indicators: Sequence[str] = None, secondary_indicators_dual_axis: Sequence[str] = None, indicator_properties: PlotPropertiesType = None, signals: Sequence[str] = None, signal_properties: PlotPropertiesType = None, pnl_columns: Sequence[str] = None, title: str = None, figsize: Tuple[int, int] = (20, 15), _date_range: DateRangeType = None, date_format: str = None, sampling_frequency: str = None, trade_marker_properties: PlotPropertiesType = None, hspace: float = 0.15) -> None: ''' Plot indicators, signals, trades, position, pnl Args: contract_groups: Contract groups to plot or None (default) for all contract groups. primary indicators: List of indicators to plot in the main indicator section. Default None (plot everything) primary indicators: List of indicators to plot in the secondary indicator section. Default None (don't plot anything) indicator_properties: If set, we use the line color, line type indicated for the given indicators signals: Signals to plot. Default None (plot everything). plot_equity: If set, we plot the equity curve. Default is True title: Title of plot. Default None figsize: Figure size. Default (20, 15) date_range: Used to restrict the date range of the graph. Default None date_format: Date format for tick labels on x axis. If set to None (default), will be selected based on date range. See matplotlib date format strings sampling_frequency: Downsampling frequency. The graph may get too busy if you have too many bars of data, so you may want to downsample before plotting. See pandas frequency strings for possible values. Default None. trade_marker_properties: A dictionary of order reason code -> marker shape, marker size, marker color for plotting trades with different reason codes. By default we use the dictionary from the :obj:`ReasonCode` class hspace: Height (vertical) space between subplots. Default is 0.15 ''' date_range = strtup2date(_date_range) if contract_groups is None: contract_groups = self.contract_groups if isinstance(contract_groups, ContractGroup): contract_groups = [contract_groups] if pnl_columns is None: pnl_columns = ['equity'] for contract_group in contract_groups: primary_indicator_names = [ind_name for ind_name in self.indicator_values[contract_group].__dict__ if hasattr(self.indicator_values[contract_group], ind_name)] if primary_indicators: primary_indicator_names = list(set(primary_indicator_names).intersection(primary_indicators)) secondary_indicator_names: List[str] = [] if secondary_indicators: secondary_indicator_names = list(secondary_indicators) signal_names = [sig_name for sig_name in self.signals.keys() if hasattr(self.signal_values[contract_group], sig_name)] if signals: signal_names = list(set(signal_names).intersection(signals)) primary_indicator_list = _get_time_series_list(self.timestamps, primary_indicator_names, self.indicator_values[contract_group], indicator_properties) secondary_indicator_list = _get_time_series_list(self.timestamps, secondary_indicator_names, self.indicator_values[contract_group], indicator_properties) signal_list = _get_time_series_list(self.timestamps, signal_names, self.signal_values[contract_group], signal_properties) df_pnl_ = self.df_pnl(contract_group) pnl_list = [TimeSeries(pnl_column, timestamps=df_pnl_.timestamp.values, values=df_pnl_[pnl_column].values) for pnl_column in pnl_columns] trades = [trade for trade in self._trades if trade.order.contract.contract_group == contract_group] if trade_marker_properties: trade_sets = trade_sets_by_reason_code(trades, trade_marker_properties, remove_missing_properties=True) else: trade_sets = trade_sets_by_reason_code(trades) primary_indicator_subplot = Subplot( primary_indicator_list + trade_sets, # type: ignore # mypy does not allow adding heterogeneous lists secondary_y=primary_indicators_dual_axis, height_ratio=0.5, ylabel='Primary Indicators') if len(secondary_indicator_list): secondary_indicator_subplot = Subplot(secondary_indicator_list, secondary_y=secondary_indicators_dual_axis, height_ratio=0.5, ylabel='Secondary Indicators') signal_subplot = Subplot(signal_list, ylabel='Signals', height_ratio=0.167) pnl_subplot = Subplot(pnl_list, ylabel='Equity', height_ratio=0.167, log_y=True, y_tick_format='${x:,.0f}') position = df_pnl_.position.values disp_attribs = FilledLinePlotAttributes() pos_subplot = Subplot( [TimeSeries('position', timestamps=df_pnl_.timestamp, values=position, display_attributes=disp_attribs)], ylabel='Position', height_ratio=0.167) title_full = title if len(contract_groups) > 1: if title is None: title = '' title_full = f'{title} {contract_group.name}' plot_list = [] if len(primary_indicator_list): plot_list.append(primary_indicator_subplot) if len(secondary_indicator_list): plot_list.append(secondary_indicator_subplot) if len(signal_list): plot_list.append(signal_subplot) if len(position): plot_list.append(pos_subplot) if len(pnl_list): plot_list.append(pnl_subplot) if not len(plot_list): return plot = Plot(plot_list, figsize=figsize, date_range=date_range, date_format=date_format, sampling_frequency=sampling_frequency, title=title_full, hspace=hspace) plot.draw()
def plot(self, contract_groups=None, primary_indicators=None, primary_indicators_dual_axis=None, secondary_indicators=None, secondary_indicators_dual_axis=None, indicator_properties=None, signals=None, signal_properties=None, pnl_columns=None, title=None, figsize=(20, 15), date_range=None, date_format=None, sampling_frequency=None, trade_marker_properties=None, hspace=0.15): '''Plot indicators, signals, trades, position, pnl Args: contract_groups (list of :obj:`ContractGroup`, optional): Contract groups to plot or None (default) for all contract groups. primary indicators (list of str, optional): List of indicators to plot in the main indicator section. Default None (plot everything) primary indicators (list of str, optional): List of indicators to plot in the secondary indicator section. Default None (don't plot anything) indicator_properties (dict of str : dict, optional): If set, we use the line color, line type indicated for the given indicators signals (list of str, optional): Signals to plot. Default None (plot everything). plot_equity (bool, optional): If set, we plot the equity curve. Default is True title (list of str, optional): Title of plot. Default None figsize (tuple of int): Figure size. Default (20, 15) date_range (tuple of str or np.datetime64, optional): Used to restrict the date range of the graph. Default None date_format (str, optional): Date format for tick labels on x axis. If set to None (default), will be selected based on date range. See matplotlib date format strings sampling_frequency (str, optional): Downsampling frequency. The graph may get too busy if you have too many bars of data, in which case you may want to downsample before plotting. See pandas frequency strings for possible values. Default None. trade_marker_properties (dict of str : tuple, optional): A dictionary of order reason code -> marker shape, marker size, marker color for plotting trades with different reason codes. Default is None in which case the dictionary from the ReasonCode class is used hspace (float, optional): Height (vertical) space between subplots. Default is 0.15 ''' date_range = strtup2date(date_range) if contract_groups is None: contract_groups = self.contract_groups if isinstance(contract_groups, ContractGroup): contract_groups = [contract_groups] if pnl_columns is None: pnl_columns = ['equity'] for contract_group in contract_groups: primary_indicator_names = [ind_name for ind_name in self.indicator_values[contract_group].__dict__ \ if hasattr(self.indicator_values[contract_group], ind_name)] if primary_indicators: primary_indicator_names = list( set(primary_indicator_names).intersection( primary_indicators)) secondary_indicator_names = [] if secondary_indicators: secondary_indicator_names = secondary_indicators signal_names = [ sig_name for sig_name in self.signals.keys() if hasattr(self.signal_values[contract_group], sig_name) ] if signals: signal_names = list(set(signal_names).intersection(signals)) primary_indicator_list = _get_time_series_list( self.timestamps, primary_indicator_names, self.indicator_values[contract_group], indicator_properties) secondary_indicator_list = _get_time_series_list( self.timestamps, secondary_indicator_names, self.indicator_values[contract_group], indicator_properties) signal_list = _get_time_series_list( self.timestamps, signal_names, self.signal_values[contract_group], signal_properties) df_pnl_ = self.df_pnl(contract_group) pnl_list = [ TimeSeries(pnl_column, timestamps=df_pnl_.timestamp.values, values=df_pnl_[pnl_column].values) for pnl_column in pnl_columns ] trades = [ trade for trade in self._trades if trade.order.contract.contract_group == contract_group ] if trade_marker_properties: trade_sets = trade_sets_by_reason_code( trades, trade_marker_properties, remove_missing_properties=True) else: trade_sets = trade_sets_by_reason_code(trades) primary_indicator_subplot = Subplot( primary_indicator_list + trade_sets, secondary_y=primary_indicators_dual_axis, height_ratio=0.5, ylabel='Primary Indicators') if len(secondary_indicator_list): secondary_indicator_subplot = Subplot( secondary_indicator_list, secondary_y=secondary_indicators_dual_axis, height_ratio=0.5, ylabel='Secondary Indicators') signal_subplot = Subplot(signal_list, ylabel='Signals', height_ratio=0.167) pnl_subplot = Subplot(pnl_list, ylabel='Equity', height_ratio=0.167, log_y=True, y_tick_format='${x:,.0f}') position = df_pnl_.position.values pos_subplot = Subplot([ TimeSeries('position', timestamps=df_pnl_.timestamp, values=position, plot_type='filled_line') ], ylabel='Position', height_ratio=0.167) title_full = title if len(contract_groups) > 1: if title is None: title = '' title_full = f'{title} {contract_group.name}' plot_list = [] if len(primary_indicator_list): plot_list.append(primary_indicator_subplot) if len(secondary_indicator_list): plot_list.append(secondary_indicator_subplot) if len(signal_list): plot_list.append(signal_subplot) if len(position): plot_list.append(pos_subplot) if len(pnl_list): plot_list.append(pnl_subplot) if not len(plot_list): return plot = Plot(plot_list, figsize=figsize, date_range=date_range, date_format=date_format, sampling_frequency=sampling_frequency, title=title_full, hspace=hspace) plot.draw()
def plot_3d(self, x: str, y: str, z: str = 'all', plot_type: str = 'surface', figsize: Tuple[float, float] = (15, 15), interpolation: str = 'linear', cmap: str = 'viridis', marker: str = 'X', marker_size: int = 50, marker_color: str = 'r', xlim: Tuple[float, float] = None, ylim: Tuple[float, float] = None, hspace: float = None) -> None: """Creates a 3D plot of the optimization output for plotting 2 parameters and costs. Args: x: Name of the parameter to plot on the x axis, corresponding to the same name in the generator. y: Name of the parameter to plot on the y axis, corresponding to the same name in the generator. z: Can be one of: "cost" The name of another cost variable corresponding to the output from the cost function "all", which creates a subplot for cost plus all other costs plot_type: surface or contour (default surface) figsize: Figure size interpolation: Can be ‘linear’, ‘nearest’ or ‘cubic’ for plotting z points between the ones passed in. See scipy.interpolate.griddata for details cmap: Colormap to use (default viridis). See matplotlib colormap for details marker: Adds a marker to each point in x, y, z to show the actual data used for interpolation. You can set this to None to turn markers off. hspace: Vertical space between subplots """ if len(self.experiments) == 0: print('No experiments found') return if not has_display(): return # Get rid of nans since matplotlib does not like them experiments = [ experiment for experiment in self.experiments if experiment.valid() ] if not len(experiments): print('No valid experiments found') return if xlim: experiments = [ experiment for experiment in experiments if experiment.suggestion[x] >= xlim[0] and experiment.suggestion[x] <= xlim[1] ] if ylim: experiments = [ experiment for experiment in experiments if experiment.suggestion[y] >= ylim[0] and experiment.suggestion[y] <= ylim[1] ] xvalues = [experiment.suggestion[x] for experiment in experiments] yvalues = [experiment.suggestion[y] for experiment in experiments] zvalues = [] if z == 'all': zvalues.append( ('cost', np.array([experiment.cost for experiment in experiments]))) if len(experiments[0].other_costs): other_cost_keys = experiments[0].other_costs.keys() for key in other_cost_keys: zvalues.append((key, np.array([ experiment.other_costs[key] for experiment in experiments ]))) elif z == 'cost': zvalues.append( ('cost', np.array([experiment.cost for experiment in experiments]))) else: zvalues.append( (z, np.array([ experiment.other_costs[z] for experiment in experiments ]))) title: Optional[str] subplots = [] for tup in zvalues: name = tup[0] zarray = tup[1] if plot_type == 'contour': zlabel = None title = name else: zlabel = name title = None disp = SurfacePlotAttributes(marker=marker, marker_size=marker_size, marker_color=marker_color, interpolation=interpolation) subplots.append( Subplot(data_list=[ XYZData(name, xvalues, yvalues, zarray, display_attributes=disp) ], title=title, xlabel=x, ylabel=y, zlabel=zlabel, xlim=xlim, ylim=ylim)) plot = Plot(subplots, figsize=figsize, title='Optimizer 2D Test', hspace=hspace) plot.draw()