1 votos

Implementación de la reducción máxima global y la duración máxima de la reducción en Python

Siguiendo el libro de E.P. Chan, estoy intentando calcular el máximo drawdown y la mayor duración del drawdown a partir de los rendimientos acumulados de la cartera. Él lo codifica en MATLAB, pero yo quería probar el mismo código en Python.

import pandas as pd

def drawdownCalculator(data):
    highwatermark = data.copy()
    highwatermark[:] = 0
    drawdown = data.copy()
    drawdown[:] = 0
    drawdownduration = data.copy()
    drawdownduration[:]=0
    t = 1
    while t <= len(data):
        highwatermark[t] = max(highwatermark[t-1], data[t])
        drawdown[t] = (1 + highwatermark[t])/(1 + data[t]) - 1
        if drawdown[t] == 0:
            drawdownduration[t] = 0
        else:
            drawdownduration[t] = drawdownduration[t-1] + 1
        t += 1
    return drawdown.max(), drawdownduration.max()
max_drawdown, max_drawdown_time = drawdownCalculator(cumulative_returns) #cumulative_returns is a Pandas series

Creía que lo tenía resuelto, pero me sale el siguiente error:

return self._engine.get_value(s, k, tz=getattr(series.dtype, "tz", None))
  File "pandas/_libs/index.pyx", line 80, in pandas._libs.index.IndexEngine.get_value
  File "pandas/_libs/index.pyx", line 88, in pandas._libs.index.IndexEngine.get_value
  File "pandas/_libs/index.pyx", line 131, in pandas._libs.index.IndexEngine.get_loc
  File "pandas/_libs/hashtable_class_helper.pxi", line 992, in pandas._libs.hashtable.Int64HashTable.get_item
  File "pandas/_libs/hashtable_class_helper.pxi", line 998, in pandas._libs.hashtable.Int64HashTable.get_item
KeyError: 0

Gracias de antemano

5voto

Greg Hurlman Puntos 10944

Supongo que tu Serie está indexada por una marca de tiempo, lo que explicaría por qué el acceso por un entero no funciona. Pero no puedo asegurarlo ya que no nos has mostrado ningún dato.

La buena noticia es que, de todos modos, no lo necesito. Aquí hay una forma más idiomática de calcular lo que quieres:

highwatermarks = cumulative_returns.cummax()

drawdowns = (1 + highwatermarks)/(1 + cumulative_returns) - 1

max_drawdown = max(drawdowns)

No hay una forma sencilla de calcular la duración con la notación de matriz. Afortunadamente, esta pregunta muestra cómo utilizar un acumulador exactamente para su escenario:

from itertools import accumulate

drawdown_times = (drawdowns > 0).astype(np.int64)

max_drawdown_time = max(accumulate(drawdown_times, lambda x,y: (x+y)*y))

También puede agrupar las duraciones consecutivas. No recomiendo este enfoque, pero lo incluiré para la posteridad:

max_drawdown_time = drawdown_times.groupby((drawdown_times != drawdown_times.shift()).cumsum()).cumsum().max()

1voto

Grizly Puntos 850

Además de la respuesta de chrisaycock, también podríamos normalizar la reducción máxima con los wartermarks altos en lugar de los rendimientos acumulados actuales.

highwatermarks = cumulative_returns.cummax()
drawdowns = 1 - (1 + cumulative_returns) / (1 + highwatermarks)
max_drawdown = max(drawdowns)

Aquí observamos la definición de detracción definida aquí . $$MDD=\frac{Trough\ ValuePeak\ Value}{Peak\ Value}$$

Finanhelp.com

FinanHelp es una comunidad para personas con conocimientos de economía y finanzas, o quiere aprender. Puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X