def gain_to_loss_ratio(self): """Gain-to-loss ratio, ratio of positive to negative returns. Formula: (n pos. / n neg.) * (avg. up-month return / avg. down-month return) [Source: CFA Institute] Returns ------- float """ gt = self > 0 lt = self < 0 return (nansum(gt) / nansum(lt)) * (self[gt].mean() / self[lt].mean())
def semi_stdev(self, threshold=0., ddof=0, freq=None): """Semi-standard deviation; stdev of downside returns. It is designed to address that fact that plain standard deviation penalizes "upside volatility."" Formula: `sqrt( sum([min(self - thresh, 0] **2 ) / (n - ddof) )` Also known as: downside deviation. Parameters ---------- threshold : {float, TSeries, pd.Series}, default 0. While zero is the default, it is also customary to use a "minimum acceptable return" (MAR) or a risk-free rate. Note: this is assumed to be a *periodic*, not necessarily annualized, return. ddof : int, default 0 Degrees of freedom, passed to pd.Series.std(). freq : str or None, default None A frequency string used to create an annualization factor. If None, `self.freq` will be used. If that is also None, a frequency will be inferred. If none can be inferred, an exception is raised. It may be any frequency string or anchored offset string recognized by Pandas, such as 'D', '5D', 'Q', 'Q-DEC', or 'BQS-APR'. Returns ------- float """ if freq is None: freq = self._try_get_freq() if freq is None: raise FrequencyError(msg) n = self.count() - ddof ss = (nansum(np.minimum(self - threshold, 0.)**2)**0.5) / n return ss * freq**0.5