Inflearn brand logo image

인프런 커뮤니티 질문&답변

wltjq님의 프로필 이미지
wltjq

작성한 질문수

베개 투자법: 자면서 돈 버는 AI 주식 자동 매매 머신

경제 및 주가 데이터 수집 📑

4.15, 4.16 강의를 따라하는데 주가 데이터가 이상합니다

작성

·

36

·

수정됨

1

오늘 날짜 25-08-16에 python run.py로 실행 해서 주가 데이터를 supabase에 저장 시키는 부분은 오류 없이 잘 작동 했는데 Table Editor에 economic_and_stock_data 컬럼에 저장된 주가 데이터들을 보니깐 주가 데이터가 전혀 맞지도 않고 중복된 값이 여러개 들어가 있습니다 예로 몇개만 예시를 들면 2025-06-15 ~ 2025-08-14 애플 주가 데이터 저장된 것을 보면 232.77999877929688 중복으로 저장이 되있어요 당연 실제 주가 데이터랑 비교 해봐도 다르구요 다른 주식들도 마찬가지에요 중복으로 안맞는 주가 데이터가 저장되 있는게 많아요 주가를 가져오는 yfinance 라이브러리에 문제가 있는 것 같은데 확인좀 부탁드려요 4.15 강의를 보면 주가 데이터가 맞게 저장 되는 것 같은데 현재 날짜로 따라 해보면 주가 데이터가 이상해요

답변 3

0

안녕하세요, @wltjq님.

@wltjq님께서 데이터 수집 과정에서 겪으신 문제를 확인하고, 저도 최종 코드 기준으로 2025년 6월 1일부터 8월 16일까지 약 2개월 치 데이터를 수집해 Investing.com의 종가 데이터를 기준으로 검증해 보았습니다.

그 결과, 아래 이미지와 같이 데이터가 정상적으로 수집된 것을 확인할 수 있었습니다.

데이터 중복에 대한 부분은 말씀하신 대로 금, 토, 일요일의 경우 토요일과 일요일 데이터가 없으므로 금요일 종가로 대체됩니다. 이는 시장이 주말 동안 거래되지 않기 때문에 발생하는 정상적인 처리 방식입니.

image.png

추가로, 제가 사용한 최종본 stock.py 코드를 아래에 첨부드리오니 참고 부탁드립니다. @wltjq님께서 이미 이 문제를 독립적으로 해결하신 점, 정말 대단하시다고 생각합니다. 개발 과정에서 의도치 않은 동작을 마주하는 경우는 흔히 있지만, 이를 분석하고 해결하시는 과정에서 Cursor와 같은 도구를 적극 활용하신 점을 보면 강의에 대한 의도가 잘 전달되어 다행이라는 생각이듭니다.

앞으로도 이와 같이 체계적인 접근으로 문제를 풀어나가시면 실력 향상에 큰 도움이 되리라 믿습니다. 추가 질문이나 필요한 도움이 있다면 언제든지 편하게 말씀해 주세요. 항상 지원하겠습니다.

감사합니다.

 

import requests
import pandas as pd
import yfinance as yf
from datetime import datetime, timedelta
import numpy as np
import time



# FRED API Key 설정
api_key = 'fred api key를 설정해주세요.'

# FRED에서 제공하는 지표 코드와 명칭
fred_indicators = {
    'T10YIE': '10년 기대 인플레이션율',  # 10년 만기 기대 인플레이션율 (일간)
    'T10Y2Y': '장단기 금리차',  # 10년-2년 국채 수익률 스프레드 (일간)
    'FEDFUNDS': '기준금리',  # 연방기금 금리 (월간)
    'UMCSENT': '미시간대 소비자 심리지수',  # 소비자 신뢰 지수 (월간)
    'UNRATE': '실업률',  # 실업률 (월간)
    # 'USREC': '경기침체',  # 경기침체 지수 (월간) --> 장단기 금리차를 통해 확인 가능.
    'DGS2': '2년 만기 미국 국채 수익률',  # 2년 만기 국채 수익률 (일간)
    'DGS10': '10년 만기 미국 국채 수익률',  # 10년 만기 국채 수익률 (일간)

    # 추가 지표
    'STLFSI4': '금융스트레스지수',  # 금융 스트레스 지수 (주간)
    'PCE': '개인 소비 지출',  # 개인 소비 지출 (월간) -> 소비자물가지수(CPI)나 GDP, 실업률, 인플레이션 기대 등 다른 핵심 지표가 이미 전반적 경기 상황을 반영.
    # 'INDPRO': '산업생산',  # 산업 생산 지수 (월간)
    # 'HOUST': '주택 착공',  # 신규 주택 착공 건수 (월간)
    # 'UNEMPLOY': '실업자수',  # 실업자의 총 수 (월간)
    # 'RSAFS': '소매판매',  # 소매판매 지수 (월간)
    # 'CPIENGSL': '에너지 가격 지수',  # 소비자 물가지수 중 에너지 부문 (월간) -> 소비자물가지수(CPI)나 GDP, 실업률, 인플레이션 기대 등 다른 핵심 지표가 이미 전반적 경기 상황을 반영.
    # 'AHETPI': '임금 성장률',  # 시간당 평균 임금 성장률 (월간)
    # 'PPIACO': '농산물 가격 지수',  # 생산자 물가지수 중 농산물 부문 (월간)
    'CPIAUCSL': '소비자 물가지수',  # 전체 소비자 물가지수 (월간)
    # 'CSUSHPINSA': '주택가격지수',  # 케이스-실러 주택 가격 지수 (월간) -> 5년 변동금리 모기지 (MORTGAGE5US): 부동산 시장이 대상 종목(빅테크) 주가 변동에 단기적으로 큰 영향 미치는지 불분명. 단기간(1주일 후) 예측에서는 영향력 제한적.
    # 'MORTGAGE30US': '30년 고정금리 모기지',  # 30년 만기 고정금리 모기지 금리 (주간)
    # 'MORTGAGE15US': '15년 고정금리 모기지',  # 15년 만기 고정금리 모기지 금리 (주간)
    'MORTGAGE5US': '5년 변동금리 모기지',  # 5년 변동금리 모기지 금리 (주간)
    'DTWEXM': '미국 달러 환율',  # 미국 무역가중 환율 (월간)
    'M2': '통화 공급량 M2',  # M2 통화 공급량 (주간) -> FEDFUNDS나 금리 동향, 달러 인덱스, 금융스트레스지수가 이미 유동성 상황을 대략 파악 가능.
    # 'TEDRATE': 'TED 스프레드',  # 3개월 만기 미국 국채와 유로달러 금리 스프레드 (일간) -> FEDFUNDS나 금리 동향, 달러 인덱스, 금융스트레스지수가 이미 유동성 상황을 대략 파악 가능.
    # 'BAMLH0A0HYM2': '미국 하이일드 채권 스프레드',  # 미국 하이일드 채권과 국채 스프레드 (일간) -> 금융시장 신용위험을 반영하지만, 이미 금융스트레스지수(STLFSI4), 장단기금리차, VIX 등의 지표로 대략적인 위험 선호도나 스트레스 상황 파악 가능.
    # 'BAMLC0A0CM': '미국 회사채 스프레드',  # 미국 회사채와 국채 스프레드 (일간)
    # 'BAMLCC0A0CMTRIV': '미국 회사채 수익률',  # 미국 회사채 수익률 (일간)
    # 'BAMLCC0A1AAATRIV': '미국 회사채 AAA등급 수익률',  # AAA등급 회사채 수익률 (일간)
    # 'BAMLCC0A4BBBTRIV': '미국 회사채 BBB등급 수익률',  # BBB등급 회사채 수익률 (일간)
    # 'BAMLHYH0A0HYM2TRIV': '미국 하이일드 채권 수익률',  # 하이일드 채권 수익률 (일간)
    # 'BAMLHYH0A3CMTRIV': '미국 하이일드 채권 CCC등급 수익률',  # CCC등급 하이일드 채권 수익률 (일간)
    # 'BAMLHE00EHYIEY': '미국 하이일드 채권 기대수익률',  # 하이일드 채권 기대수익률 (일간)

    'TDSP': '가계 부채 비율',  # 가계의 부채 상환 비율을 나타냄 (분기)
    # 'A939RX0Q048SBEA': '실질 GDP 성장률',  # 계절 조정된 연간 실질 GDP 성장률 (분기)
    'GDPC1': 'GDP 성장률',  # 실질 국내총생산 성장률, 물가 조정을 반영 (분기)
    # 'W019RCQ027SBEA': '정부 지출',  # 정부의 총 지출 금액 (분기)
    # 'DRBLACBS': '대출 연체율',  # 기업 대출의 연체율 (분기)

    # 주식시장 관련 추가 지표
    # 'DJIA': '다우존스 산업평균지수',  # 미국 대형 30개 기업의 주가 평균 (일간)
    'NASDAQCOM': '나스닥 종합지수'  # 나스닥 시장 전체 종합 주가 지수 (일간)
}


