<jupyter_start><jupyter_text>14MPAA.py를 ipynb로 옮겨서 시험<jupyter_code>import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import matplotlib
matplotlib.rc('font', family='NanumMyeongjo',size=8, weight = 'bold')
# plt.rcParams['axes.formatter.useoffset'] = False

plt.rcParams['axes.unicode_minus'] = False

import bt
get_ipython().magic("matplotlib inline")
# 매월 1일로 resample한 데이터
자료1 = pd.read_csv("data/mpaa.csv", index_col=0, parse_dates=True)
tickers = {'국가':['S&P 500', '러셀 3000', '니케이 225', '항셍', '홍콩 H', '대만 가권', '상해종합',
                    '영국 FTSE 100', '프랑스 CAC 40', '독일 DAX', 'KOSPI', '인도 SENSEX'],
           '섹터':['에너지', '화학', '금속및광물', '기타 소재', '건설', '기타자본재', '상업서비스',
                    '운송', '자동차및부품', '내구소비재및의류', '소비자서비스', '미디어', '유통',
                    '음식료및담배', '생활용품', '의료', '은행', '보험', '증권', '기타금융',
                    '소프트웨어', '하드웨어', '반도체', '디스플레이', '통신서비스', '유틸리티'],
           '팩터':['블루칩30', '모멘텀', '경기방어주', '고배당주', '베타플러스', 'Low Vol', '배당성장',
                    'Big Vol 지수', 'FnGuide 컨트래리안', 'FnGuide 퀄리티밸류 지수', '대형가치',
                    '대형성장', '대형순수가치', '대형순수성장', '중형가치', '중형성장', '중형순수가치',
                    '중형순수성장', '소형가치', '소형성장', '소형순수가치', '소형순수성장', '중대형가치',
                    '중대형성장', '중대형순수가치', '중대형순수성장', '중소형가치', '중소형순수가치',
                    '중소형성장', '중소형순수성장'],
           '채권':['채권', '20년채권', '채권인버스'],
           '현금':['현금']}
자료1
def 월간수익률(데이터):
    return 데이터 / 데이터.shift(1)

# %%
def 변동성대비모멘텀(데이터):
    a = 데이터/데이터.shift(12)
    b = 월간수익률(데이터).rolling(12).std()
    return a/b

# %%
def 연평균수익률(데이터): # not used
    return 데이터/데이터.shift(12)

# %%   앞 12개 NaN (2001-1 ~2001-12)
def 평균모멘텀(데이터, 개월=12):
    초기값 = 0
    for i in range(1, 개월+1):
        초기값 = 데이터 / 데이터.shift(i) + 초기값
    return 초기값 / 개월

# %%
def 모멘텀순위(데이터, 순위):
    x = 평균모멘텀(데이터)
    y = x.iloc[ : , 0: len(x.columns)].rank(1, ascending=0)
    y[y <= 순위] = 1
    y[y > 순위] = 0
    return y

# %%
def 평균모멘텀스코어(데이터):
    a = 평균모멘텀(데이터).copy()
    초기값 = 0
    for i in range(1, 13):
        초기값 = np.where(데이터 / 데이터.shift(i) > 1, 1, 0) + 초기값
    a[a > -1] = 초기값/12
    return a

# %%
def 평균모멘텀스코어6(데이터):
    a = 평균모멘텀(데이터, 6).copy() # bug 수익곡선은 6개월만 있으면 되는 12개월을 잡아먹음
    초기값 = 0
    for i in range(1, 7):
        초기값 = np.where(데이터 / 데이터.shift(i) > 1, 1, 0) + 초기값
    a[a > -1] = 초기값/6
    return a

