10 votos

¿Cómo puedo calcular la máxima reducción de MDD en la pitón

Necesito calcular la máxima reducción dinámica del tiempo en Python. El problema es que, por ejemplo:

( df.CLOSE_SPX.max() - df.CLOSE_SPX.min() ) / df.CLOSE_SPX.max()

no puede funcionar, ya que estas funciones utilizan todos los datos y no consideran el mínimo sólo a partir de un máximo determinado en la línea de tiempo. ¿Alguien sabe cómo implementar eso en Python?

Este es un breve ejemplo del marco de datos utilizado:

              CLOSE_SPX    Close_iBoxx  A_Returns  B_Returns  A_Vola    B_Vola
2014-05-15    1870.85      234.3017    -0.009362   0.003412   0.170535  0.075468   
2014-05-16    1877.86      234.0216     0.003747  -0.001195   0.170153  0.075378
2014-05-19    1885.08      233.7717     0.003845  -0.001068   0.170059  0.075384   
2014-05-20    1872.83      234.2596    -0.006498   0.002087   0.170135  0.075410   
2014-05-21    1888.03      233.9101     0.008116  -0.001492   0.169560  0.075326   
2014-05-22    1892.49      233.5429     0.002362  -0.001570   0.169370  0.075341   
2014-05-23    1900.53      233.8605     0.004248   0.001360   0.168716  0.075333   
2014-05-27    1911.91      234.0368     0.005988   0.000754   0.168797  0.075294   
2014-05-28    1909.78      235.4454    -0.001114   0.006019   0.168805  0.075474   
2014-05-29    1920.03      235.1813     0.005367  -0.001122   0.168866  0.075451   
2014-05-30    1923.57      235.2161     0.001844   0.000148   0.168844  0.075430   
2014-06-02    1924.97      233.8868     0.000728  -0.005651   0.168528  0.075641   
2014-06-03    1924.24      232.9049    -0.000379  -0.004198   0.167852  0.075267

30voto

Skaughty Puntos 693

Puede obtener esto usando un pandas rolling_max para encontrar el máximo pasado en una ventana para calcular la reducción del día actual, y luego usar un rolling_min para determinar la reducción máxima que se ha experimentado.

Digamos que queremos el máximo drawdown móvil de 1 año (252 días de negociación) experimentado por un símbolo en particular. Lo siguiente debería servir:

import pandas as pd
import pandas_datareader as  web
import matplotlib.pyplot as pp
import datetime

# Get SPY data for past several years

SPY_Dat = web.DataReader('SPY', 'yahoo', datetime.date(2007,1,1))

# We are going to use a trailing 252 trading day window
window = 252

# Calculate the max drawdown in the past window days for each day in the series.
# Use min_periods=1 if you want to let the first 252 days data have an expanding window
Roll_Max = SPY_Dat['Adj Close'].rolling(window, min_periods=1).max()
Daily_Drawdown = SPY_Dat['Adj Close']/Roll_Max - 1.0

# Next we calculate the minimum (negative) daily drawdown in that window.
# Again, use min_periods=1 if you want to allow the expanding window
Max_Daily_Drawdown = Daily_Drawdown.rolling(window, min_periods=1).min()

# Plot the results
Daily_Drawdown.plot()
Max_Daily_Drawdown.plot()
pp.show()

Qué rendimientos (el azul es la reducción diaria de 252 días, el verde es la reducción máxima experimentada de 252 días en el último año): Max Drawdown Result

Nota: con el nuevo

0 votos

Se ve bien, pero devuelve un error de valor: ValueError Traceback (most recent call last) D:\Python Módulos \MDDown.pyx en <módulo>() 20 21 # Trazar los resultados ---> 22 Daily_Drawdown.plot() 23 Max_Daily_Drawdown.plot() 24 pp.show()

0 votos

Parece que puede haber un problema con su integración de pandas/matplotlib compruebe la variable Max_Daily_Drawdown.. debería contener lo que necesita.

0 votos

¡Funciona, perfecto! ¡Muchas gracias, MarkD! ¡Aprecio mucho tu apoyo!

16voto

Alex Puntos 18

Si desea considerar la reducción desde el principio de la serie temporal en lugar de sólo los últimos 252 días de negociación, considere el uso de cummax() y cummin()

Roll_Max = SPY_Dat['Adj Close'].cummax()
Daily_Drawdown = SPY_Dat['Adj Close']/Roll_Max - 1.0
Max_Daily_Drawdown = Daily_Drawdown.cummin()

10voto

Kevin Tighe Puntos 5573

Para cualquiera que encuentre esto ahora pandas ha eliminado pd.rolling_max y min por lo que hay que pasar

(series o df).rolling(window, min_periods=None, center=False, win_type=None, on=None, axis=0, closed=None).max()

# We are going to use a trailing 252 trading day window
window = 252

# Calculate the max drawdown in the past window days for each day in the series.
# Use min_periods=1 if you want to let the first 252 days data have an expanding window
Roll_Max = SPY_Dat['Adj Close'].rolling(window, min_periods=1).max()
Daily_Drawdown = SPY_Dat['Adj Close']/Roll_Max - 1.0

# Next we calculate the minimum (negative) daily drawdown in that window.
# Again, use min_periods=1 if you want to allow the expanding window
Max_Daily_Drawdown = Daily_Drawdown.rolling(window, min_periods=1).min()

# Plot the results
Daily_Drawdown.plot()
Max_Daily_Drawdown.plot()
pp.show()

8voto

Antero Duarte Puntos 106

Hace poco tuve un problema similar, pero en lugar de una MDD global, debía encontrar la MDD para el intervalo después de cada pico. Mi implementación basada en Investopedia La descripción es la siguiente.

import pandas as pd

def calc_MDD(networth):
  df = pd.Series(networth, name="nw").to_frame()

  max_peaks_idx = df.nw.expanding(min_periods=1).apply(lambda x: x.argmax()).fillna(0).astype(int)
  df['max_peaks_idx'] = pd.Series(max_peaks_idx).to_frame()

  nw_peaks = pd.Series(df.nw.iloc[max_peaks_idx.values].values, index=df.nw.index)

  df['dd'] = ((df.nw-nw_peaks)/nw_peaks)
  df['mdd'] = df.groupby('max_peaks_idx').dd.apply(lambda x: x.expanding(min_periods=1).apply(lambda y: y.min())).fillna(0)

  return df

Aquí hay un ejemplo después de ejecutar este código:

    nw          max_peaks_idx       dd          mdd
0   10000.000       0           0.000000    0.000000
1   9726.943        0           -0.027306   -0.027306
2   9464.503        0           -0.053550   -0.053550
3   9676.380        0           -0.032362   -0.053550
4   9709.717        0           -0.029028   -0.053550
5   9824.248        0           -0.017575   -0.053550
6   9919.061        0           -0.008094   -0.053550
7   9909.199        0           -0.009080   -0.053550
8   10140.184       8           0.000000    0.000000
9   10088.081       8           -0.005138   -0.005138
10  9970.515        8           -0.016732   -0.016732
11  9972.278        8           -0.016558   -0.016732

Y aquí hay una imagen del completo aplicada al conjunto de datos completo. enter image description here

PD: Podría haber eliminado los valores cero en el dd y mdd pero me parece útil que estos valores ayuden a indicar cuándo se ha observado un nuevo pico en la serie temporal.

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