# Yahoo Finance에서 제공하는 지표와 티커
yfinance_indicators = {
    'S&P 500 지수': '^GSPC',    # S&P 500 지수
    '금 가격': 'GC=F',           # 금 가격 (선물)
    '달러 인덱스': 'DX-Y.NYB',    # 달러 인덱스

    # 추가 지표
    '나스닥 100': '^NDX',           # 나스닥 100 지수
    'S&P 500 ETF': 'SPY',           # S&P 500 추종 ETF
    'QQQ ETF': 'QQQ',               # 나스닥 100 추종 ETF
    '러셀 2000 ETF': 'IWM',         # 러셀 2000 추종 ETF
    '다우 존스 ETF': 'DIA',          # 다우 존스 추종 ETF
    # 'NYSE FANG+ 지수': '^NYFANG'   # NYSE FANG+ 지수
    'VIX 지수': '^VIX',          # ^VIX (변동성 지수, 공포 지수): S&P 500 옵션 가격을 기반으로 앞으로의 시장 변동성 기대치를 반영해 시장 심리를 나타내는 지표.

    # 글로벌 지수
    '닛케이 225': '^N225',          # 일본 닛케이 225 지수
    '상해종합': '000001.SS',        # 중국 상해종합지수
    '항셍': '^HSI',                # 홍콩 항셍지수
    # '유로스톡스 50': '^STOXX50E',   # 유럽 유로스톡스 50 지수
    '영국 FTSE': '^FTSE',          # 영국 FTSE 100 지수
    '독일 DAX': '^GDAXI',          # 독일 DAX 지수
    '프랑스 CAC 40': '^FCHI',       # 프랑스 CAC 40 지수

    '미국 전체 채권시장 ETF': 'AGG',  # iShares 핵심 미국 전체 채권 ETF
    'TIPS ETF': 'TIP',             # iShares TIPS ETF (물가연동국채)
    # '하이일드 채권 ETF': 'HYG',      # iShares iBoxx $ 하이일드 회사채 ETF
    '투자등급 회사채 ETF': 'LQD',     # iShares iBoxx $ 투자등급 회사채 ETF
    # '신흥국 채권 ETF': 'EMB',        # iShares JP모건 USD 신흥시장 채권 ETF

    # 환율
    '달러/엔': 'JPY=X',          # 달러/엔 환율
    '달러/위안': 'CNY=X',         # 달러/위안 환율

    # 리츠(부동산) 관련
    '미국 리츠 ETF': 'VNQ',       # Vanguard Real Estate ETF
    # '모기지 리츠 ETF': 'REM',      # iShares Mortgage Real Estate ETF
}

# 나스닥 100 상위 종목 티커 리스트와 한글 이름
nasdaq_top_100 = [
    ("AAPL", "애플"),                      # 1위, 9.50%
    ("MSFT", "마이크로소프트"),            # 3위, 7.67%
    ("AMZN", "아마존"),                    # 4위, 5.80%
    ("GOOGL", "구글 A"),                   # 10위, 2.58%
    ("GOOG", "구글 C"),                    # 11위, 2.48%
    ("META", "메타"),                      # 6위, 3.79%
    ("TSLA", "테슬라"),                    # 8위, 2.76%
    ("NVDA", "엔비디아"),                  # 2위, 7.95%
    ("COST", "코스트코"),                  # 7위, 2.97%
    ("NFLX", "넷플릭스"),                  # 9위, 2.68%
    ("PYPL", "페이팔"),                    # 51위, 0.46%
    ("INTC", "인텔"),                      # 36위, 0.65%
    ("CSCO", "시스코"),                    # 13위, 1.63%
    ("CMCSA", "컴캐스트"),                 # 27위, 0.88%
    ("PEP", "펩시코"),                     # 15위, 1.35%
    ("AMGN", "암젠"),                      # 23위, 1.06%
    ("HON", "허니웰 인터내셔널"),           # 26위, 0.89%
    ("SBUX", "스타벅스"),                  # 28위, 0.84%
    ("MDLZ", "몬델리즈"),                  # 41위, 0.55%
    ("MU", "마이크론"),                    # 35위, 0.67%
    ("AVGO", "브로드컴"),                  # 5위, 4.00%
    ("ADBE", "어도비"),                    # 17위, 1.23%
    ("TXN", "텍사스 인스트루먼트"),        # 19위, 1.14%
    ("AMD", "AMD"),                        # 24위, 1.04%
    ("AMAT", "어플라이드 머티리얼즈")     # 29위, 0.83%
]