# %%
def 현금혼합모멘텀수익곡선(데이터, 현금비율=0):
    # 데이터수익률+현금수익률
    # --------------------  . cumprod() 로 지수화
    #  전체 비중    
    # x = 월간수익률(자료1[tickers['현금']])*현금비율
    # a = pd.DataFrame( (월간수익률(데이터).values*평균모멘텀스코어(데이터).shift(1).values+x.values) \
    #                  / \
    #                  (현금비율+평균모멘텀스코어(데이터).shift(1).values) )\
    #                  .cumprod()
    x = 월간수익률(자료1[tickers['현금']])*현금비율*평균모멘텀스코어(자료1[tickers['현금']]).shift(1).values                     
    a = pd.DataFrame( (월간수익률(데이터).values*평균모멘텀스코어(데이터).shift(1).values+x.values) \
                     / \
                     (현금비율*평균모멘텀스코어(자료1[tickers['현금']]).shift(1).values+평균모멘텀스코어(데이터).shift(1).values) )\
                     .cumprod()
    a.index = 데이터.index
    a.columns = 데이터.columns
    return a

# %%
def 자산군통합포트(데이터, 순위, 자산군비중, 이름, 현금비율):
    x = 월간수익률(현금혼합모멘텀수익곡선(데이터, 현금비율))
    y = np.where(모멘텀순위(데이터, 순위).shift(1)==0,np.nan,자산군비중/순위)

    z = ((x*y).sum(1)).dropna()
    z = z.replace(0, np.nan)

    df = pd.DataFrame(현금혼합모멘텀수익곡선(데이터, 현금비율)*y, index=데이터.index)
    df.columns = 데이터.columns
    df.to_csv(이름+".csv")
    return z

# %%
def 통합모멘텀(국가비중,섹터비중,팩터비중,채권비중, 현금비율):
    a = 자산군통합포트(자료1[tickers['국가']],4,국가비중, '국가', 현금비율) # 2021-1~2022.2 NaN
    b = 자산군통합포트(자료1[tickers['섹터']],8,섹터비중, '섹터', 현금비율)
    c = 자산군통합포트(자료1[tickers['팩터']],10,팩터비중, '팩터', 현금비율)
    d = 자산군통합포트(자료1[tickers['채권']],1,채권비중, '채권', 현금비율)

    e = (pd.concat([a, b, c, d], axis=1).sum(1)/(국가비중+섹터비중+팩터비중+채권비중))
    # print(e.head(20))

    e = e.replace(0,np.nan).cumprod()
    e.columns = ['통합수익']
    return e

# %%
def 수익곡선모멘텀(국가비중,섹터비중,팩터비중,채권비중, 현금비율):
    x = 월간수익률(자료1[tickers['현금']])
    y = pd.DataFrame(통합모멘텀(국가비중,섹터비중,팩터비중,채권비중, 현금비율), index = x.index)  # x.index는 날짜  2001.1~2002.2 NaN
    # print(y.head(20))
    # print(월간수익률(y).head(25)) # 2002.3 NaN

    y.dropna().to_csv("통합모멘텀.csv")
    # print(평균모멘텀스코어6(y).to_csv("수익곡선.csv"))
    # 수익곡선모멘텀
    a = pd.DataFrame((월간수익률(y).values*평균모멘텀스코어6(y).shift(1).values+(1-평균모멘텀스코어6(y).shift(1).values)*x.values), index = x.index).cumprod().dropna()
    return a
a = 수익곡선모멘텀(1,1,1,3, 현금비율=1)
b = 자료1[tickers['국가']].KOSPI/자료1[tickers['국가']].KOSPI.iloc[0]

a.to_csv("수익곡선.csv")

c = pd.concat([a, b], axis=1).dropna()
c.columns = ['포트폴리오', '코스피']

c.divide(c.iloc[0]).plot(figsize = (18,12))
plt.show()

#5. MDD
최대하락 = c.포트폴리오.rolling(min_periods=1, window = 500).max()
당월하락 = c.포트폴리오/최대하락 - 1.0
최대하락폭 = 당월하락.rolling(min_periods=1, window=500).min()

당월하락.plot(subplots=True, figsize = (18,2), linestyle='dotted');
최대하락폭.plot(subplots=True, figsize = (18,2), color = 'red', linestyle='dotted');
plt.show()

