def recovered_rate(self, group_by: tp.GroupByLike = None, wrap_kwargs: tp.KwargsLike = None) -> tp.MaybeSeries: """Rate of recovered drawdowns.""" recovered_count = to_1d(self.recovered.count(group_by=group_by), raw=True) total_count = to_1d(self.count(group_by=group_by), raw=True) wrap_kwargs = merge_dicts(dict(name_or_index='recovered_rate'), wrap_kwargs) return self.wrapper.wrap_reduced(recovered_count / total_count, group_by=group_by, **wrap_kwargs)
def active_rate(self, group_by=None, **kwargs): """Rate of recovered drawdowns.""" active_count = to_1d(self.active.count(group_by=group_by), raw=True) total_count = to_1d(self.count(group_by=group_by), raw=True) return self.wrapper.wrap_reduced(active_count / total_count, group_by=group_by, **kwargs)
def short_rate(self, group_by=None, **kwargs): """Rate of short trades.""" short_count = to_1d(self.short.count(group_by=group_by), raw=True) total_count = to_1d(self.count(group_by=group_by), raw=True) return self.wrapper.wrap_reduced(short_count / total_count, group_by=group_by, **kwargs)
def long_rate(self, group_by=None, **kwargs): """Rate of long trades.""" long_count = to_1d(self.long.count(group_by=group_by), raw=True) total_count = to_1d(self.count(group_by=group_by), raw=True) return self.wrapper.wrap_reduced(long_count / total_count, group_by=group_by, **kwargs)
def closed_rate(self, group_by=None, **kwargs): """Rate of closed trades.""" closed_count = to_1d(self.closed.count(group_by=group_by), raw=True) total_count = to_1d(self.count(group_by=group_by), raw=True) return self.wrapper.wrap_reduced(closed_count / total_count, group_by=group_by, **kwargs)
def open_rate(self, group_by=None, **kwargs): """Rate of open trades.""" open_count = to_1d(self.open.count(group_by=group_by), raw=True) total_count = to_1d(self.count(group_by=group_by), raw=True) return self.wrapper.wrap_reduced(open_count / total_count, group_by=group_by, **kwargs)
def sqn(self, group_by=None, **kwargs): """System Quality Number (SQN).""" count = to_1d(self.count(group_by=group_by), raw=True) pnl_mean = to_1d(self.pnl.mean(group_by=group_by), raw=True) pnl_std = to_1d(self.pnl.std(group_by=group_by), raw=True) sqn = np.sqrt(count) * pnl_mean / pnl_std return self.wrapper.wrap_reduced(sqn, group_by=group_by, **kwargs)
def win_rate(self, group_by=None, **kwargs): """Rate of profitable events.""" win_count = to_1d(self.winning.count(group_by=group_by), raw=True) total_count = to_1d(self.count(group_by=group_by), raw=True) return self.wrapper.wrap_reduced(win_count / total_count, group_by=group_by, **kwargs)
def buy_rate(self, group_by=None, **kwargs): """Rate of buy operations.""" buy_count = to_1d(self.buy.count(group_by=group_by), raw=True) total_count = to_1d(self.count(group_by=group_by), raw=True) return self.wrapper.wrap_reduced(buy_count / total_count, group_by=group_by, **kwargs)
def sqn(self): """System Quality Number (SQN).""" count = to_1d(self.count, raw=True) pnl_mean = to_1d(self.pnl.mean(), raw=True) pnl_std = to_1d(self.pnl.std(), raw=True) sqn = np.sqrt(count) * pnl_mean / pnl_std return self.wrapper.wrap_reduced(sqn)
def win_rate(self): """Rate of profitable events.""" winning_count = to_1d(self.winning.count, raw=True) count = to_1d(self.count, raw=True) win_rate = winning_count / count return self.wrapper.wrap_reduced(win_rate)
def sell_rate(self, group_by=None, **kwargs): """Rate of sell operations.""" sell_count = to_1d(self.sell.count(group_by=group_by), raw=True) total_count = to_1d(self.count(group_by=group_by), raw=True) return self.wrapper.wrap_reduced(sell_count / total_count, group_by=group_by, **kwargs)
def loss_rate(self, group_by=None, wrap_kwargs=None): """Rate of losing trades.""" loss_count = to_1d(self.losing.count(group_by=group_by), raw=True) total_count = to_1d(self.count(group_by=group_by), raw=True) wrap_kwargs = merge_dicts(dict(name_or_index='loss_rate'), wrap_kwargs) return self.wrapper.wrap_reduced(loss_count / total_count, group_by=group_by, **wrap_kwargs)
def sqn(self, group_by=None, wrap_kwargs=None): """System Quality Number (SQN).""" count = to_1d(self.count(group_by=group_by), raw=True) pnl_mean = to_1d(self.pnl.mean(group_by=group_by), raw=True) pnl_std = to_1d(self.pnl.std(group_by=group_by), raw=True) sqn = np.sqrt(count) * pnl_mean / pnl_std wrap_kwargs = merge_dicts(dict(name_or_index='sqn'), wrap_kwargs) return self.wrapper.wrap_reduced(sqn, group_by=group_by, **wrap_kwargs)
def open_rate(self, group_by=None, wrap_kwargs=None): """Rate of open trades.""" open_count = to_1d(self.open.count(group_by=group_by), raw=True) total_count = to_1d(self.count(group_by=group_by), raw=True) wrap_kwargs = merge_dicts(dict(name_or_index='open_rate'), wrap_kwargs) return self.wrapper.wrap_reduced(open_count / total_count, group_by=group_by, **wrap_kwargs)
def sell_rate(self, group_by=None, wrap_kwargs=None): """Rate of sell operations.""" sell_count = to_1d(self.sell.count(group_by=group_by), raw=True) total_count = to_1d(self.count(group_by=group_by), raw=True) wrap_kwargs = merge_dicts(dict(name_or_index='sell_rate'), wrap_kwargs) return self.wrapper.wrap_reduced(sell_count / total_count, group_by=group_by, **wrap_kwargs)
def common_sense_ratio(self, wrap_kwargs: tp.KwargsLike = None ) -> tp.MaybeSeries: """Common Sense Ratio.""" result = to_1d(self.tail_ratio(), raw=True) * (1 + to_1d(self.annualized(), raw=True)) wrap_kwargs = merge_dicts(dict(name_or_index='common_sense_ratio'), wrap_kwargs) return self.wrapper.wrap_reduced(result, **wrap_kwargs)
def win_rate(self, group_by=None, columns=None, **kwargs): """Rate of profitable events.""" win_count = to_1d(self.winning.count(group_by=group_by), raw=True) total_count = to_1d(self.count(group_by=group_by), raw=True) columns = self.grouper.get_new_index(group_by=group_by, new_index=columns) return self.wrapper.wrap_reduced(win_count / total_count, columns=columns, **kwargs)
def active_rate(self, group_by=None, wrap_kwargs=None): """Rate of recovered drawdowns.""" active_count = to_1d(self.active.count(group_by=group_by), raw=True) total_count = to_1d(self.count(group_by=group_by), raw=True) wrap_kwargs = merge_dicts(dict(name_or_index='active_rate'), wrap_kwargs) return self.wrapper.wrap_reduced(active_count / total_count, group_by=group_by, **wrap_kwargs)
def sqn(self, group_by=None, columns=None, **kwargs): """System Quality Number (SQN).""" count = to_1d(self.count(group_by=group_by), raw=True) pnl_mean = to_1d(self.pnl.mean(group_by=group_by), raw=True) pnl_std = to_1d(self.pnl.std(group_by=group_by), raw=True) sqn = np.sqrt(count) * pnl_mean / pnl_std columns = self.grouper.get_new_index(group_by=group_by, new_index=columns) return self.wrapper.wrap_reduced(sqn, columns=columns, **kwargs)
def closed_rate(self, group_by=None, wrap_kwargs=None): """Rate of closed trades.""" closed_count = to_1d(self.closed.count(group_by=group_by), raw=True) total_count = to_1d(self.count(group_by=group_by), raw=True) wrap_kwargs = merge_dicts(dict(name_or_index='closed_rate'), wrap_kwargs) return self.wrapper.wrap_reduced(closed_count / total_count, group_by=group_by, **wrap_kwargs)
def closed_rate(self, group_by=None, columns=None, **kwargs): """Rate of closed events.""" closed_count = to_1d(self.closed.count(group_by=group_by), raw=True) total_count = to_1d(self.count(group_by=group_by), raw=True) columns = self.grouper.get_new_index(group_by=group_by, new_index=columns) return self.wrapper.wrap_reduced(closed_count / total_count, columns=columns, **kwargs)
def long_rate(self, group_by: tp.GroupByLike = None, wrap_kwargs: tp.KwargsLike = None) -> tp.MaybeSeries: """Rate of long trades.""" long_count = to_1d(self.long.count(group_by=group_by), raw=True) total_count = to_1d(self.count(group_by=group_by), raw=True) wrap_kwargs = merge_dicts(dict(name_or_index='long_rate'), wrap_kwargs) return self.wrapper.wrap_reduced(long_count / total_count, group_by=group_by, **wrap_kwargs)
def _col_idxs_meta(self, col_idxs): """Get metadata of column indices. Returns element indices and new column array. Automatically decides whether to use column range or column map.""" if self.is_sorted(): new_indices, new_col_arr = nb.col_range_select_nb(self.col_range, to_1d(col_idxs)) # faster else: new_indices, new_col_arr = nb.col_map_select_nb(self.col_map, to_1d(col_idxs)) return new_indices, new_col_arr
def buy_rate(self, group_by: tp.GroupByLike = None, wrap_kwargs: tp.KwargsLike = None) -> tp.MaybeSeries: """Rate of buy operations.""" buy_count = to_1d(self.buy.count(group_by=group_by), raw=True) total_count = to_1d(self.count(group_by=group_by), raw=True) wrap_kwargs = merge_dicts(dict(name_or_index='buy_rate'), wrap_kwargs) return self.wrapper.wrap_reduced(buy_count / total_count, group_by=group_by, **wrap_kwargs)
def _col_idxs_records(self, col_idxs): """Get records corresponding to column indices. Returns new records array.""" if self.col_mapper.is_sorted(): new_records_arr = nb.record_col_range_select_nb( self.values, self.col_mapper.col_range, to_1d(col_idxs)) # faster else: new_records_arr = nb.record_col_map_select_nb( self.values, self.col_mapper.col_map, to_1d(col_idxs)) return new_records_arr
def profit_factor(self, group_by=None, **kwargs): """Profit factor.""" total_win = to_1d(self.winning.pnl.sum(group_by=group_by), raw=True) total_loss = to_1d(self.losing.pnl.sum(group_by=group_by), raw=True) # Otherwise columns with only wins or losses will become NaNs has_values = to_1d(self.count(group_by=group_by), raw=True) > 0 total_win[np.isnan(total_win) & has_values] = 0. total_loss[np.isnan(total_loss) & has_values] = 0. profit_factor = total_win / np.abs(total_loss) return self.wrapper.wrap_reduced(profit_factor, group_by=group_by, **kwargs)
def expectancy(self, group_by=None, **kwargs): """Average profitability.""" win_rate = to_1d(self.win_rate(group_by=group_by), raw=True) avg_win = to_1d(self.winning.pnl.mean(group_by=group_by), raw=True) avg_loss = to_1d(self.losing.pnl.mean(group_by=group_by), raw=True) # Otherwise columns with only wins or losses will become NaNs has_values = to_1d(self.count(group_by=group_by), raw=True) > 0 avg_win[np.isnan(avg_win) & has_values] = 0. avg_loss[np.isnan(avg_loss) & has_values] = 0. expectancy = win_rate * avg_win - (1 - win_rate) * np.abs(avg_loss) return self.wrapper.wrap_reduced(expectancy, group_by=group_by, **kwargs)
def describe(self, percentiles=None, ddof=1, **kwargs): """Return statistics by column.""" if percentiles is not None: percentiles = to_1d(percentiles, raw=True) else: percentiles = np.array([0.25, 0.5, 0.75]) percentiles = percentiles.tolist() if 0.5 not in percentiles: percentiles.append(0.5) percentiles = np.unique(percentiles) perc_formatted = pd.io.formats.format.format_percentiles(percentiles) index = pd.Index( ['count', 'mean', 'std', 'min', *perc_formatted, 'max']) kwargs = merge_dicts(dict(wrap_kwargs=dict(name_or_index=index)), kwargs) out = self.reduce(generic_nb.describe_reduce_nb, percentiles, ddof, to_array=True, to_idx=False, **kwargs) if isinstance(out, pd.DataFrame): out.loc['count'].fillna(0., inplace=True) else: if np.isnan(out.loc['count']): out.loc['count'] = 0. return out
def deflated_sharpe_ratio( self, risk_free: float = 0., var_sharpe: tp.Optional[float] = None, nb_trials: tp.Optional[int] = None, ddof: int = 0, bias: bool = True, wrap_kwargs: tp.KwargsLike = None) -> tp.MaybeSeries: """Deflated Sharpe Ratio (DSR). Expresses the chance that the advertized strategy has a positive Sharpe ratio. If `var_sharpe` is None, is calculated based on all columns. If `nb_trials` is None, is set to the number of columns.""" sharpe_ratio = to_1d(self.sharpe_ratio(risk_free=risk_free), raw=True) if var_sharpe is None: var_sharpe = np.var(sharpe_ratio, ddof=ddof) if nb_trials is None: nb_trials = self.wrapper.shape_2d[1] returns = to_2d(self._obj, raw=True) nanmask = np.isnan(returns) if nanmask.any(): returns = returns.copy() returns[nanmask] = 0. result = metrics.deflated_sharpe_ratio( est_sharpe=sharpe_ratio / np.sqrt(self.ann_factor), var_sharpe=var_sharpe / self.ann_factor, nb_trials=nb_trials, backtest_horizon=self.wrapper.shape_2d[0], skew=skew(returns, axis=0, bias=bias), kurtosis=kurtosis(returns, axis=0, bias=bias)) wrap_kwargs = merge_dicts(dict(name_or_index='deflated_sharpe_ratio'), wrap_kwargs) return self.wrapper.wrap_reduced(result, **wrap_kwargs)