# 결과 데이터프레임을 전역 변수로 정의 (초기에는 None)
result_df = None

# yfinance.py에서 가져온 함수
def download_yahoo_chart(symbol, start_date, end_date, interval="1d"):
    """
    Yahoo Finance Chart API를 통해 주어진 symbol의 종가(Close) 시계열을 가져옵니다.
    - symbol: Yahoo Finance 티커 문자열 (예: "^GSPC", "AAPL")
    - start_date: 시작일 (YYYY-MM-DD)
    - end_date: 종료일 (YYYY-MM-DD)
    - interval: "1d", "1wk", "1mo"
    """
    sess = requests.Session()
    sess.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
    })
    
    # 날짜 범위로 변환
    start_dt = datetime.strptime(start_date, '%Y-%m-%d')
    end_dt = datetime.strptime(end_date, '%Y-%m-%d')
    delta = end_dt - start_dt
    
    # 범위 문자열 결정 (차이가 1달 이하이면 1mo, 3달 이하이면 3mo, 6달 이하이면 6mo, 그 이상이면 max)
    if delta.days <= 30:
        range_str = "1mo"
    elif delta.days <= 90:
        range_str = "3mo"
    elif delta.days <= 180:
        range_str = "6mo"
    elif delta.days <= 365:
        range_str = "1y"
    elif delta.days <= 730:
        range_str = "2y"
    elif delta.days <= 1825:
        range_str = "5y"
    else:
        range_str = "max"
    
    url = f"https://query1.finance.yahoo.com/v8/finance/chart/{symbol}"
    params = {
        "range": range_str,
        "interval": interval,
        "includePrePost": "false",
        "events": "div|split"
    }
    
    r = sess.get(url, params=params)
    r.raise_for_status()
    result = r.json().get("chart", {}).get("result", [None])[0]
    if not result:
        raise ValueError(f"No data for symbol: {symbol}")
    
    timestamps = result["timestamp"]
    closes = result["indicators"]["quote"][0]["close"]
    
    # 시작 - 수정된 부분: 날짜만 사용하도록 처리
    # 각 타임스탬프를 datetime으로 변환하고 날짜 부분만 사용
    date_only = [pd.Timestamp.fromtimestamp(ts).date() for ts in timestamps]
    
    # 데이터프레임 생성 시 날짜만 포함하도록 수정
    df = pd.DataFrame({
        "Close": closes
    }, index=pd.DatetimeIndex(date_only))
    
    # 중복된 날짜가 있는 경우 마지막 값만 유지
    if df.index.duplicated().any():
        df = df[~df.index.duplicated(keep='last')]
    # 종료 - 수정된 부분
    
    # 시작일과 종료일 사이의 데이터만 필터링
    df = df[(df.index >= pd.Timestamp(start_date)) & (df.index <= pd.Timestamp(end_date))]
    
    return df

