

모든 시점에 모든 자산에서 0%가 나오는 듯... ㅠㅜ
어쩌면 야후 파이낸스 데이터 문제일지도
일단 도전해봤다는 것에 의의를 둡니다
import numpy as np
import pandas as pd
import yfinance as yf
import matplotlib.pyplot as plt
from scipy.optimize import minimize
from scipy.linalg import lstsq
from datetime import datetime, timedelta
import warnings
import os
import time
warnings.filterwarnings('ignore')
class LPPL:
def __init__(self, observations):
"""
LPPL 모델 초기화.
Parameters:
observations (pd.DataFrame): 'Close' 가격 데이터와 DatetimeIndex를 포함하는 DataFrame.
"""
self.observations = observations
self.t = self.get_days_since_start() # 시작일로부터의 일수 계산
self.price = self.observations['Close'].values
self.log_price = np.log(self.price)
self.ts = self.t / self.t[-1] # 최적화를 위해 t를 [0,1] 범위로 스케일 조정
self.bounds = [
(0.01, 0.99), # m의 범위
(6, 13), # omega의 범위
(0, 2 * np.pi), # phi의 범위
# tc의 범위는 fit()에서 추가
]
def get_days_since_start(self):
"""
DatetimeIndex를 시작일로부터의 일수 배열로 변환.
Returns:
np.array: 시작일로부터의 일수를 나타내는 정수 배열.
"""
start_date = self.observations.index[0]
return (self.observations.index - start_date).days.values
def lppl_matrix(self, t, tc, m, omega, phi):
"""
주어진 파라미터에 대해 LPPL 행렬을 계산.
이 버전은 다음과 같은 3항식 형태를 사용합니다:
log(p(t)) = A + B*(tc-t)^m + C*(tc-t)^m * cos(omega * log(tc-t) - phi)
Args:
t (np.ndarray): 스케일 조정된 시간 배열 (0~1).
tc (float): 임계 시간.
m (float): 버블 성장 지수.
omega (float): 진동 주파수.
phi (float): 위상 이동.
Returns:
np.ndarray: (n, 3) 모양의 LPPL 행렬.
"""
t = np.array(t)
dt = (tc - t).clip(0) # 음수가 되지 않도록 함
dt_pow_m = dt**m
oscillatory = dt_pow_m * np.cos(omega * np.log(dt + 1e-8) - phi)
return np.vstack((np.ones_like(t), dt_pow_m, oscillatory)).T
def _func_(self, x, *args):
"""
최적화에서 최소화할 목적 함수 (비선형 파라미터에 대해).
Args:
x (np.ndarray): 비선형 파라미터 [m, omega, phi, tc] 배열.
*args: 추가 인자 (t, log_price).
Returns:
float: 제곱 오차 합.
"""
m, omega, phi, tc = x
t, log_price = args
lppl_m = self.lppl_matrix(t, tc, m, omega, phi)
try:
coefs = lstsq(lppl_m, log_price)[0]
except np.linalg.LinAlgError:
return 1e10 # lstsq 실패 시 큰 값을 반환
return np.sum((log_price - lppl_m @ coefs) ** 2)
def fit(self):
"""
L-BFGS-B 최적화 기법을 사용하여 가격 데이터에 LPPL 모델을 피팅.
Returns:
dict: 피팅된 파라미터와 기타 지표를 포함하는 딕셔너리.
"""
t_end = self.ts[-1]
# tc의 경계: 마지막 데이터 이후로 설정
bounds = self.bounds + [(t_end + 0.01, t_end + 5)]
init_guess = np.array([np.random.uniform(low, high) for low, high in bounds])
opt = minimize(
self._func_,
x0=init_guess,
args=(self.ts, self.log_price),
method='L-BFGS-B',
bounds=bounds,
)
m, omega, phi, tc = opt.x
lppl_m = self.lppl_matrix(self.ts, tc, m, omega, phi)
coefs = lstsq(lppl_m, self.log_price)[0]
A, B, C = coefs[0], coefs[1], coefs[2]
model = lppl_m @ coefs
residuals = self.log_price - model
mse = np.mean(residuals**2)
damping_factor = abs(B) / abs(C) if C != 0 else np.inf
num_oscillations = omega / (2 * np.pi) * np.log((tc - self.ts[0]) / (tc - self.ts[-1]))
rel_error = np.std(residuals) / np.std(self.log_price)
params = {
'A': A,
'B': B,
'C': C,
'm': m,
'omega': omega,
'phi': phi,
'tc': tc,
'tc_date': self.observations.index[0] + pd.Timedelta(days=int(tc * self.t[-1])),
'mse': mse,
'damping_factor': damping_factor,
'num_oscillations': num_oscillations,
'rel_error': rel_error,
'fit_success': opt.success,
'residuals': residuals
}
return params
def check_bubble_conditions(self, params):
"""
피팅된 파라미터가 버블 조건을 만족하는지 확인.
Parameters:
params (dict): 피팅된 LPPL 파라미터 딕셔너리.
...
먼저, 도전해보셨다는 점에서 이미 앞서 나가시는 분이라고 생각합니다. 데이터가 지정해주신 경로인 /root/desktop 쪽에 잘 다운로드 되어있고 안에 내용을 열어보셨을 때 이상이 없다면 데이터의 문제는 아닐 확률이 높습니다. 그렇다면 다음으로 확인해 봐야 할 것은 ' 현재 설정해놓은 파라미터들의 조건들이 너무 엄격한지 , 느슨한지 ' 체크해 봐야하는데 선생님의 코드를 그대로 가져다가 복사 붙여넣기를 하면 저도 모든 티커에서 0%라 나오고 문제를 해결하기 위해 이 코드를 디버깅해보면(과정생략) def check_bubble_conditions conditions = [ (0.01 <= m <= 0.99, f"m ({m:.4f}) not in [0.01, 0.99]"), (6 <= omega <= 13, f"omega ({omega:.4f}) not in [6, 13]"), (tc > t_last, f"tc ({tc:.4f}) not greater than t_last ({t_last:.4f})"), (tc < t_last + 5, f"tc ({tc:.4f}) too far in future (> t_last + 5)"), (num_oscillations >= 2.5, f"num_oscillations ({num_oscillations:.4f}) < 2.5"), (damping_factor > 1, f"damping_factor ({damping_factor:.4f}) <= 1"), (rel_error < 0.05, f"relative error ({rel_error:.4f}) >= 0.05") ] 결론적으로, 이 부분에서 설정해놓은 rel_error(상대 오차)의 조건(rel_error < 0.05)을 현재 설정해 놓은 다른 조건들에서 모든 데이터들이 만족하지 않는다는 것을 알 수 있습니다. 이 뜻은 모델 예측값이 실제값과 5% 밖에 차이를 내지 않는(rel_error < 0.05) 데이터를 찾는 과정이라 신뢰도는 매우 높지만, 현재 데이터들 중 이 오차를 만족한다는 데이터는 없고 현실적으로 불가능 하다는 것과 같은 말이 됩니다. 따라서, 다른 파라미터들의 값(ex. 기간,진동횟수 등)을 적절히 수정해 주신다던가 rel_error의 값을 0.05보다는 높게(ex. 0.3) 설정해주시면 이 문제는 해결 하실 수 있습니다. (단순하게 저 조건에서 rel_error < 0.05를 rel_error < 0.3 으로만 바꾸고 나름 버블이라고 생각했던 TSLA의 2020-01-01 ~ 2022-01-01 로 세팅을 해도 그럴싸한 결과 그래프는 나오긴 합니다.) 추가로 선생님께서 전공자가 아니시고, 코딩을 직접 하시거나 불러왔을 때 에러 발생 or 결과값이 지금처럼 유의미하게 나오지 않는다면 'Chat GPT' 같은 OpenAI를 옆에 두시고 도움을 받으시는 것도 좋은 방법이라고 생각합니다.(AI에게 물어보면 이정도는 30초안에 해결해 줄 수 있을 것 같습니다.)

우와 너무 감사합니다 선생님 알려주신 방법대로 수정해서 다시 한 번 도전해보겠습니다! 컴퓨터가 전공과 거리가 있어서 혼자 해결하기 쉽지 않았는데 도움 주셔서 감사합니다