[PYTHON] Python에서 벡터화 된 솔루션으로 최대 계산
PYTHONPython에서 벡터화 된 솔루션으로 최대 계산
최대 삭도는 경험 한 가장 큰 부정적인 반환을 사정하기 위하여 양이 많은 회계에서 사용 된 일반적인 위험 측정 규정입니다.
최근에, 나는 루프 방식을 사용하여 최대 삭감을 계산할 시간에 참을성이 없어졌습니다.
def max_dd_loop(returns):
"""returns is assumed to be a pandas series"""
max_so_far = None
start, end = None, None
r = returns.add(1).cumprod()
for r_start in r.index:
for r_end in r.index:
if r_start < r_end:
current = r.ix[r_end] / r.ix[r_start] - 1
if (max_so_far is None) or (current < max_so_far):
max_so_far = current
start, end = r_start, r_end
return max_so_far, start, end
저는 벡터화 된 솔루션이 더 좋을 것이라는 일반적인 인식에 익숙합니다.
질문은 다음과 같습니다.
알렉산더의 대답을 다음과 같이 수정했습니다.
def max_dd(returns):
"""Assumes returns is a pandas Series"""
r = returns.add(1).cumprod()
dd = r.div(r.cummax()).sub(1)
mdd = dd.min()
end = dd.argmin()
start = r.loc[:end].argmax()
return mdd, start, end
해결법
-
==============================
1.df_returns는 수익의 데이터 프레임으로 간주되며 각 열은 별도의 전략 / 관리자 / 보안이며 각 행은 새로운 날짜 (예 : 월별 또는 매일)입니다.
df_returns는 수익의 데이터 프레임으로 간주되며 각 열은 별도의 전략 / 관리자 / 보안이며 각 행은 새로운 날짜 (예 : 월별 또는 매일)입니다.
cum_returns = (1 + df_returns).cumprod() drawdown = 1 - cum_returns.div(cum_returns.cummax())
-
==============================
2.먼저 .expanding () 창을 사용하여 제안했지만 .cumprod () 및 .cummax () 함수를 사용하여 특정 지점까지 최대 drawdown을 계산할 필요는 없습니다.
먼저 .expanding () 창을 사용하여 제안했지만 .cumprod () 및 .cummax () 함수를 사용하여 특정 지점까지 최대 drawdown을 계산할 필요는 없습니다.
df = pd.DataFrame(data={'returns': np.random.normal(0.001, 0.05, 1000)}, index=pd.date_range(start=date(2016,1,1), periods=1000, freq='D')) df = pd.DataFrame(data={'returns': np.random.normal(0.001, 0.05, 1000)}, index=pd.date_range(start=date(2016, 1, 1), periods=1000, freq='D')) df['cumulative_return'] = df.returns.add(1).cumprod().subtract(1) df['max_drawdown'] = df.cumulative_return.add(1).div(df.cumulative_return.cummax().add(1)).subtract(1)
returns cumulative_return max_drawdown 2016-01-01 -0.014522 -0.014522 0.000000 2016-01-02 -0.022769 -0.036960 -0.022769 2016-01-03 0.026735 -0.011214 0.000000 2016-01-04 0.054129 0.042308 0.000000 2016-01-05 -0.017562 0.024004 -0.017562 2016-01-06 0.055254 0.080584 0.000000 2016-01-07 0.023135 0.105583 0.000000 2016-01-08 -0.072624 0.025291 -0.072624 2016-01-09 -0.055799 -0.031919 -0.124371 2016-01-10 0.129059 0.093020 -0.011363 2016-01-11 0.056123 0.154364 0.000000 2016-01-12 0.028213 0.186932 0.000000 2016-01-13 0.026914 0.218878 0.000000 2016-01-14 -0.009160 0.207713 -0.009160 2016-01-15 -0.017245 0.186886 -0.026247 2016-01-16 0.003357 0.190869 -0.022979 2016-01-17 -0.009284 0.179813 -0.032050 2016-01-18 -0.027361 0.147533 -0.058533 2016-01-19 -0.058118 0.080841 -0.113250 2016-01-20 -0.049893 0.026914 -0.157492 2016-01-21 -0.013382 0.013173 -0.168766 2016-01-22 -0.020350 -0.007445 -0.185681 2016-01-23 -0.085842 -0.092648 -0.255584 2016-01-24 0.022406 -0.072318 -0.238905 2016-01-25 0.044079 -0.031426 -0.205356 2016-01-26 0.045782 0.012917 -0.168976 2016-01-27 -0.018443 -0.005764 -0.184302 2016-01-28 0.021461 0.015573 -0.166797 2016-01-29 -0.062436 -0.047836 -0.218819 2016-01-30 -0.013274 -0.060475 -0.229189 ... ... ... ... 2018-08-28 0.002124 0.559122 -0.478738 2018-08-29 -0.080303 0.433921 -0.520597 2018-08-30 -0.009798 0.419871 -0.525294 2018-08-31 -0.050365 0.348359 -0.549203 2018-09-01 0.080299 0.456631 -0.513004 2018-09-02 0.013601 0.476443 -0.506381 2018-09-03 -0.009678 0.462153 -0.511158 2018-09-04 -0.026805 0.422960 -0.524262 2018-09-05 0.040832 0.481062 -0.504836 2018-09-06 -0.035492 0.428496 -0.522411 2018-09-07 -0.011206 0.412489 -0.527762 2018-09-08 0.069765 0.511031 -0.494817 2018-09-09 0.049546 0.585896 -0.469787 2018-09-10 -0.060201 0.490423 -0.501707 2018-09-11 -0.018913 0.462235 -0.511131 2018-09-12 -0.094803 0.323611 -0.557477 2018-09-13 0.025736 0.357675 -0.546088 2018-09-14 -0.049468 0.290514 -0.568542 2018-09-15 0.018146 0.313932 -0.560713 2018-09-16 -0.034118 0.269104 -0.575700 2018-09-17 0.012191 0.284576 -0.570527 2018-09-18 -0.014888 0.265451 -0.576921 2018-09-19 0.041180 0.317562 -0.559499 2018-09-20 0.001988 0.320182 -0.558623 2018-09-21 -0.092268 0.198372 -0.599348 2018-09-22 -0.015386 0.179933 -0.605513 2018-09-23 -0.021231 0.154883 -0.613888 2018-09-24 -0.023536 0.127701 -0.622976 2018-09-25 0.030160 0.161712 -0.611605 2018-09-26 0.025528 0.191368 -0.601690
-
==============================
3.일련의 수익률을 감안할 때 시작 지점과 종료 지점의 모든 조합에 대한 총 수익을 평가해야합니다.
일련의 수익률을 감안할 때 시작 지점과 종료 지점의 모든 조합에 대한 총 수익을 평가해야합니다.
첫 번째 트릭은 일련의 반환 값을 일련의 반환 인덱스로 변환하는 것입니다. 일련의 수익률 지수가 주어지면, 임의의 하위 기간에 걸쳐 수익률을 시작 지표 ri_0과 끝점 ri_1에서 계산할 수 있습니다. 계산은 ri_1 / ri_0 - 1입니다.
두 번째 트릭은 리턴 인덱스의 반전에 대한 두 번째 계열을 생성하는 것입니다. 만약 r이 나의 일련의 반환 지수라면, 1 / r은 나의 역행렬입니다.
세 번째 트릭은 r * (1 / r) .Transpose의 행렬 곱을 취하는 것입니다.
r은 nx1 행렬입니다. (1 / r) .Transpose는 1 x n 행렬입니다. 결과 제품은 ri_j / ri_k의 모든 조합을 포함합니다. 그냥 1을 빼면 실제로 수익을 얻었습니다.
네 번째 요령은 내가 분자로 표현되기 이전의 마침표를 나타내도록 내 분모를 제한하는 것입니다.
아래는 내 벡터화 된 함수입니다.
import numpy as np import pandas as pd def max_dd(returns): # make into a DataFrame so that it is a 2-dimensional # matrix such that I can perform an nx1 by 1xn matrix # multiplication and end up with an nxn matrix r = pd.DataFrame(returns).add(1).cumprod() # I copy r.T to ensure r's index is not the same # object as 1 / r.T's columns object x = r.dot(1 / r.T.copy()) - 1 x.columns.name, x.index.name = 'start', 'end' # let's make sure we only calculate a return when start # is less than end. y = x.stack().reset_index() y = y[y.start < y.end] # my choice is to return the periods and the actual max # draw down z = y.set_index(['start', 'end']).iloc[:, 0] return z.min(), z.argmin()[0], z.argmin()[1]
이 기능은 어떻게 수행됩니까?
벡터화 된 솔루션의 경우 길이 10, 50, 100, 150, 200의 시계열에서 10 번의 반복을 실행했습니다. 시간은 아래와 같습니다.
10: 0.032 seconds 50: 0.044 seconds 100: 0.055 seconds 150: 0.082 seconds 200: 0.047 seconds
루프 된 솔루션에 대한 동일한 테스트가 아래와 같습니다.
10: 0.153 seconds 50: 3.169 seconds 100: 12.355 seconds 150: 27.756 seconds 200: 49.726 seconds
알렉산더의 대답은 뛰어난 결과를 제공합니다. 수정 된 코드를 사용하여 동일한 테스트
10: 0.000 seconds 50: 0.000 seconds 100: 0.004 seconds 150: 0.007 seconds 200: 0.008 seconds
코드를 다음 함수로 수정했습니다.
def max_dd(returns): r = returns.add(1).cumprod() dd = r.div(r.cummax()).sub(1) mdd = drawdown.min() end = drawdown.argmin() start = r.loc[:end].argmax() return mdd, start, end
from https://stackoverflow.com/questions/36750571/calculate-max-draw-down-with-a-vectorized-solution-in-python by cc-by-sa and MIT license
'PYTHON' 카테고리의 다른 글
[PYTHON] 문자열에서 모든 구두점을 제거하는 방법? (파이썬) [복제] (0) | 2018.10.21 |
---|---|
[PYTHON] 특정 투영법을 사용할 때 Basemap.contour ()가있는 IndexError (0) | 2018.10.21 |
[PYTHON] 장고 관리자의 다른 선택 필드를 기반으로 선택 필드 옵션을 제한하는 방법 (0) | 2018.10.21 |
[PYTHON] 토네이도 셀러리 통합 해킹 (0) | 2018.10.21 |
[PYTHON] numpy에서 가우스 커널 행렬을 효율적으로 계산하는 방법은 무엇입니까? (0) | 2018.10.21 |