def collect_economic_data(start_date='2006-01-01', end_date=None):
    """
    경제 데이터를 수집하는 메인 함수
    
    Args:
        start_date (str): 데이터 수집 시작 날짜 (YYYY-MM-DD 형식)
        end_date (str, optional): 데이터 수집 종료 날짜. 기본값은 현재 날짜.
    
    Returns:
        pd.DataFrame: 수집된 모든 경제 및 주식 데이터
    """
    global result_df
    
    # end_date가 지정되지 않은 경우 현재 날짜 사용
    if end_date is None:
        end_date = datetime.today().strftime('%Y-%m-%d')
    
    print(f"경제 데이터 수집 시작: {start_date} ~ {end_date}")
    
    # FRED API를 통한 데이터 수집
    print("FRED 경제 지표 수집 중...")
    fred_data_frames = []
    for code, name in fred_indicators.items():
        # 지표별 제공 주기에 따른 요청 주기 설정
        if code in ['FEDFUNDS', 'UMCSENT', 'UNRATE', 'USREC', 'PCE', 'INDPRO',
                    'HOUST', 'UNEMPLOY', 'RSAFS', 'CPIENGSL', 'AHETPI', 'PPIACO', 'CPIAUCSL',
                    'CSUSHPINSA', 'DTWEXM']:
            frequency = 'm'
        elif code in ['STLFSI4', 'M2', 'MORTGAGE30US', 'MORTGAGE15US', 'MORTGAGE5US']:
            frequency = 'w'
        elif code in ['TDSP', 'A939RX0Q048SBEA', 'GDPC1', 'W019RCQ027SBEA', 'DRBLACBS']:
            frequency = 'q'
        else:
            frequency = 'd'
    
        url = f'https://api.stlouisfed.org/fred/series/observations'
        params = {
            'series_id': code,
            'api_key': api_key,
            'file_type': 'json',
            'observation_start': start_date,
            'observation_end': end_date,
            'frequency': frequency
        }
        response = requests.get(url, params=params)
    
        if response.status_code == 200:
            data = response.json().get('observations', [])
            if data:
                df = pd.DataFrame(data)[['date', 'value']]
                df.columns = ['date', name]
                df['date'] = pd.to_datetime(df['date']).dt.tz_localize(None)
                fred_data_frames.append(df.set_index('date'))
            else:
                print(f"No data found for indicator {name} ({code}).")
        else:
            print(f"Failed to fetch data for indicator {name} ({code}): {response.status_code}")
    
    # 데이터 빈도에 따른 리샘플링 처리
    for i, df in enumerate(fred_data_frames):
        if df.empty:
            print(f"DataFrame {i} is empty, skipping resampling.")
            continue
        try:
            inferred_freq = df.index.inferred_freq
            # 빈도에 따라 일간 데이터로 변환
            if inferred_freq in ['M', 'MS']:  # 월간 데이터
                fred_data_frames[i] = df.resample('D').ffill()
            elif inferred_freq in ['W', 'W-FRI']:  # 주간 데이터
                fred_data_frames[i] = df.resample('D').ffill()
            elif inferred_freq in ['Q', 'QS-OCT']:  # 분기 데이터
                fred_data_frames[i] = df.resample('D').ffill()
            elif inferred_freq in ['B']:  # 영업일 데이터
                fred_data_frames[i] = df.resample('D').ffill()
            else:
                fred_data_frames[i] = df.resample('D').ffill()
        except Exception as e:
            print(f"Error processing DataFrame {i}: {e}")
    
    # yfinance를 통한 데이터 수집 (yfinance.py의 방식으로 대체)
    print("\nYahoo Finance 지표 데이터 수집 중...")
    yfinance_data_frames = []
    for name, ticker in yfinance_indicators.items():
        try:
            # download_yahoo_chart 함수를 사용하여 데이터 수집
            df = download_yahoo_chart(ticker, start_date, end_date)
            if not df.empty:
                df.columns = [name]  # 'Close' 컬럼명을 지표 이름으로 변경
                df.index = df.index.tz_localize(None)  # 시간대 정보 제거
                yfinance_data_frames.append(df)
                print(f"{name}({ticker}) 수집 완료, {len(df)}개")
            else:
                print(f"No data found for indicator {name} ({ticker}).")
        except Exception as e:
            print(f"Error downloading data for {ticker} ({name}): {e}")
        # 요청 간 간격을 두어 rate limit 방지
        time.sleep(1)
    
    # 나스닥 100 상위 종목 데이터 수집 (yfinance.py의 방식으로 대체)
    print("\n나스닥 100 상위 종목 데이터 수집 중...")
    nasdaq_data_frames = []
    for ticker, name in nasdaq_top_100:
        try:
            # download_yahoo_chart 함수를 사용하여 데이터 수집
            df = download_yahoo_chart(ticker, start_date, end_date)
            if not df.empty:
                df.columns = [name]  # 'Close' 컬럼명을 종목 한글 이름으로 변경
                df.index = df.index.tz_localize(None)  # 시간대 정보 제거
                nasdaq_data_frames.append(df)
                print(f"{name}({ticker}) 수집 완료, {len(df)}개")
            else:
                print(f"No data found for stock {name} ({ticker}).")
        except Exception as e:
            print(f"Error downloading data for {ticker} ({name}): {e}")
        # 요청 간 간격을 두어 rate limit 방지
        time.sleep(1)
    
    # 모든 데이터를 날짜 기준으로 외부 결합하여 하나의 데이터프레임으로 결합
    all_data_frames = fred_data_frames + yfinance_data_frames + nasdaq_data_frames
    if all_data_frames:
        # 중복된 인덱스 처리
        for i, df in enumerate(all_data_frames):
            if df.index.duplicated().any():
                all_data_frames[i] = df[~df.index.duplicated(keep='first')]
        
        # 결합
        print("데이터프레임 병합 중...")
        result_df = pd.concat(all_data_frames, axis=1, join='outer')
    
        # 결측치 및 비정상적인 값 처리
        result_df.replace('.', pd.NA, inplace=True)
        
        # 결측치를 이전 값으로 채움
        result_df.sort_index(inplace=True)
        result_df.ffill(inplace=True)
        
        # 주요 수정: 날짜 인덱스의 시간 부분을 제거하고 일자만 남김
        # 동일 날짜의 데이터가 여러 개 있는 경우, 마지막 데이터만 사용
        print("날짜 인덱스 표준화 중...")
        result_df.index = pd.to_datetime(result_df.index.date)  # 날짜만 남김
        result_df = result_df[~result_df.index.duplicated(keep='last')]  # 중복 날짜 제거, 마지막 값 유지
        
        # 결과 데이터프레임 로그 출력
        print("\n=== 결과 데이터프레임 정보 ===")
        print(f"행 수: {len(result_df)}")
        print(f"열 수: {len(result_df.columns)}")
        print("컬럼 목록:")
        for col in result_df.columns:
            print(f"  - {col}")
        
        print("\n=== 결과 데이터프레임 처음 5행 ===")
        print(result_df.head())
        
        print("\n=== 결과 데이터프레임 마지막 5행 ===")
        print(result_df.tail())
        
        print(f"\n데이터 수집 완료")
        return result_df
    else:
        print("No data collected for any indicators.")
        return None

# 스크립트가 직접 실행될 때만 데이터 수집 진행
if __name__ == "__main__":
    result_df = collect_economic_data()
    # 필요한 경우 CSV로 저장
    # result_df.to_csv('total.csv', index_label="날짜", encoding='utf-8-sig')
import requests
import pandas as pd
import yfinance as yf
from datetime import datetime, timedelta
import numpy as np
import time



# FRED API Key 설정
api_key = 'fred api key를 설정해주세요.'