#6. MDD / CAGR
투자기간 = len(c.index)/12
print("CAGR : "+str(c.포트폴리오[-1]**(1/투자기간)*100-100)[0:4]+"%")
print("MDD : "+str(최대하락폭.min()*100)[0:5]+"%")
c.to_csv('mpaa_result.csv')
c.calc_stats().display()<jupyter_output>Stat                 포트폴리오    코스피
-------------------  ------------  ----------
Start                2002-10-01    2002-10-01
End                  2017-07-01    2017-07-01
Risk-free rate       0.00%         0.00%

Total Return         214.99%       263.63%
Daily Sharpe         -             -
Daily Sortino        -             -
CAGR                 8.09%         9.15%
Max Drawdown         -4.09%        -48.52%
Calmar Ratio         1.98          0.19

MTD                  0.02%         0.18%
3m                   2.02%         8.64%
6m                   3.01%         15.88%
YTD                  3.07%         18.24%
1Y                   0.69%         18.84%
3Y (ann.)            5.45%         4.89%
5Y (ann.)            5.61%         4.95%
10Y (ann.)           6.40%         2.17%
Since Incep. (ann.)  8.09%         9.15%

Daily Sharpe         -             -
Daily Sortino        -             -
Daily Mean (ann.)    -             -
Daily Vol (ann.)     -             -
Daily Skew           - [...]<jupyter_text>자료 분석을 위해 테스트한 코드들<jupyter_code>aa = 자산군통합포트(자료1[tickers['국가']],4,1,'국가', 1)
aa
aa = aa.cumprod().dropna()
aa
aa = aa/aa.iloc[0] * 100
aa
# 자산군통합포트
x = 월간수익률(현금혼합모멘텀수익곡선(자료1[tickers['국가']], 1))

# y = np.where(모멘텀순위(데이터, 순위).shift(1)==0,np.nan,자산군비중/순위)

# z = ((x*y).sum(1)).dropna()
# z = z.replace(0, np.nan)
평균모멘텀스코어(자료1[tickers['국가']]).shift(1).dropna()
현금_평균모멘텀 = 평균모멘텀스코어(자료1[tickers['현금']]).shift(1).dropna()
현금_평균모멘텀.loc['2013-8-1']
y = np.where(모멘텀순위(자료1[tickers['국가']], 4).shift(1)==0,np.nan,1/4)
y
df = pd.DataFrame(y, index=자료1[tickers['국가']].index)
df.columns = 자료1[tickers['국가']].columns

df['2002-3':]
통합 = 통합모멘텀(1,0,0,0, 1).dropna().to_frame()
통합.columns = ['통합모멘텀']
통합
import bt
get_ipython().magic("matplotlib inline")
통합.calc_stats().display()
# 현금비율*평균모멘텀스코어(자료1[tickers['현금']]).shift(1).values
1.0*평균모멘텀스코어(자료1[tickers['현금']]).shift(1).values
월간수익률(자료1[tickers['현금']])*1.0*평균모멘텀스코어(자료1[tickers['현금']]).shift(1).values
월간수익률(자료1[tickers['현금']]).values*1.0*평균모멘텀스코어(자료1[tickers['현금']]).shift(1).values
x = 현금혼합모멘텀수익곡선(자료1[tickers['국가']], 1.0)
x
y = np.where(모멘텀순위(자료1[tickers['국가']], 4).shift(1)==0,np.nan,1/4)
y
# x 가상의 현금혼합모멘텀수익곡선 -> 각 국가지수의 비중을 역추산하기는 어렵다.
# y 순위에 따른 선택지수 비중
df = x*y
df['2002-2-1':].head(20)
df.sum(1).head(20)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.21551839464882944, 'fraction_numerical': 0.05377926421404682, 'mean_word_length': 2.398181818181818, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 14, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '2', 'dir': 'jupyter-structured-clean-dedup', 'id': '475804', 'license': 'MIT', 'n_tokens_mistral': 4749, 'n_tokens_neox': 5889, 'n_words': 564, 'path': '3.33_MPAA_dist.ipynb', 'repo_name': 'hermian/startetf', 'size': '7475'}