def recov_date(self, return_date=False): """Drawdown recovery date. Date at which `self` recovered to previous high-water mark. Parameters ---------- return_date : bool, default False If True, return a `datetime.date` object. If False, return a Pandas Timestamp object. Returns ------- {datetime.date, pandas._libs.tslib.Timestamp, pd.NaT} Returns NaT if recovery has not occured. """ dd = self.drawdown_idx() # False beginning on trough date and all later dates. mask = nancumprod(dd != nanmin(dd)).astype(bool) res = dd.mask(mask) == 0 # If `res` is all False (recovery has not occured), # .idxmax() will return `res.index[0]`. if not res.any(): recov = pd.NaT else: recov = res.idxmax() if return_date: return recov.date() return recov
def max_drawdown(self): """Most negative drawdown derived from drawdown index. The largest difference between a high-water point and a subsequent low. A portfolio may also be said to be in a position of drawdown from a decline from a high-water mark until a new high-water mark is reached. [Source: CFA Institute] Returns ------- float """ return nanmin(self.drawdown_idx())
def drawdown_start(self, return_date=False): """The date of the peak at which most severe drawdown began. Parameters ---------- return_date : bool, default False If True, return a `datetime.date` object. If False, return a Pandas Timestamp object. Returns ------- datetime.date or pandas._libs.tslib.Timestamp """ # Thank you @cᴏʟᴅsᴘᴇᴇᴅ # https://stackoverflow.com/a/47892766/7954504 dd = self.drawdown_idx() mask = nancumsum(dd == nanmin(dd.min)).astype(bool) start = dd.mask(mask)[::-1].idxmax() if return_date: return start.date() return start