# FRED에서 제공하는 지표 코드와 명칭
fred_indicators = {
    'T10YIE': '10년 기대 인플레이션율',  # 10년 만기 기대 인플레이션율 (일간)
    'T10Y2Y': '장단기 금리차',  # 10년-2년 국채 수익률 스프레드 (일간)
    'FEDFUNDS': '기준금리',  # 연방기금 금리 (월간)
    'UMCSENT': '미시간대 소비자 심리지수',  # 소비자 신뢰 지수 (월간)
    'UNRATE': '실업률',  # 실업률 (월간)
    # 'USREC': '경기침체',  # 경기침체 지수 (월간) --> 장단기 금리차를 통해 확인 가능.
    'DGS2': '2년 만기 미국 국채 수익률',  # 2년 만기 국채 수익률 (일간)
    'DGS10': '10년 만기 미국 국채 수익률',  # 10년 만기 국채 수익률 (일간)

    # 추가 지표
    'STLFSI4': '금융스트레스지수',  # 금융 스트레스 지수 (주간)
    'PCE': '개인 소비 지출',  # 개인 소비 지출 (월간) -> 소비자물가지수(CPI)나 GDP, 실업률, 인플레이션 기대 등 다른 핵심 지표가 이미 전반적 경기 상황을 반영.
    # 'INDPRO': '산업생산',  # 산업 생산 지수 (월간)
    # 'HOUST': '주택 착공',  # 신규 주택 착공 건수 (월간)
    # 'UNEMPLOY': '실업자수',  # 실업자의 총 수 (월간)
    # 'RSAFS': '소매판매',  # 소매판매 지수 (월간)
    # 'CPIENGSL': '에너지 가격 지수',  # 소비자 물가지수 중 에너지 부문 (월간) -> 소비자물가지수(CPI)나 GDP, 실업률, 인플레이션 기대 등 다른 핵심 지표가 이미 전반적 경기 상황을 반영.
    # 'AHETPI': '임금 성장률',  # 시간당 평균 임금 성장률 (월간)
    # 'PPIACO': '농산물 가격 지수',  # 생산자 물가지수 중 농산물 부문 (월간)
    'CPIAUCSL': '소비자 물가지수',  # 전체 소비자 물가지수 (월간)
    # 'CSUSHPINSA': '주택가격지수',  # 케이스-실러 주택 가격 지수 (월간) -> 5년 변동금리 모기지 (MORTGAGE5US): 부동산 시장이 대상 종목(빅테크) 주가 변동에 단기적으로 큰 영향 미치는지 불분명. 단기간(1주일 후) 예측에서는 영향력 제한적.
    # 'MORTGAGE30US': '30년 고정금리 모기지',  # 30년 만기 고정금리 모기지 금리 (주간)
    # 'MORTGAGE15US': '15년 고정금리 모기지',  # 15년 만기 고정금리 모기지 금리 (주간)
    'MORTGAGE5US': '5년 변동금리 모기지',  # 5년 변동금리 모기지 금리 (주간)
    'DTWEXM': '미국 달러 환율',  # 미국 무역가중 환율 (월간)
    'M2': '통화 공급량 M2',  # M2 통화 공급량 (주간) -> FEDFUNDS나 금리 동향, 달러 인덱스, 금융스트레스지수가 이미 유동성 상황을 대략 파악 가능.
    # 'TEDRATE': 'TED 스프레드',  # 3개월 만기 미국 국채와 유로달러 금리 스프레드 (일간) -> FEDFUNDS나 금리 동향, 달러 인덱스, 금융스트레스지수가 이미 유동성 상황을 대략 파악 가능.
    # 'BAMLH0A0HYM2': '미국 하이일드 채권 스프레드',  # 미국 하이일드 채권과 국채 스프레드 (일간) -> 금융시장 신용위험을 반영하지만, 이미 금융스트레스지수(STLFSI4), 장단기금리차, VIX 등의 지표로 대략적인 위험 선호도나 스트레스 상황 파악 가능.
    # 'BAMLC0A0CM': '미국 회사채 스프레드',  # 미국 회사채와 국채 스프레드 (일간)
    # 'BAMLCC0A0CMTRIV': '미국 회사채 수익률',  # 미국 회사채 수익률 (일간)
    # 'BAMLCC0A1AAATRIV': '미국 회사채 AAA등급 수익률',  # AAA등급 회사채 수익률 (일간)
    # 'BAMLCC0A4BBBTRIV': '미국 회사채 BBB등급 수익률',  # BBB등급 회사채 수익률 (일간)
    # 'BAMLHYH0A0HYM2TRIV': '미국 하이일드 채권 수익률',  # 하이일드 채권 수익률 (일간)
    # 'BAMLHYH0A3CMTRIV': '미국 하이일드 채권 CCC등급 수익률',  # CCC등급 하이일드 채권 수익률 (일간)
    # 'BAMLHE00EHYIEY': '미국 하이일드 채권 기대수익률',  # 하이일드 채권 기대수익률 (일간)

    'TDSP': '가계 부채 비율',  # 가계의 부채 상환 비율을 나타냄 (분기)
    # 'A939RX0Q048SBEA': '실질 GDP 성장률',  # 계절 조정된 연간 실질 GDP 성장률 (분기)
    'GDPC1': 'GDP 성장률',  # 실질 국내총생산 성장률, 물가 조정을 반영 (분기)
    # 'W019RCQ027SBEA': '정부 지출',  # 정부의 총 지출 금액 (분기)
    # 'DRBLACBS': '대출 연체율',  # 기업 대출의 연체율 (분기)

    # 주식시장 관련 추가 지표
    # 'DJIA': '다우존스 산업평균지수',  # 미국 대형 30개 기업의 주가 평균 (일간)
    'NASDAQCOM': '나스닥 종합지수'  # 나스닥 시장 전체 종합 주가 지수 (일간)
}


# Yahoo Finance에서 제공하는 지표와 티커
yfinance_indicators = {
    'S&P 500 지수': '^GSPC',    # S&P 500 지수
    '금 가격': 'GC=F',           # 금 가격 (선물)
    '달러 인덱스': 'DX-Y.NYB',    # 달러 인덱스

    # 추가 지표
    '나스닥 100': '^NDX',           # 나스닥 100 지수
    'S&P 500 ETF': 'SPY',           # S&P 500 추종 ETF
    'QQQ ETF': 'QQQ',               # 나스닥 100 추종 ETF
    '러셀 2000 ETF': 'IWM',         # 러셀 2000 추종 ETF
    '다우 존스 ETF': 'DIA',          # 다우 존스 추종 ETF
    # 'NYSE FANG+ 지수': '^NYFANG'   # NYSE FANG+ 지수
    'VIX 지수': '^VIX',          # ^VIX (변동성 지수, 공포 지수): S&P 500 옵션 가격을 기반으로 앞으로의 시장 변동성 기대치를 반영해 시장 심리를 나타내는 지표.

    # 글로벌 지수
    '닛케이 225': '^N225',          # 일본 닛케이 225 지수
    '상해종합': '000001.SS',        # 중국 상해종합지수
    '항셍': '^HSI',                # 홍콩 항셍지수
    # '유로스톡스 50': '^STOXX50E',   # 유럽 유로스톡스 50 지수
    '영국 FTSE': '^FTSE',          # 영국 FTSE 100 지수
    '독일 DAX': '^GDAXI',          # 독일 DAX 지수
    '프랑스 CAC 40': '^FCHI',       # 프랑스 CAC 40 지수

    '미국 전체 채권시장 ETF': 'AGG',  # iShares 핵심 미국 전체 채권 ETF
    'TIPS ETF': 'TIP',             # iShares TIPS ETF (물가연동국채)
    # '하이일드 채권 ETF': 'HYG',      # iShares iBoxx $ 하이일드 회사채 ETF
    '투자등급 회사채 ETF': 'LQD',     # iShares iBoxx $ 투자등급 회사채 ETF
    # '신흥국 채권 ETF': 'EMB',        # iShares JP모건 USD 신흥시장 채권 ETF

    # 환율
    '달러/엔': 'JPY=X',          # 달러/엔 환율
    '달러/위안': 'CNY=X',         # 달러/위안 환율

    # 리츠(부동산) 관련
    '미국 리츠 ETF': 'VNQ',       # Vanguard Real Estate ETF
    # '모기지 리츠 ETF': 'REM',      # iShares Mortgage Real Estate ETF
}

