경제분석

금리인하 와 S&P500 지수 변동 분석(with 파이썬, FRED, yfinance)

치타뱅뱅 2024. 11. 5. 13:54
728x90

안녕하세요.

 

주식투자하시는 분이라면 2024년 9월에 미국 연준에 기준금리를 인하하고 S&P500 지수가 어떤 흐름을 보일지 관심이 많습니다.

아래는 기준금리는 FRED API를 이용해서 수집, S&P500지수는 yfinance API를 이용해 수집하여 분석하였습니다.

 

정량적 분석을 활용해서 분석하고 싶으신 분들은 아래사항 참고하세요.

 

1. 결과표

기준금리 인하후 4개월 뒤의 S&P500 지수

 

Probability of decline after 4 months: 35.00%
Average decline after 4 months (for decline cases): -7.73%

 - 결과 해석 : 금리이하후 4개월뒤 S&P500 지수 하락 가능성 35%, 평균 하락율 -7.73%

   ==> 통계의 함정으로 정확히 해석하면 금리가 상승기조를 유지하다가 하락기조로 변경후 약 4개월내 시점인

          1987 블랙먼데이, 2000 닷컴버블, 2008 금융위기, 2020 코로나 위기시 -20% 이상의 하락폭이 발생

   ==> 현 시사점 : 2021년도부터 S&P 500지수의 큰 폭 상승이후 금리인하한 현 시점에서 아직 큰 조정이 없었음 --> 이후 큰폭의 하락이 발생할 확률이 상당히 높음

2. 분석방법

 2.1 전제조건

 - 기간 : 데이터 존재하는 1985.01.01 ~ 2024.10.31

 - 가설 : 역대 경제위기 전에는 약 4개월전 금리를 인하하고, 이후 S&P500지수의 큰 하락폭이 발생한다.(-20%)

 - 경제위기 : 1987 블랙먼데이, 2000 닷컴버블, 2008 금융위기, 2020 코로나 위기

 2.2 수행방법(code 중심)

 

    가. 각종 필요 라이브러리 import 및 데이터 수집

import pandas as pd
import matplotlib.pyplot as plt
import yfinance as yf
from fredapi import Fred

# Initialize FRED API
fred = Fred(api_key='본인의 API를 입력하세요')

# Fetch the interest rate data  
interest_rate = fred.get_series('FEDFUNDS', start='1985-01-01', end='2024-10-31')

# Fetch the S&P 500 index data
sp500 = yf.download('^GSPC', start='1985-01-01', end='2024-10-31', interval='1mo')['Adj Close']

# Identify rate cuts (where interest rate drops from the previous value)
rate_cuts = interest_rate[interest_rate.diff() < 0]

# Filter S&P 500 change 4 months after each rate cut
sp500_changes_4mo_after_cut = pd.DataFrame(columns=['Date', '4-Month Change (%)'])
first_cut_dates = []

for date in rate_cuts.index:
    # Find the closest available date in S&P 500 data
    closest_date = sp500.index.asof(date)
    
    # Ensure that closest_date is valid (not NaT)
    if pd.notna(closest_date):
        initial_value = sp500.loc[closest_date]
        
        # Calculate 4 months later date and find the closest available date
        four_months_later = closest_date + pd.DateOffset(months=4)
        four_months_later = sp500.index.asof(four_months_later)
        
        # Ensure four_months_later is valid (not NaT)
        if pd.notna(four_months_later):
            four_month_value = sp500.loc[four_months_later]
            change_4mo = ((four_month_value - initial_value) / initial_value) * 100
            sp500_changes_4mo_after_cut = pd.concat([
                sp500_changes_4mo_after_cut,
                pd.DataFrame({'Date': [four_months_later], '4-Month Change (%)': [change_4mo]})
            ], ignore_index=True)
            
            # Record the date of the first rate cut for annotation
            if len(first_cut_dates) == 0 or first_cut_dates[-1] != closest_date:
                first_cut_dates.append(closest_date)

 

    나. 금리인하후 4개월 뒤의 S&P 500지수 변동률 계산 및 그래프 도식
# Calculate probability of decline and average decline
decline_cases = sp500_changes_4mo_after_cut[sp500_changes_4mo_after_cut['4-Month Change (%)'] < 0]
decline_probability = len(decline_cases) / len(sp500_changes_4mo_after_cut) * 100  # Percentage of declines
average_decline = decline_cases['4-Month Change (%)'].mean()  # Average decline

# Print results
print(f"Probability of decline after 4 months: {decline_probability:.2f}%")
print(f"Average decline after 4 months (for decline cases): {average_decline:.2f}%")

# Plotting the 4-month changes after rate cuts with color differentiation
plt.figure(figsize=(12, 6))

# Assign colors based on positive (red) and negative (blue) values
colors = ['red' if val > 0 else 'blue' for val in sp500_changes_4mo_after_cut['4-Month Change (%)']]
bars = plt.bar(sp500_changes_4mo_after_cut['Date'], sp500_changes_4mo_after_cut['4-Month Change (%)'], 
               color=colors, alpha=0.7, width=20)

# Highlight the first rate cut points with enlarged green arrows
for cut_date in first_cut_dates:
    plt.annotate(
        'Rate Cut Start', 
        xy=(cut_date, sp500.loc[cut_date]), 
        xytext=(cut_date, sp500.loc[cut_date] + 100),  # Adjust position of the text above the bar
        arrowprops=dict(arrowstyle='->', color='green', lw=2),
        ha='center', color='green', fontsize=12, weight='bold'
    )

plt.xlabel('Date')
plt.ylabel('S&P 500 4-Month % Change')
plt.title('4-Month S&P 500 Changes After Fed Rate Cuts')

plt.show()