-
카테고리
-
세부 분야
금융 · 재테크
-
해결 여부
미해결
수익률이 맞는지 코드 문의 드립니다.
24.02.19 23:45 작성 조회수 96
0
안녕하세요 수강을 하여 만족스러운 강의를 들었습니다.
개인적으로 궁금한 것을 구현했는데 소스가 맞는지 검증 부탁드려도 될까 합니다.
생각해 본 부분을 짜보긴 했지만 수익률이 잘못 나온 듯하여 오류를 아무리 검증해보려고해도 알 수가 없어서 문의드립니다.
추가로 다른 분에게도 도움이 되길 바라고, 또한 제 코드에서도 최적화 할 부분이 보일 듯하니 조언 부탁드립니다.
강의에서 나온 부분이 많기에 주석과 맥락등은 일부 제거 했습니다.
[조건]
종목 TQQQ, SCHD
adj_close 값
TQQQ RSI<30 : TQQQ 3% 비중 증가 , SCHD 3%비중 감소
리밸런싱 5:5 매 반기마다 실행
!apt-get update -qq
!pip install yfinance
import yfinance as yf
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
import numpy as np
# 수정종가
def getAdjCloseData(ticker, end=None):
return yf.download(ticker, period='12y')['Adj Close']
# RSI 데이터
def getRSIData(closeDataSet, periods=""):
average_periods = 14 # 이평 초기에 값은 나오지 않기 때문에 더 계산하고 자름
delta = closeDataSet.diff() # closeDataSet - closeDataSet.shift(1) # 변화량
if periods != "":
delta = delta.iloc[(periods + average_periods) * -1:]
AU = pd.DataFrame(np.where(delta>=0, delta, 0), delta.index, delta.columns)
AD = pd.DataFrame(np.where(delta<0, delta.abs(), 0), delta.index, delta.columns)
# SMA
AU_MA = getSimpleMovingAverage(AU, average_periods)
AD_MA = getSimpleMovingAverage(AD, average_periods)
rsi = AU_MA / (AU_MA + AD_MA) * 100
# RSI Signal
rsiSignal = getSimpleMovingAverage(rsi, 9)
if periods != "":
rsi = rsi[average_periods:]
rsiSignal = rsiSignal[average_periods:]
return rsi, rsiSignal
# RSI 값에 따른 리밸런싱 날짜
def getRSIRebalancingDate(closeDataSet, RSI = 30):
rsi, rsiSignal = getRSIData(closeDataSet)
data = rsi.copy()
data = pd.DataFrame(data)
dataIndex = data[data.iloc[:, 0] <= RSI].index
return dataIndex
def getWeightByRSI(closeDataSet):
RSIrebalancingDate = getRSIRebalancingDate(closeDataSet, 30) # RSI가 30이하일 때 리밸런싱 날짜
rebalancingDate = getRebalancingDate(closeDataSet, 'half') # 동일비중 리밸런싱 할 날짜
rebal = pd.DataFrame([[1/len(closeDataSet.columns)] * len(closeDataSet.columns)] * len(rebalancingDate),
index=rebalancingDate,
columns=closeDataSet.columns)
rebal['period'] = 1 # 기간에 따른 리밸런싱
rsiRebal = pd.DataFrame([[1/len(closeDataSet.columns)] * len(closeDataSet.columns)] * len(RSIrebalancingDate),
index=RSIrebalancingDate,
columns=closeDataSet.columns)
rsiRebal['period'] = 0 # RSI에 따른 리밸런싱
weightDf = pd.concat([rebal, rsiRebal], axis=0)
weightDf = weightDf.sort_index()
# 리밸런싱 날짜 별
for i in range(1, len(weightDf)):
if weightDf.iloc[i]['period'] == 1: # 기간에 따른 리밸런싱
weightDf.iloc[i, weightDf.columns.get_loc("TQQQ")] = weightDf.iloc[0, weightDf.columns.get_loc("TQQQ")]
weightDf.iloc[i, weightDf.columns.get_loc("SCHD")] = weightDf.iloc[0, weightDf.columns.get_loc("SCHD")]
else: # RSI에 따른 리밸런싱
weightDf.iloc[i, weightDf.columns.get_loc("TQQQ")] = weightDf.iloc[i-1, weightDf.columns.get_loc("TQQQ")] * 1.03
weightDf.iloc[i, weightDf.columns.get_loc("SCHD")] = weightDf.iloc[i-1, weightDf.columns.get_loc("SCHD")] * 0.97
return weightDf
def getRSIPortfolioResult(closeDataSet):
weight = getWeightByRSI(closeDataSet)
weightDf = pd.DataFrame(weight)
rebalancingDate = weightDf.index
portfolio = pd.DataFrame() # 빈 데이터 프레임 생성
totalAsset = 1 # 총 자산, 초기값 1
start = rebalancingDate[0] # 리밸런싱 날짜, 초기값 첫 투자일
for end in rebalancingDate[1:]:
weight = weightDf.loc[start] # 당월 리밸런싱 비율
weight = weight.drop('period')
priceData = closeDataSet.loc[start:end] # 당월 가격 데이터
cumReturn = getCumulativeReturn(priceData) # 당월 누적 수익률
weightedCumReturn = weight * cumReturn # 당월 리밸런싱 비율이 반영된 누적 수
netCumReturn = totalAsset * weightedCumReturn # 전월 투자 결과 반영 (이전 블록의 누적 수익을 포함시킴)
start = end # start 갱신
totalAsset = netCumReturn.iloc[-1].sum() # 총 자산 갱신
portfolio = pd.concat([portfolio, netCumReturn]) # 매월 데이터 추가
portfolio = portfolio.loc[~portfolio.index.duplicated(keep='last')] # 중복 데이터 제거
portfolioCumulativeReturn = portfolio.sum(axis=1) # 포트폴리오 누적 수익률
portfolioDayReturn = (portfolioCumulativeReturn / portfolioCumulativeReturn.shift(1)).fillna(1) # 포트폴리오 일간 수익률
return portfolioDayReturn, portfolioCumulativeReturn
closeDataSet = pd.DataFrame()
TQQQ = getAdjCloseData("TQQQ") # TQQQ
SCHD = getAdjCloseData("SCHD") # SCHD
closeDataSet = pd.concat([TQQQ , SCHD ], axis=1)
closeDataSet.columns = asset
closeDataSet.dropna(inplace=True)
_, rsiCumReturn = getRSIPortfolioResult(closeDataSet)
rsiMomentumCAGR, rsiMomentumDD, rsiMomentumMDD = getEvaluation(rsiCumReturn)
답변을 작성해보세요.
0
인프런 AI 인턴
2024.02.21
안녕하세요, 인프런 AI 인턴입니다.
님이 질문하신 코드에 대한 검증은 직접 실행해본 결과를 통해 이루어져야 하지만, 아쉽게도 저는 코드를 실행할 수 없습니다. 하지만 코드를 작성하면서 고려해야 할 사항을 몇 가지 말씀드릴 수 있습니다.
getAdjCloseData
함수에서 ‘Adj Close’를 가져올 때, 종종 티커에 따라 올바르게 데이터가 다운로드되지 않는 경우가 발생할 수 있습니다. 따라서 데이터를 다운로드한 후 확인하는 과정이 필요합니다.getRSIData
함수에서 RSI를 계산할 때, 이동 평균 계산 방법(SMA, EMA 등)이 명확히 정의되어 있는지 확인해야 합니다. 해당 함수 내에 있는getSimpleMovingAverage
함수의 정의와 동작을 정확히 이해하는 것이 중요합니다.리밸런싱 로직에서는 각 리밸런싱 포인트와 비중 조절이 올바르게 계산되고 있는지 체크해야 합니다. 특히, RSI 기반 비중 조정 과정에서 예상과 다르게 작동할 수 있는 부분을 주의 깊게 보아야 합니다.
전체 포트폴리오 수익률을 계산하는 과정에서
cumReturn
,weightedCumReturn
,netCumReturn
등의 계산이 기대하는 바대로 이루어지고 있는지 확인이 필요합니다.마지막으로,
getEvaluation
함수가 호출되고 있지만, 이 함수의 정의가 제공되지 않았습니다. 해당 함수가 어떻게 포트폴리오의 CAGR(복리 연평균 성장률), DD(드로다운), MDD(최대 드로다운)를 계산하는지 이해하는 것이 중요합니다.
코드의 최적화와 오류 발견을 위해 디버깅을 할 때는 작은 단위의 데이터로 함수를 테스트하고, 각 단계에서의 출력 결과를 확인하는 것을 추천드립니다. 또한, 문제가 발생하는 부분에 대해서는 강의 Q&A 섹션을 활용하거나 해당 소스 코드를 게시할 수 있는 포럼이나 다른 수강생들과의 소통을 통해 도움을 받는 것도 좋은 방법입니다.
원하는 답변을 찾지 못하셨나요?
그럼 우측 하단의 ‘문의하기’ 에서 직접 문의해주세요.
최대한 빠르게 답변드리도록 하겠습니다!
참고 URL:
- 인프런 FAQ
답변 1