# 나스닥 100 상위 종목 티커 리스트와 한글 이름
nasdaq_top_100 = [
    ("AAPL", "애플"),                      # 1위, 9.50%
    ("MSFT", "마이크로소프트"),            # 3위, 7.67%
    ("AMZN", "아마존"),                    # 4위, 5.80%
    ("GOOGL", "구글 A"),                   # 10위, 2.58%
    ("GOOG", "구글 C"),                    # 11위, 2.48%
    ("META", "메타"),                      # 6위, 3.79%
    ("TSLA", "테슬라"),                    # 8위, 2.76%
    ("NVDA", "엔비디아"),                  # 2위, 7.95%
    ("COST", "코스트코"),                  # 7위, 2.97%
    ("NFLX", "넷플릭스"),                  # 9위, 2.68%
    ("PYPL", "페이팔"),                    # 51위, 0.46%
    ("INTC", "인텔"),                      # 36위, 0.65%
    ("CSCO", "시스코"),                    # 13위, 1.63%
    ("CMCSA", "컴캐스트"),                 # 27위, 0.88%
    ("PEP", "펩시코"),                     # 15위, 1.35%
    ("AMGN", "암젠"),                      # 23위, 1.06%
    ("HON", "허니웰 인터내셔널"),           # 26위, 0.89%
    ("SBUX", "스타벅스"),                  # 28위, 0.84%
    ("MDLZ", "몬델리즈"),                  # 41위, 0.55%
    ("MU", "마이크론"),                    # 35위, 0.67%
    ("AVGO", "브로드컴"),                  # 5위, 4.00%
    ("ADBE", "어도비"),                    # 17위, 1.23%
    ("TXN", "텍사스 인스트루먼트"),        # 19위, 1.14%
    ("AMD", "AMD"),                        # 24위, 1.04%
    ("AMAT", "어플라이드 머티리얼즈")     # 29위, 0.83%
]

# 결과 데이터프레임을 전역 변수로 정의 (초기에는 None)
result_df = None

# yfinance.py에서 가져온 함수
def download_yahoo_chart(symbol, start_date, end_date, interval="1d"):
    """
    Yahoo Finance Chart API를 통해 주어진 symbol의 종가(Close) 시계열을 가져옵니다.
    - symbol: Yahoo Finance 티커 문자열 (예: "^GSPC", "AAPL")
    - start_date: 시작일 (YYYY-MM-DD)
    - end_date: 종료일 (YYYY-MM-DD)
    - interval: "1d", "1wk", "1mo"
    """
    sess = requests.Session()
    sess.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
    })
    
    # 날짜 범위로 변환
    start_dt = datetime.strptime(start_date, '%Y-%m-%d')
    end_dt = datetime.strptime(end_date, '%Y-%m-%d')
    delta = end_dt - start_dt
    
    # 범위 문자열 결정 (차이가 1달 이하이면 1mo, 3달 이하이면 3mo, 6달 이하이면 6mo, 그 이상이면 max)
    if delta.days <= 30:
        range_str = "1mo"
    elif delta.days <= 90:
        range_str = "3mo"
    elif delta.days <= 180:
        range_str = "6mo"
    elif delta.days <= 365:
        range_str = "1y"
    elif delta.days <= 730:
        range_str = "2y"
    elif delta.days <= 1825:
        range_str = "5y"
    else:
        range_str = "max"
    
    url = f"https://query1.finance.yahoo.com/v8/finance/chart/{symbol}"
    params = {
        "range": range_str,
        "interval": interval,
        "includePrePost": "false",
        "events": "div|split"
    }
    
    r = sess.get(url, params=params)
    r.raise_for_status()
    result = r.json().get("chart", {}).get("result", [None])[0]
    if not result:
        raise ValueError(f"No data for symbol: {symbol}")
    
    timestamps = result["timestamp"]
    closes = result["indicators"]["quote"][0]["close"]
    
    # 시작 - 수정된 부분: 날짜만 사용하도록 처리
    # 각 타임스탬프를 datetime으로 변환하고 날짜 부분만 사용
    date_only = [pd.Timestamp.fromtimestamp(ts).date() for ts in timestamps]
    
    # 데이터프레임 생성 시 날짜만 포함하도록 수정
    df = pd.DataFrame({
        "Close": closes
    }, index=pd.DatetimeIndex(date_only))
    
    # 중복된 날짜가 있는 경우 마지막 값만 유지
    if df.index.duplicated().any():
        df = df[~df.index.duplicated(keep='last')]
    # 종료 - 수정된 부분
    
    # 시작일과 종료일 사이의 데이터만 필터링
    df = df[(df.index >= pd.Timestamp(start_date)) & (df.index <= pd.Timestamp(end_date))]
    
    return df

def collect_economic_data(start_date='2006-01-01', end_date=None):
    """
    경제 데이터를 수집하는 메인 함수
    
    Args:
        start_date (str): 데이터 수집 시작 날짜 (YYYY-MM-DD 형식)
        end_date (str, optional): 데이터 수집 종료 날짜. 기본값은 현재 날짜.
    
    Returns:
        pd.DataFrame: 수집된 모든 경제 및 주식 데이터
    """
    global result_df
    
    # end_date가 지정되지 않은 경우 현재 날짜 사용
    if end_date is None:
        end_date = datetime.today().strftime('%Y-%m-%d')
    
    print(f"경제 데이터 수집 시작: {start_date} ~ {end_date}")
    
    # FRED API를 통한 데이터 수집
    print("FRED 경제 지표 수집 중...")
    fred_data_frames = []
    for code, name in fred_indicators.items():
        # 지표별 제공 주기에 따른 요청 주기 설정
        if code in ['FEDFUNDS', 'UMCSENT', 'UNRATE', 'USREC', 'PCE', 'INDPRO',
                    'HOUST', 'UNEMPLOY', 'RSAFS', 'CPIENGSL', 'AHETPI', 'PPIACO', 'CPIAUCSL',
                    'CSUSHPINSA', 'DTWEXM']:
            frequency = 'm'
        elif code in ['STLFSI4', 'M2', 'MORTGAGE30US', 'MORTGAGE15US', 'MORTGAGE5US']:
            frequency = 'w'
        elif code in ['TDSP', 'A939RX0Q048SBEA', 'GDPC1', 'W019RCQ027SBEA', 'DRBLACBS']:
            frequency = 'q'
        else:
            frequency = 'd'
    
        url = f'https://api.stlouisfed.org/fred/series/observations'
        params = {
            'series_id': code,
            'api_key': api_key,
            'file_type': 'json',
            'observation_start': start_date,
            'observation_end': end_date,
            'frequency': frequency
        }
        response = requests.get(url, params=params)
    
        if response.status_code == 200:
            data = response.json().get('observations', [])
            if data:
                df = pd.DataFrame(data)[['date', 'value']]
                df.columns = ['date', name]
                df['date'] = pd.to_datetime(df['date']).dt.tz_localize(None)
                fred_data_frames.append(df.set_index('date'))
            else:
                print(f"No data found for indicator {name} ({code}).")
        else:
            print(f"Failed to fetch data for indicator {name} ({code}): {response.status_code}")
    
    # 데이터 빈도에 따른 리샘플링 처리
    for i, df in enumerate(fred_data_frames):
        if df.empty:
            print(f"DataFrame {i} is empty, skipping resampling.")
            continue
        try:
            inferred_freq = df.index.inferred_freq
            # 빈도에 따라 일간 데이터로 변환
            if inferred_freq in ['M', 'MS']:  # 월간 데이터
                fred_data_frames[i] = df.resample('D').ffill()
            elif inferred_freq in ['W', 'W-FRI']:  # 주간 데이터
                fred_data_frames[i] = df.resample('D').ffill()
            elif inferred_freq in ['Q', 'QS-OCT']:  # 분기 데이터
                fred_data_frames[i] = df.resample('D').ffill()
            elif inferred_freq in ['B']:  # 영업일 데이터
                fred_data_frames[i] = df.resample('D').ffill()
            else:
                fred_data_frames[i] = df.resample('D').ffill()
        except Exception as e:
            print(f"Error processing DataFrame {i}: {e}")
    
    # yfinance를 통한 데이터 수집 (yfinance.py의 방식으로 대체)
    print("\nYahoo Finance 지표 데이터 수집 중...")
    yfinance_data_frames = []
    for name, ticker in yfinance_indicators.items():
        try:
            # download_yahoo_chart 함수를 사용하여 데이터 수집
            df = download_yahoo_chart(ticker, start_date, end_date)
            if not df.empty:
                df.columns = [name]  # 'Close' 컬럼명을 지표 이름으로 변경
                df.index = df.index.tz_localize(None)  # 시간대 정보 제거
                yfinance_data_frames.append(df)
                print(f"{name}({ticker}) 수집 완료, {len(df)}개")
            else:
                print(f"No data found for indicator {name} ({ticker}).")
        except Exception as e:
            print(f"Error downloading data for {ticker} ({name}): {e}")
        # 요청 간 간격을 두어 rate limit 방지
        time.sleep(1)
    
    # 나스닥 100 상위 종목 데이터 수집 (yfinance.py의 방식으로 대체)
    print("\n나스닥 100 상위 종목 데이터 수집 중...")
    nasdaq_data_frames = []
    for ticker, name in nasdaq_top_100:
        try:
            # download_yahoo_chart 함수를 사용하여 데이터 수집
            df = download_yahoo_chart(ticker, start_date, end_date)
            if not df.empty:
                df.columns = [name]  # 'Close' 컬럼명을 종목 한글 이름으로 변경
                df.index = df.index.tz_localize(None)  # 시간대 정보 제거
                nasdaq_data_frames.append(df)
                print(f"{name}({ticker}) 수집 완료, {len(df)}개")
            else:
                print(f"No data found for stock {name} ({ticker}).")
        except Exception as e:
            print(f"Error downloading data for {ticker} ({name}): {e}")
        # 요청 간 간격을 두어 rate limit 방지
        time.sleep(1)
    
    # 모든 데이터를 날짜 기준으로 외부 결합하여 하나의 데이터프레임으로 결합
    all_data_frames = fred_data_frames + yfinance_data_frames + nasdaq_data_frames
    if all_data_frames:
        # 중복된 인덱스 처리
        for i, df in enumerate(all_data_frames):
            if df.index.duplicated().any():
                all_data_frames[i] = df[~df.index.duplicated(keep='first')]
        
        # 결합
        print("데이터프레임 병합 중...")
        result_df = pd.concat(all_data_frames, axis=1, join='outer')
    
        # 결측치 및 비정상적인 값 처리
        result_df.replace('.', pd.NA, inplace=True)
        
        # 결측치를 이전 값으로 채움
        result_df.sort_index(inplace=True)
        result_df.ffill(inplace=True)
        
        # 주요 수정: 날짜 인덱스의 시간 부분을 제거하고 일자만 남김
        # 동일 날짜의 데이터가 여러 개 있는 경우, 마지막 데이터만 사용
        print("날짜 인덱스 표준화 중...")
        result_df.index = pd.to_datetime(result_df.index.date)  # 날짜만 남김
        result_df = result_df[~result_df.index.duplicated(keep='last')]  # 중복 날짜 제거, 마지막 값 유지
        
        # 결과 데이터프레임 로그 출력
        print("\n=== 결과 데이터프레임 정보 ===")
        print(f"행 수: {len(result_df)}")
        print(f"열 수: {len(result_df.columns)}")
        print("컬럼 목록:")
        for col in result_df.columns:
            print(f"  - {col}")
        
        print("\n=== 결과 데이터프레임 처음 5행 ===")
        print(result_df.head())
        
        print("\n=== 결과 데이터프레임 마지막 5행 ===")
        print(result_df.tail())
        
        print(f"\n데이터 수집 완료")
        return result_df
    else:
        print("No data collected for any indicators.")
        return None

# 스크립트가 직접 실행될 때만 데이터 수집 진행
if __name__ == "__main__":
    result_df = collect_economic_data()
    # 필요한 경우 CSV로 저장
    # result_df.to_csv('total.csv', index_label="날짜", encoding='utf-8-sig')

0

wltjq님의 프로필 이미지
wltjq
질문자

커서 ai 클로드-4-소넷한테 물어봐서 해결했습니다 yfinance 라이브러리 문제가 아니고 stock.py 코드 로직 문제였습니다 아래는 커서 ai 답변 입니다
수정해야 할 부분

우선순위 1: stock.pydownload_yahoo_chart 함수 수정

이 함수가 제대로 작동하지 않아서 모든 날짜에 빈 데이터가 반환되고, economic_service.py의 이전 데이터 채우기 로직이 계속 동작하고 있습니다.

stock.py의 189번 라인 근처에 문제가 있을 것 같습니다. 확인해보겠습니다:

Read stock.py and thought for 5s

문제를 찾았습니다! stock.pydownload_yahoo_chart 함수에서 날짜 필터링 부분에 문제가 있습니다.

Yahoo Finance API가 2019년 데이터를 요청했는데 2025년 최신 데이터를 반환하고 있습니다!

🔧 문제 원인 및 해결 방안

stock.py의 Yahoo Finance API 호출 방식이 잘못되었습니다. range: max는 최신 데이터만 반환하므로 과거 특정 기간 데이터를 가져오려면 period1, period2 파라미터를 사용해야 합니다.

stock.py 코드에서 download_yahoo_chart 함수 부분을 아래와 같이 수정해서 해결 했습니다

# yfinance.py에서 가져온 함수
def download_yahoo_chart(symbol, start_date, end_date, interval="1d"):
    """
    Yahoo Finance Chart API를 통해 주어진 symbol의 종가(Close) 시계열을 가져옵니다.
    - symbol: Yahoo Finance 티커 문자열 (예: "^GSPC", "AAPL")
    - start_date: 시작일 (YYYY-MM-DD)
    - end_date: 종료일 (YYYY-MM-DD)
    - interval: "1d", "1wk", "1mo"
    """
    sess = requests.Session()
    sess.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)"
    })
    
    # 날짜를 Unix 타임스탬프로 변환
    start_dt = datetime.strptime(start_date, '%Y-%m-%d')
    end_dt = datetime.strptime(end_date, '%Y-%m-%d')
    
    # 하루 더 추가하여 종료일 포함
    end_dt = end_dt + timedelta(days=1)
    
    start_timestamp = int(start_dt.timestamp())
    end_timestamp = int(end_dt.timestamp())
    
    url = f"https://query1.finance.yahoo.com/v8/finance/chart/{symbol}"
    params = {
        "period1": start_timestamp,
        "period2": end_timestamp,
        "interval": interval,
        "includePrePost": "false",
        "events": "div|split"
    }
    
    r = sess.get(url, params=params)
    r.raise_for_status()
    result = r.json().get("chart", {}).get("result", [None])[0]
    if not result:
        raise ValueError(f"No data for symbol: {symbol}")
    
    timestamps = result["timestamp"]
    closes = result["indicators"]["quote"][0]["close"]
    
    # 시작 - 수정된 부분: 날짜만 사용하도록 처리
    # 각 타임스탬프를 datetime으로 변환하고 날짜 부분만 사용
    date_only = [pd.Timestamp.fromtimestamp(ts).date() for ts in timestamps]
    
    # 데이터프레임 생성 시 날짜만 포함하도록 수정
    df = pd.DataFrame({
        "Close": closes
    }, index=pd.DatetimeIndex(date_only))
    
    # 중복된 날짜가 있는 경우 마지막 값만 유지
    if df.index.duplicated().any():
        df = df[~df.index.duplicated(keep='last')]
    # 종료 - 수정된 부분
    
    # 시작일과 종료일 사이의 데이터만 필터링
    df = df[(df.index >= pd.Timestamp(start_date)) & (df.index <= pd.Timestamp(end_date))]
    
    return df

0

안녕하세요, 인프런 AI 인턴입니다. wltjq님.

주가 데이터 수집 과정에서의 문제점을 이해하고 계시며, 특히 데이터의 중복 저장과 불일치가 발생하는 점에 대해 말씀해 주셨습니다. 이 문제는 주로 데이터를 수집하는 과정에서 사용되는 API나 라이브러리의 변경 사항, 또는 데이터베이스 저장 과정에서의 논리적 오류 때문에 발생할 수 있습니다.

  1. YFinance 라이브러리 문제: YFinance 라이브러리는 Yahoo Finance의 데이터를 수집하는데, 간혹 Yahoo Finance의 업데이트나 제한 사항 등으로 인해 데이터 불일치가 발생할 수 있습니다. yfinance 라이브러리의 최신 버전 또는 관련 이슈가 있는지 공식 GitHub 저장소에서 확인해 보시는 것을 추천드립니다.

  2. 데이터 중복 및 불일치 문제 해결: 데이터가 중복되거나 불일치가 발생하는 경우, 저장 전 데이터 정리 작업이 필요할 수 있습니다. 특정 날짜에 대한 데이터를 수집하기 전, 기존의 중복 데이터나 잘못된 데이터를 삭제하는 과정이 필요할 수 있습니다. 또한 수집한 데이터를 데이터베이스에 저장할 때, primary key로 날짜를 설정하여 중복을 방지하도록 설정할 수도 있습니다.

  3. 강의 내용 확인: 강의에서 제공된 코드와 스크립트가 현재 시점에서도 동일하게 작동할 수 있도록 yfinance 라이브러리 외에 supabase에서 데이터를 어떻게 저장하고 관리하는지를 조금 더 면밀히 살펴보십시오. 강의에서 구체적으로 다루는 데이터 수집 및 저장 로직을 점검해 보실 것을 권장합니다.

지식공유자님께서 이와 관련하여 추가적인 답변이나 업데이트를 제공해 주실 수 있습니다. 그리고 다른 사용자들의 추가적인 질문 및 답변도 함께 참조해 보시는 것이 좋겠습니다.

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다. 현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏 추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

wltjq님의 프로필 이미지
wltjq

작성한 질문수

질문하기