Skip to content

블로그

ETF 상관계수만으로 분산효과를 판단하면 안 되는 이유

서로 다른 자산의 움직임과 상관관계를 표현한 연구 공간

ETF를 여러 개 담으면 포트폴리오가 자동으로 안전해질까요? 흔히 ETF 사이의 상관계수가 낮으면 분산효과가 크다고 설명합니다. 방향은 맞지만, 상관계수 하나만으로 실제 위험을 판단하기에는 부족합니다. 평소에는 서로 다르게 움직이던 자산도 시장 충격이 발생하면 함께 하락할 수 있기 때문입니다.

이 글에서는 상관계수의 의미와 한계를 살펴보고, ETF 포트폴리오를 구성할 때 함께 확인해야 할 지표를 정리합니다.

두 ETF의 수익률을 , 라고 할 때 피어슨 상관계수는 다음과 같이 계산합니다.

값이 1에 가까우면 같은 방향으로, -1에 가까우면 반대 방향으로 움직이는 경향이 있다는 뜻입니다. 0에 가까우면 선형적인 동조화가 뚜렷하지 않습니다.

문제는 이 값이 어떤 기간과 수익률 간격을 사용했는지에 따라 달라진다는 점입니다. 일간 수익률로 계산한 상관계수와 월간 수익률로 계산한 상관계수는 서로 다를 수 있습니다. 상승장, 하락장, 금리 변동기처럼 시장 국면을 나누면 결과가 더 크게 달라질 수 있습니다.

낮은 상관계수가 항상 낮은 위험은 아니다

Section titled “낮은 상관계수가 항상 낮은 위험은 아니다”

포트폴리오의 분산은 각 자산의 변동성과 자산 사이의 공분산에 의해 결정됩니다.

따라서 상관계수는 중요한 요소이지만 전체가 아닙니다. 상관계수가 낮아도 한 자산의 변동성이 매우 크면 포트폴리오 위험이 커질 수 있습니다. 반대로 상관계수가 다소 높더라도 변동성이 낮고 비중이 적절하면 전체 변동성을 완화할 수 있습니다.

예를 들어 주식 ETF와 원자재 ETF를 섞었다고 해도, 두 상품의 가격 변동폭과 환율 민감도가 크게 다르면 단순 상관계수만으로 체감 위험을 설명하기 어렵습니다. ETF의 기초자산뿐 아니라 환헤지 여부, 선물 롤오버, 분배금 정책도 함께 봐야 합니다.

위기 때 상관관계가 높아지는 현상

Section titled “위기 때 상관관계가 높아지는 현상”

평상시에는 서로 다른 자산군으로 보이던 상품이 급락장에서 동시에 하락하는 현상을 흔히 관찰할 수 있습니다. 투자자가 위험자산을 한꺼번에 줄이거나, 유동성이 낮은 자산부터 매도하기 때문입니다.

이런 현상을 확인하려면 전체 기간의 상관계수 하나보다 다음 결과를 나누어 보는 편이 낫습니다.

  • 전체 기간의 상관계수
  • 하락한 날만 추린 하방 상관계수
  • 최근 60일 또는 120일 이동 상관계수
  • 두 ETF가 같은 날 손실을 기록한 비율
  • 포트폴리오의 최대낙폭과 회복 기간

특히 하방 상관계수가 전체 상관계수보다 높다면, 평소에는 분산되어 보여도 손실이 커지는 시점에 함께 움직일 가능성을 경계해야 합니다.

ETF 분산효과를 확인하는 실전 순서

Section titled “ETF 분산효과를 확인하는 실전 순서”

먼저 비교할 ETF의 총수익률 기준을 통일해야 합니다. 분배금을 제외한 가격 수익률만 비교하면 실제 투자자가 경험하는 결과와 차이가 생길 수 있습니다. 그다음 동일한 기간과 빈도의 수익률로 상관계수와 변동성을 계산합니다.

returns = prices.pct_change().dropna()
summary = returns[['etf_a', 'etf_b', 'etf_c']].agg(['mean', 'std'])
correlation = returns[['etf_a', 'etf_b', 'etf_c']].corr()
downside_correlation = returns[returns[['etf_a', 'etf_b', 'etf_c']].min(axis=1) < 0].corr()

마지막으로 동일한 비중을 가정한 포트폴리오 수익률을 계산하고, 월별 또는 분기별 리밸런싱을 적용해 결과가 어떻게 바뀌는지 확인합니다. 상관계수가 낮더라도 한 상품이 계속 상승해 비중이 커지면, 시간이 지나면서 포트폴리오의 위험 구조가 달라질 수 있습니다.

상관계수 외에 확인할 체크리스트

Section titled “상관계수 외에 확인할 체크리스트”
  • 기초자산과 지역이 실제로 얼마나 겹치는가
  • 상위 보유종목의 중복 비중은 얼마인가
  • 환율과 환헤지 여부가 성과에 어떤 영향을 주는가
  • 하락장에서 동시 손실 빈도는 어느 정도인가
  • 최대낙폭과 회복 기간이 감당 가능한 수준인가
  • 거래량과 스프레드가 리밸런싱 비용을 키우지 않는가

ETF 이름이 다르거나 운용사가 달라도 상위 보유종목이 비슷하면 실질적인 분산효과는 작을 수 있습니다. 반대로 상관계수가 낮아 보이는 상품도 구조가 복잡하거나 거래비용이 크면 장기 보유에 적합하지 않을 수 있습니다.

상관계수는 ETF 포트폴리오를 분석하는 좋은 출발점이지만, 분산효과의 최종 답은 아닙니다. 기간과 수익률 빈도를 바꾸어도 결과가 유지되는지 확인하고, 하락장 상관관계·변동성·최대낙폭·보유종목 중복도를 함께 살펴야 합니다.

좋은 분산 포트폴리오는 단순히 서로 다른 이름의 ETF를 모은 포트폴리오가 아닙니다. 손실이 커지는 국면에서 위험이 어떻게 겹치는지 설명할 수 있는 포트폴리오에 가깝습니다.

이 글은 ETF와 포트폴리오 분석 방법을 설명하기 위한 자료이며, 특정 상품의 매수·매도를 권유하지 않습니다.

방산주는 왜 장기 성장주로 평가받는가

항공우주 생산시설과 방산 산업의 장기 성장을 표현한 이미지

방산주는 국제 정세가 불안해질 때마다 주목받는 테마주로 소개되곤 합니다. 그러나 방산 기업을 단순히 뉴스에 반응하는 종목으로만 보면 산업의 구조적 변화를 놓칠 수 있습니다. 국방 예산의 장기 계획, 무기체계 교체 주기, 수출 계약, 유지보수 사업이 서로 연결되면서 방산은 긴 시간 동안 매출이 누적되는 산업이기 때문입니다.

이 글에서는 한화에어로스페이스와 한국항공우주를 대표 사례로 삼아, 방산주를 장기 성장주 관점에서 볼 때 확인해야 할 요소를 정리합니다. 특정 종목의 매수·매도를 권유하는 글은 아닙니다.

방산 산업의 매출은 한 번의 계약으로 끝나지 않는다

Section titled “방산 산업의 매출은 한 번의 계약으로 끝나지 않는다”

방산 사업은 일반 소비재처럼 매년 수요가 반복되는 구조와 다릅니다. 먼저 무기체계 도입 계약이 체결되고, 이후 생산·납품·정비·부품 교체·성능 개량이 이어집니다. 하나의 플랫폼이 장기간 운용되기 때문에 초기 수주뿐 아니라 후속 지원 사업도 중요한 매출원이 됩니다.

이 구조를 단순화하면 방산 기업의 매출은 다음과 같이 나눌 수 있습니다.

구분주요 내용투자자가 볼 지표
신규 수주전차, 자주포, 항공기, 엔진 등 신규 계약수주잔고, 계약 기간
생산·납품계약 물량을 실제 매출로 전환매출 인식 속도, 원가율
후속 지원정비, 부품, 개량, 교육·훈련반복 매출, 수익성
수출 확대해외 고객과 추가 국가 진입수출 비중, 환율, 현지 생산

따라서 보도된 계약 금액만 보고 기업가치를 판단하기보다 수주잔고가 몇 년에 걸쳐 매출과 영업현금흐름으로 전환되는지 확인해야 합니다.

수출이 장기 성장의 핵심인 이유

Section titled “수출이 장기 성장의 핵심인 이유”

국내 방산 기업의 성장성은 국내 국방 예산만으로 결정되지 않습니다. 해외 수출이 늘어나면 고객 국가가 다양해지고 생산 규모가 커지면서 단위당 비용과 공급망 효율이 개선될 가능성이 있습니다. 동시에 수출 계약은 환율, 금융 조건, 현지 생산 의무, 기술 이전 조건의 영향을 받습니다.

수출 비중이 커지는 기업을 볼 때는 다음 질문이 필요합니다.

  • 수출 계약이 실제 납품 단계에 진입했나요?
  • 계약의 수익성이 국내 사업과 비교해 어떤가요?
  • 현지 조립·생산 조건이 원가에 어떤 영향을 주나요?
  • 환율 변동과 원자재 가격 상승을 계약이 얼마나 흡수하나요?
  • 한 국가 또는 한 플랫폼에 대한 의존도가 과도하지 않나요?

수출 계약은 성장 동력이 될 수 있지만, 계약 체결과 이익 실현 사이에 시간이 길다는 점도 함께 고려해야 합니다.

한화에어로스페이스(012450)는 지상방산과 항공엔진 등 여러 사업 축을 보유한 기업으로 분류할 수 있습니다. 이 기업을 분석할 때는 지상 무기체계의 수주잔고뿐 아니라 엔진 사업의 장기 공급 구조, 계열사 및 연결 실적, 대규모 계약의 생산 일정까지 함께 봐야 합니다.

한국항공우주(047810)는 항공기 개발·생산과 항공기 정비·훈련 등 항공우주 분야의 사업 구조가 중요한 기업입니다. 완제품 납품만이 아니라 개발비 부담, 양산 전환 시점, 후속 군수지원 매출, 해외 고객 확대 가능성을 구분해 분석해야 합니다.

두 기업은 모두 방산주로 묶이지만 매출이 발생하는 방식과 비용 구조가 다릅니다. 따라서 같은 업종의 주가수익비율만 단순 비교하기보다 사업별 매출 성장률과 영업이익률, 수주잔고의 질을 나누어 보는 것이 적절합니다.

실적보다 현금흐름을 먼저 확인해야 하는 경우

Section titled “실적보다 현금흐름을 먼저 확인해야 하는 경우”

방산 기업은 장기 계약과 선투자가 많기 때문에 회계상 이익과 현금 유입 시점이 다를 수 있습니다. 매출과 영업이익이 증가해도 재고와 매출채권이 빠르게 늘면 현금흐름이 약해질 수 있습니다. 반대로 초기 생산 투자가 마무리되고 선수금이 유입되면 이후 현금 전환이 개선될 수도 있습니다.

분석할 때는 다음 항목을 함께 비교하는 것이 좋습니다.

  • 수주잔고 증가율과 매출 전환 속도
  • 영업이익률과 계약별 원가 변동
  • 영업활동현금흐름과 매출채권 증가폭
  • 재고자산과 설비투자 규모
  • 순차입금과 이자비용

특히 수주잔고가 크다는 이유만으로 높은 이익을 보장할 수는 없습니다. 계약 변경, 납품 지연, 원가 상승, 고객의 예산 집행 일정이 실제 수익성을 바꿀 수 있습니다.

첫째는 기대의 선반영입니다. 대형 수주 뉴스가 발표되면 향후 몇 년의 성장 기대가 단기간에 주가에 반영될 수 있습니다. 둘째는 정책과 외교 위험입니다. 수출 승인은 기업의 기술력만으로 결정되지 않으며 정부 간 협상과 구매국의 예산에 영향을 받습니다.

셋째는 생산능력의 한계입니다. 수주가 급증해도 인력·부품·공장 증설이 따라가지 못하면 납품이 늦어지고 비용이 커질 수 있습니다. 마지막으로 환율과 원자재 가격, 기술 이전 조건은 계약 수익성에 영향을 줍니다.

종목을 비교하는 간단한 프레임

Section titled “종목을 비교하는 간단한 프레임”

방산주를 비교할 때는 다음처럼 네 축으로 정리할 수 있습니다.

성장성 = 신규 수주 + 수출 확대 + 후속지원 매출
수익성 = 사업별 영업이익률 + 원가 관리 + 생산 효율
현금성 = 영업현금흐름 + 선수금 + 운전자본 관리
위험성 = 고객·국가 집중도 + 납품 지연 + 정책·환율 변수

이 네 항목을 분기별로 업데이트하면 주가가 수주 뉴스에만 반응하는지, 실제 실적과 현금흐름이 개선되고 있는지 구분하는 데 도움이 됩니다.

방산주가 장기 성장주로 평가받는 이유는 단기적인 지정학적 이슈 때문만이 아닙니다. 장기 국방 계획, 교체 수요, 수출 확대, 생산·정비·개량으로 이어지는 매출 구조가 성장의 기반이 될 수 있기 때문입니다.

다만 수주잔고가 곧바로 이익이나 현금이 되는 것은 아닙니다. 방산 기업을 분석할 때는 수주 규모보다 매출 전환 속도, 수출 계약의 수익성, 생산능력, 영업현금흐름을 함께 확인해야 합니다. 기대가 큰 산업일수록 계약의 질과 실행력을 점검하는 과정이 중요합니다.

이 글은 방산 산업과 기업 분석 방법을 설명하기 위한 자료이며, 특정 종목의 투자 결과를 보장하지 않습니다.

외국인 순매수 종목을 따라 사도 될까? 실제 데이터로 확인한 수급의 함정

외국인 수급과 주가 흐름을 분석하는 연구 공간

외국인 순매수 상위 종목은 많은 투자자가 참고하는 대표적인 수급 지표입니다. 하지만 외국인이 많이 샀다는 사실만으로 다음 상승을 기대해도 될까요? 순매수는 강력한 정보일 수 있지만, 매수 기간·거래대금·다른 투자자 수급·이미 진행된 주가 상승을 함께 보지 않으면 신호를 잘못 해석하기 쉽습니다.

이 글에서는 퀀티랩이 수집한 일별 투자자 매매와 주가 데이터를 이용해 2026년 8월 7일부터 9월 4일까지 최근 20거래일을 분석했습니다. 분석 대상은 해당 기간 데이터가 15거래일 이상 존재하는 종목 중 외국인 순매수 금액이 가장 큰 5개 종목입니다.

최근 20거래일 외국인 순매수와 같은 기간 주가 수익률

투자자별 매매 금액은 순매수 기준으로 집계했습니다. 금액은 억 원 단위이며, 주가 수익률은 분석 구간의 첫 종가와 마지막 종가를 비교한 단순 수익률입니다. 최대낙폭은 같은 구간 안에서 종가 기준 누적수익률이 고점 대비 얼마나 하락했는지를 계산한 값입니다.

순위종목외국인 순매수매수 우위 일수주가 수익률최대낙폭
1우리금융지주(316140)4,004억9일-4.6%-9.3%
2한미반도체(042700)1,840억15일+19.6%-8.7%
3실리콘투(257720)1,791억11일+22.1%-11.4%
4한국금융지주(071050)1,737억19일+0.4%-10.2%
5파마리서치(214450)1,685억17일+2.1%-17.4%

결과는 단순합니다. 외국인 순매수 상위 종목이라고 해서 모두 같은 방향으로 움직이지 않았습니다. 우리금융지주는 외국인 순매수 금액이 가장 컸지만 주가는 오히려 4.6% 하락했습니다. 반면 한미반도체와 실리콘투는 외국인 매수와 주가 상승이 함께 나타났습니다. 한국금융지주와 파마리서치는 외국인 매수 우위 일수가 많았지만 주가 상승폭은 제한적이었습니다.

순매수 금액이 큰 것과 매수가 지속되는 것은 다르다

Section titled “순매수 금액이 큰 것과 매수가 지속되는 것은 다르다”

우리금융지주의 외국인 순매수는 4,004억 원으로 다른 종목보다 크게 나타났습니다. 그러나 9개 거래일만 매수 우위였고, 9월 3일 하루 외국인 순매수가 약 4,317억 원으로 기록되었습니다. 하루의 대규모 거래가 누적값을 크게 끌어올린 사례입니다.

이런 경우 누적 순매수만 보면 외국인이 꾸준히 매수했다고 착각할 수 있습니다. 따라서 다음 세 지표를 함께 확인해야 합니다.

  • 순매수 누적 금액
  • 순매수 우위 일수와 연속성
  • 최대 단일 거래일 순매수 금액이 전체 누적값에서 차지하는 비중

한 번의 블록성 거래나 지수 편입·편출 관련 거래가 전체 신호를 왜곡할 수 있기 때문입니다. 누적 금액이 크더라도 며칠에 걸쳐 반복된 매수인지, 특정 하루에 집중된 매수인지에 따라 해석은 달라져야 합니다.

다른 투자자의 매매 방향도 함께 봐야 한다

Section titled “다른 투자자의 매매 방향도 함께 봐야 한다”

이번 구간에서 한미반도체는 외국인 순매수 1,840억 원과 함께 주가가 19.6% 상승했습니다. 하지만 기관은 약 2,303억 원 순매도했고 개인은 약 455억 원 순매수했습니다. 외국인 매수가 주가를 지지했지만, 기관의 반대 매매도 동시에 나타난 것입니다.

실리콘투는 외국인 순매수 1,791억 원, 주가 상승률 22.1%를 기록했지만 기관과 개인은 각각 약 645억 원, 1,119억 원을 순매도했습니다. 이런 패턴은 외국인 수급이 가격을 끌어올린 사례로 볼 수 있지만, 외국인 매수세가 약해지면 매수 주체가 빠르게 사라질 위험도 있습니다.

반대로 한국금융지주는 외국인 순매수 우위 일수가 19일로 가장 안정적이었지만, 기관은 약 63억 원, 개인은 약 1,653억 원 순매도했습니다. 그럼에도 주가 수익률은 0.4%에 그쳤습니다. 지속적인 외국인 매수가 있었지만 다른 매도 물량을 상쇄하는 데 대부분 사용되었을 가능성이 있습니다.

거래대금 대비 순매수 비율은 신호의 강도를 보여준다

Section titled “거래대금 대비 순매수 비율은 신호의 강도를 보여준다”

절대 금액만 비교하면 대형주가 항상 상위에 오릅니다. 그래서 평균 거래대금 대비 외국인 누적 순매수 규모도 확인했습니다.

종목평균 일 거래대금외국인 순매수 / 20일 거래대금
우리금융지주약 899억 원22.3%
한미반도체약 1,182억 원7.8%
실리콘투약 971억 원9.2%
한국금융지주약 398억 원21.8%
파마리서치약 697억 원12.1%

우리금융지주와 한국금융지주는 평균 거래대금 대비 외국인 순매수 비중이 상대적으로 컸습니다. 그러나 우리금융지주의 주가가 하락했다는 점에서, 비율이 높다는 것만으로 상승을 보장할 수 없다는 사실도 확인됩니다. 매수 가격대와 매도 압력, 거래가 발생한 시점이 함께 중요합니다.

외국인 순매수를 따라가기 위한 조건

Section titled “외국인 순매수를 따라가기 위한 조건”

외국인 순매수를 매매 신호로 활용하려면 최소한 다음 순서를 권합니다.

  1. 최근 20일과 60일의 누적 순매수 방향이 같은지 확인합니다.
  2. 순매수 우위 일수와 최대 단일 거래일 비중을 확인합니다.
  3. 외국인 순매수가 평균 거래대금의 어느 정도인지 계산합니다.
  4. 기관과 개인이 같은 방향인지, 반대 방향인지 구분합니다.
  5. 주가가 이미 단기 급등했는지와 최대낙폭을 확인합니다.
  6. 공매도 거래와 공매도 잔고가 매수 신호를 상쇄하지 않는지 살펴봅니다.

간단한 필터로 표현하면 다음과 같습니다.

signal = (
(foreign_net_20 > 0)
& (foreign_buy_days_20 >= 12)
& (foreign_net_20 / turnover_20 >= 0.05)
& (return_20 < 0.20)
)

이 조건은 매수 추천 공식이 아니라 수급의 지속성과 과열 여부를 함께 보려는 분석 예시입니다. 임계값은 시장과 투자 기간에 따라 다시 검증해야 합니다.

최근 20거래일 데이터에서 외국인 순매수와 주가 상승이 동시에 나타난 종목은 한미반도체와 실리콘투였습니다. 그러나 두 종목 모두 구간 중 최대낙폭이 각각 8.7%, 11.4% 발생했습니다. 수급이 좋았던 종목도 중간 변동성을 피할 수 없었다는 뜻입니다.

우리금융지주는 가장 큰 외국인 순매수 금액에도 주가가 하락했고, 한국금융지주는 외국인 매수 우위 일수가 가장 많았지만 거의 제자리였습니다. 따라서 외국인 수급은 매수 버튼을 누르게 하는 단독 신호라기보다, 주가·거래대금·다른 투자자 수급과 함께 사용하는 확인 신호에 가깝습니다.

외국인이 순매수한 종목을 따라 사는 전략은 단순하고 직관적이지만, 누적 금액만 보면 중요한 정보를 잃게 됩니다. 실제 분석에서는 매수의 지속성, 거래대금 대비 규모, 다른 투자자의 반대 매매, 이미 발생한 수익률과 최대낙폭을 함께 봐야 합니다.

이번 사례의 핵심은 외국인 순매수 상위라는 순위와 이후 주가 성과가 일치하지 않았다는 것입니다. 순매수는 관심 종목을 좁히는 유용한 출발점이지만, 최종 판단을 위해서는 수급이 가격을 실제로 지지하고 있는지, 그리고 그 흐름이 며칠의 이벤트가 아닌지 검증해야 합니다.

분석 기준일은 2026년 9월 4일이며, 데이터 집계 방식과 거래비용에 따라 결과가 달라질 수 있습니다. 이 글은 투자 판단을 위한 참고 자료이며 특정 종목의 매수·매도를 권유하지 않습니다.

AI 반도체 ETF 비교: 국내형과 미국형, 무엇이 다를까?

AI 반도체 ETF 비교 대표 이미지

AI 반도체 ETF를 찾을 때 가장 먼저 보이는 것은 최근 수익률입니다. 그러나 같은 ‘AI 반도체’라는 이름을 사용해도 국내 메모리 공급망에 집중하는 상품과 미국 팹리스·장비 기업을 담는 상품은 움직이는 이유가 다릅니다. 이 글에서는 최신 거래일 기준 데이터를 바탕으로 국내형 **RISE AI반도체TOP10(0093A0)**과 미국형 **KODEX 미국AI반도체TOP3플러스(0151S0)**를 비교합니다.

구분RISE AI반도체TOP10KODEX 미국AI반도체TOP3플러스
코드0093A00151S0
투자 지역한국미국
최신 기준일2026-09-032026-09-03
최신 종가30,400원14,345원
2026-06-01 종가39,665원17,887원

가격 수준 자체는 상품 간 비교 기준이 아닙니다. ETF 분할과 설정 시점이 다르기 때문에 수익률, 변동성, 구성종목 중복도를 함께 봐야 합니다.

수익률만 보면 국내형이 더 약했다

Section titled “수익률만 보면 국내형이 더 약했다”

2026년 6월 1일부터 9월 3일까지 단순 가격 수익률은 RISE AI반도체TOP10이 약 -23.3%, KODEX 미국AI반도체TOP3플러스가 약 -19.8%였습니다. 두 상품 모두 조정을 받았지만, 국내형의 하락폭이 조금 더 컸습니다. 반도체 업황이 같아 보여도 원화 환율, 미국 기술주 밸류에이션, 국내 대형주 비중에 따라 결과가 달라질 수 있다는 뜻입니다.

다만 이 수치는 분배금과 거래비용을 반영하지 않은 종가 기준 단순 계산입니다. 실제 투자 성과를 비교할 때는 총수익률과 환헤지 여부를 확인해야 합니다.

국내형 ETF는 삼성전자·SK하이닉스와 국내 소재·장비 기업의 실적에 민감합니다. 메모리 가격과 HBM 출하가 개선되면 이익 레버리지가 커질 수 있지만, 특정 기업과 국내 수출 사이클에 위험이 집중될 수 있습니다.

미국형 TOP3 상품은 소수 종목 비중이 높아 ‘분산 ETF’라는 이름만으로 위험이 낮다고 보기 어렵습니다. 대신 엔비디아와 미국 반도체 설계·장비 기업의 AI 데이터센터 투자, 미국 기술주 흐름, 달러 가치가 함께 반영됩니다. 국내 투자자 입장에서는 주가 변동에 환율 변동까지 더해질 수 있습니다.

  • 한국 메모리와 HBM 사이클을 직접 보고 싶다면 국내형을 검토할 수 있습니다.
  • 미국 AI 인프라와 글로벌 팹리스 생태계에 투자하고 싶다면 미국형이 더 직접적인 선택입니다.
  • 하락장에서 버틸 상품을 찾는다면 이름보다 상위 보유종목 비중, 최근 최대낙폭, 거래대금을 먼저 비교해야 합니다.

첫째, HBM과 DRAM 가격이 물량 증가를 동반하는지 확인해야 합니다. 둘째, ETF의 상위 3~5개 종목 비중이 높아졌는지 살펴봐야 합니다. 셋째, 원·달러 환율과 미국 반도체 지수의 방향을 함께 봐야 합니다. 마지막으로 최근 수익률이 높다는 이유만으로 추격 매수하지 말고, 동일 기간의 최대낙폭과 회복 기간을 비교해야 합니다.

AI 반도체 ETF 비교에서 ‘국내형이냐 미국형이냐’보다 중요한 것은 어떤 위험을 감수할 것인지입니다. 국내형은 메모리와 HBM이라는 명확한 산업 노출을 제공하지만 한국 대형주와 수출 사이클에 집중됩니다. 미국형은 글로벌 AI 투자에 접근하지만 소수 종목과 환율 위험이 커질 수 있습니다. 따라서 수익률 순위 하나가 아니라 구성종목 집중도·환율 민감도·최대낙폭·거래대금을 같은 기간에 비교한 뒤 투자 비중을 결정하는 것이 합리적입니다.

이 글은 특정 ETF의 매수·매도를 권유하지 않으며, 투자 판단과 손익의 책임은 투자자에게 있습니다.

LangGraph와 LangSmith 연결하기: AI 에이전트 실행 추적과 디버깅

LangGraph 상태 그래프와 LangSmith 실행 추적을 표현한 이미지

LangGraph로 AI 에이전트를 만들면 단순한 함수 호출보다 복잡한 흐름을 구성할 수 있습니다. 상태(state)를 여러 노드가 읽고 수정하고, 조건에 따라 다른 노드로 이동하거나 사람의 검토를 기다릴 수도 있습니다. 문제는 실행 결과만 봐서는 어느 노드에서 잘못된 판단이 시작됐는지 찾기 어렵다는 점입니다.

이때 LangSmith를 연결하면 에이전트 실행을 단계별 trace로 확인할 수 있습니다. 각 노드의 입력과 출력, 실행 시간, 오류를 한 화면에서 비교할 수 있어 프롬프트와 워크플로를 개선하기가 쉬워집니다.

두 도구는 서로 대체 관계가 아닙니다.

도구담당 영역
LangGraph상태, 노드, 엣지, 조건 분기, 재개 가능한 실행 흐름
LangSmith실행 trace, 프롬프트·응답 확인, 평가, 모니터링

LangGraph가 에이전트의 실행 구조라면 LangSmith는 그 실행을 관찰하는 기록 장치입니다. 특히 여러 번의 LLM 호출이나 도구 호출이 이어지는 에이전트에서는 최종 답변보다 중간 단계의 기록이 더 중요합니다.

Python 환경에서 다음 패키지를 설치합니다.

Terminal window
pip install -U langgraph langsmith

LangSmith 프로젝트에서 발급한 API 키는 소스 코드에 직접 넣지 않고 환경 변수로 관리합니다.

Terminal window
export LANGSMITH_TRACING=true
export LANGSMITH_API_KEY="lsv2_..."
export LANGSMITH_PROJECT="quantylab-agent-dev"

LANGSMITH_PROJECT를 지정하면 실행 결과를 애플리케이션별 프로젝트로 분리할 수 있습니다. 개발·스테이징·운영 환경마다 프로젝트 이름을 나누면 실험 trace와 실제 사용자 요청을 섞지 않을 수 있습니다.

다음 그래프는 입력된 질문을 받아 답변을 만드는 간단한 예제입니다.

from typing import TypedDict
from langgraph.graph import END, START, StateGraph
class State(TypedDict):
question: str
answer: str
def answer_question(state: State) -> dict:
# 실제 애플리케이션에서는 이곳에서 LLM을 호출합니다.
return {"answer": f"질문을 처리했습니다: {state['question']}"}
builder = StateGraph(State)
builder.add_node("answer_question", answer_question)
builder.add_edge(START, "answer_question")
builder.add_edge("answer_question", END)
graph = builder.compile()
result = graph.invoke({"question": "LangGraph란 무엇인가?", "answer": ""})
print(result["answer"])

LangSmith 추적을 활성화한 상태에서 graph.invoke()를 실행하면 그래프 실행이 프로젝트에 기록됩니다. LangGraph와 LangChain 통합을 사용하는 경우에는 노드 안의 모델 호출도 부모 실행의 하위 trace로 나타납니다.

LangGraph 노드가 직접 호출하는 데이터 조회, 문서 검색, 후처리 함수는 @traceable로 감싸면 별도의 실행 단위로 기록할 수 있습니다.

from langsmith import traceable
@traceable(name="load-market-context", run_type="tool")
def load_market_context(symbol: str) -> dict:
# 데이터베이스나 외부 API 조회
return {"symbol": symbol, "context": "시장 데이터"}
def research_node(state: dict) -> dict:
context = load_market_context(state["symbol"])
return {"context": context}

이렇게 하면 research_node 안에서 실행된 데이터 조회를 따로 확인할 수 있습니다. 응답이 이상할 때 모델 프롬프트만 의심하지 않고, 검색 결과와 데이터 변환 결과까지 역추적할 수 있습니다.

첫째, API 키와 비밀번호를 graph state에 넣지 않습니다. state는 체크포인터나 디버깅 출력에 저장될 수 있으므로 인증 정보 대신 식별자와 상태만 전달해야 합니다.

둘째, 개인정보와 원문 데이터의 전송 범위를 확인합니다. LangSmith에 기록되는 입력·출력에는 사용자 질문과 검색 문서가 포함될 수 있으므로 필요한 경우 민감한 필드를 마스킹하거나 선택적 tracing을 사용합니다.

셋째, 프로젝트와 태그를 일관되게 사용합니다. 예를 들어 quantylab-agent-dev, quantylab-agent-prod를 분리하고 모델 버전, 데이터 기준일, 실험 이름을 metadata나 tag로 남기면 실행 결과 비교가 쉬워집니다.

LangGraph는 복잡한 AI 에이전트의 실행 흐름을 명시적으로 만들고, LangSmith는 그 흐름을 관찰하고 개선하게 해줍니다. 먼저 LANGSMITH_TRACING과 프로젝트를 설정한 뒤 그래프 전체를 확인하고, 원인 분석이 필요한 함수에 @traceable을 추가하는 순서가 가장 실용적입니다.

공식 문서도 함께 참고하면 좋습니다.

반도체가 만든 420억 달러 경상수지 흑자, 한국 경제의 체력은 얼마나 강해졌나

반도체가 만든 420억 달러 경상수지 흑자 대표 이미지

2026년 9월 4일 한국 경제에서 가장 주목할 숫자는 420억 8,000만 달러입니다. 한국은행이 발표한 2026년 7월 국제수지 잠정치에 따르면 한국의 경상수지는 420억 8,000만 달러 흑자를 기록했습니다. 월간 기준 역대 두 번째 규모이며, 7월 기준으로는 가장 큰 흑자입니다.

하지만 이 숫자를 곧바로 “한국 경제 전반이 회복됐다”고 해석하기는 어렵습니다. 이번 기록은 반도체와 컴퓨터 관련 수출이 만든 외수의 힘을 보여주는 동시에, 특정 산업 의존도가 높아진 한국 경제의 구조적 과제도 함께 드러냅니다.

경상수지 흑자는 무엇을 의미하나

Section titled “경상수지 흑자는 무엇을 의미하나”

경상수지는 상품과 서비스의 수출입, 해외에서 벌어들인 본원소득, 이전소득을 합산한 국제수지입니다. 간단히 말하면 한국이 해외와 거래하면서 벌어들인 외화가 지출한 외화보다 얼마나 많은지를 보여주는 지표입니다.

흑자가 커지면 외화 유동성과 대외 지급 능력에는 긍정적입니다. 원화와 외환시장에 안정 요인이 될 수 있고, 기업의 수출 대금과 해외 투자자금 흐름에도 영향을 줍니다. 다만 경상수지 흑자는 국민경제의 모든 부문이 좋아졌다는 종합성적표는 아닙니다. 수출이 늘어도 가계 소비와 건설투자, 서비스업 고용이 부진할 수 있기 때문입니다.

CURRENT ACCOUNT · JUL 2026

경상수지 흑자

잠정
420.8 억 달러

월간 기준 역대 두 번째 · 2개월 연속 400억 달러 상회

상품수지+458.2억
서비스수지−24.1억
본원소득수지+3.5억

MONTHLY TREND

2026년 경상수지 추이

억 달러

이번 흑자의 중심에는 반도체가 있습니다

Section titled “이번 흑자의 중심에는 반도체가 있습니다”

이번 발표에서 확인되는 가장 중요한 배경은 반도체 수출 호조입니다. 인공지능 데이터센터 투자와 고성능 컴퓨팅 확산으로 메모리와 관련 컴퓨터 기기 수요가 이어지면서 상품수지가 크게 개선됐습니다. 7월 경상수지가 두 달 연속 400억 달러를 웃돈 것도 상품수지의 강한 흑자 흐름과 연결됩니다.

이 흐름은 한국 제조업의 경쟁력을 다시 확인시켜 줍니다. 삼성전자와 SK하이닉스를 중심으로 한 메모리 공급망은 AI 투자 사이클의 직접적인 수혜를 받고 있으며, 장비·소재·부품 기업으로 수요가 확산될 가능성도 있습니다. 실제로 9월 4일 국내 증시는 미국 금리 부담 완화와 반도체 대형주 강세가 겹치며 코스피와 코스닥이 동반 상승 출발했습니다.

다만 수출 증가를 이익 증가와 동일시해서는 안 됩니다. 반도체 가격, 제품 믹스, 고객사의 재고 조정, 미국의 통상정책과 현지 생산 요구에 따라 수출액과 기업 이익은 달라질 수 있습니다.

기록적인 흑자에도 남는 세 가지 질문

Section titled “기록적인 흑자에도 남는 세 가지 질문”

1. 반도체 의존도가 지나치게 높지 않은가

Section titled “1. 반도체 의존도가 지나치게 높지 않은가”

반도체가 경상수지를 견인하는 것은 강점이지만, 동시에 집중 위험입니다. 글로벌 IT 투자 사이클이 둔화되거나 메모리 가격이 조정되면 상품수지와 기업 실적이 함께 흔들릴 수 있습니다. 자동차, 조선, 방산, 바이오, 콘텐츠와 같은 수출 산업이 안정적으로 성장해 수출 기반을 넓히는지가 중요합니다.

2. 흑자가 내수 회복으로 이어지는가

Section titled “2. 흑자가 내수 회복으로 이어지는가”

경상수지 흑자는 해외에서 벌어들인 외화 흐름을 보여줍니다. 이것이 임금·투자·소비 확대로 이어지는지는 별도로 확인해야 합니다. 수출 대기업의 실적이 개선되더라도 중소기업, 서비스업, 지역경제로 확산되지 않으면 체감경기는 약할 수 있습니다.

3. 서비스수지와 소득수지는 어떤 방향인가

Section titled “3. 서비스수지와 소득수지는 어떤 방향인가”

상품수지가 크게 개선된 달에도 여행·운송·지식서비스 등 서비스수지는 적자를 낼 수 있습니다. 해외 배당과 이자 수입이 늘어나는지, 반대로 외국인 투자자에 대한 배당 지급이 커지는지도 살펴봐야 합니다. 경상수지의 질을 판단하려면 전체 흑자 규모뿐 아니라 구성 항목의 지속성까지 확인해야 합니다.

금융시장과 투자자가 볼 체크포인트

Section titled “금융시장과 투자자가 볼 체크포인트”

첫째, 반도체 수출 증가가 물량 증가인지 가격 상승인지 구분해야 합니다. 물량과 가격이 함께 개선되는 국면이라면 업황의 지속성이 높지만, 가격만 급등한 경우에는 변동성이 커질 수 있습니다.

둘째, 4분기 반도체 장비 발주와 설비투자 계획을 확인해야 합니다. 장비 주문이 실제로 늘면 이번 수출 사이클이 생산능력 확장과 공급망 전반의 실적 개선으로 이어질 가능성이 커집니다.

셋째, 미국의 반도체 통상정책과 현지 투자 요구를 봐야 합니다. 미국 현지 생산 확대는 장기적으로 고객 접근성을 높일 수 있지만, 국내 생산과 수출의 일부가 현지 생산으로 대체되는 효과도 함께 따져야 합니다.

넷째, 반도체를 제외한 수출과 내수 지표가 개선되는지 확인해야 합니다. 한국 경제의 회복이 특정 업종의 슈퍼사이클인지, 아니면 폭넓은 경기 회복인지를 가르는 기준입니다.

결론: 강한 외수, 아직 확인이 필요한 내수

Section titled “결론: 강한 외수, 아직 확인이 필요한 내수”

7월 경상수지 420억 8,000만 달러 흑자는 한국이 AI와 반도체라는 글로벌 투자 흐름에서 상당한 수혜를 받고 있다는 분명한 신호입니다. 외환 안정과 수출기업 실적, 관련 장비·소재 산업에는 긍정적입니다.

그러나 기록적인 경상수지 흑자만으로 경기 전반의 회복을 단정하기는 어렵습니다. 앞으로는 반도체 수출의 지속성, 서비스수지 개선, 내수와 고용으로의 확산 여부를 함께 봐야 합니다. 이번 통계가 보여주는 한국 경제의 모습은 강한 수출 엔진을 다시 가동했지만, 그 동력이 경제 전체로 전달되는지는 아직 확인해야 하는 단계에 가깝습니다.

이 글은 2026년 9월 4일 공개된 한국은행 2026년 7월 국제수지 잠정 통계와 당일 경제 보도를 바탕으로 작성한 경제 해설입니다. 잠정치는 추후 수정될 수 있으며, 특정 금융상품의 매수·매도를 권유하지 않습니다.

  • 한국은행, 2026년 7월 국제수지(잠정)
  • 네이버 뉴스 경제 섹션, 2026-09-04 경제·증권 주요 보도
  • 한국은행 국제수지 통계 해설

주식 종목 분석에서 신용 거래 데이터 활용

주식 신용 거래 데이터 분석 대표 이미지

주식 시장에서 신용 거래 데이터는 개인 투자자들의 심리와 레버리지 수준을 파악할 수 있는 핵심 보조 지표입니다. 이번 포스트에서는 신용 거래 데이터의 각 항목이 무엇을 의미하는지, 그리고 이를 종목 분석에 어떻게 활용할 수 있는지 다루겠습니다.

신용 거래는 증권사로부터 자금이나 주식을 빌려서 매매하는 방식으로, 크게 두 가지로 나뉩니다.

구분설명
융자증권사에서 돈을 빌려 주식을 매수 (레버리지 매수)
대주증권사에서 주식을 빌려 매도 (공매도의 일종)

융자 잔고가 늘어난다는 것은 개인 투자자들이 빚을 내서까지 해당 종목을 사고 있다는 뜻이고, 대주 잔고가 늘어난다는 것은 해당 종목의 하락에 베팅하는 수요가 있다는 뜻입니다.

신용 거래 데이터는 일반적으로 증권사 API나 HTS에서 다음과 같은 항목들로 제공됩니다. 아래는 키움증권 API를 통해 수집할 수 있는 항목들입니다.

항목설명
종목코드대상 종목
일자거래 기준일
조회구분융자(1) 또는 대주(2)
현재가해당일 종가
거래량해당일 거래량
신규해당일 새로 발생한 신용 거래 수량
상환해당일 상환(청산)된 신용 거래 수량
잔고현재 미상환 신용 거래 누적 수량
금액잔고의 금액 환산 (잔고 × 현재가)
대비전일 대비 잔고 변화량
공여율증권사가 공여한 비율
잔고율상장주식수 대비 신용 잔고 비율 (%)

데이터를 DB에 저장한다면 다음과 같은 테이블 구조로 설계할 수 있습니다.

stock_credit 테이블
─────────────────────────────────────────────
code (PK) 종목코드 예: '005930'
date (PK) 일자 예: '20260220'
qry_tp (PK) 조회구분 1:융자, 2:대주
close 현재가
volume 거래량
new 신규
repayment 상환
balance 잔고
amount 금액
balance_diff 대비
supply_ratio 공여율
balance_ratio 잔고율
─────────────────────────────────────────────

분석 예시를 위해 가상의 종목 A에 대한 20일간 융자 데이터를 만들어 보겠습니다.

import pandas as pd
# 종목 A의 융자(신용매수) 데이터 예시
df = pd.DataFrame({
"date": [
"20260203", "20260204", "20260205", "20260206", "20260207",
"20260210", "20260211", "20260212", "20260213", "20260214",
"20260217", "20260218", "20260219", "20260220", "20260221",
"20260224", "20260225", "20260226", "20260227", "20260228",
],
"close": [
50000, 50500, 51200, 52000, 53500,
54000, 55000, 54200, 53000, 51500,
50800, 50000, 49500, 48000, 47000,
47500, 48200, 49000, 50500, 51000,
],
"volume": [
1200000, 1350000, 1500000, 1800000, 2200000,
1900000, 2500000, 2100000, 2800000, 3200000,
2600000, 2400000, 2000000, 3500000, 3000000,
1800000, 1600000, 1400000, 1300000, 1200000,
],
"new": [
150, 200, 280, 350, 500,
420, 600, 380, 300, 250,
200, 180, 150, 120, 100,
130, 160, 140, 120, 110,
],
"repayment": [
100, 120, 130, 150, 180,
200, 220, 350, 400, 380,
350, 300, 280, 350, 320,
200, 180, 170, 150, 140,
],
"balance": [
3050, 3130, 3280, 3480, 3800,
4020, 4400, 4430, 4330, 4200,
4050, 3930, 3800, 3570, 3350,
3280, 3260, 3230, 3200, 3170,
],
"amount": [
15250, 15807, 16794, 18096, 20330,
21708, 24200, 24011, 22949, 21630,
20574, 19650, 18810, 17136, 15745,
15580, 15713, 15827, 16160, 16167,
],
"balance_ratio": [
1.02, 1.04, 1.09, 1.16, 1.27,
1.34, 1.47, 1.48, 1.44, 1.40,
1.35, 1.31, 1.27, 1.19, 1.12,
1.09, 1.09, 1.08, 1.07, 1.06,
],
})

위 데이터는 “상승 → 과열 → 하락 → 안정” 의 전형적인 사이클을 보여줍니다.

1. 잔고율(balance_ratio)로 과열 여부 판단

Section titled “1. 잔고율(balance_ratio)로 과열 여부 판단”

잔고율은 상장주식수 대비 신용 잔고의 비율입니다. 이 값이 높을수록 레버리지 매수가 과도하게 쌓여 있다는 뜻입니다.

import matplotlib.pyplot as plt
fig, ax1 = plt.subplots(figsize=(12, 5))
ax2 = ax1.twinx()
ax1.plot(df["date"], df["close"], label="주가", color="black", marker="o", markersize=3)
ax2.bar(df["date"], df["balance_ratio"], alpha=0.3, label="잔고율(%)", color="red")
ax2.axhline(y=1.3, color="red", linestyle="--", alpha=0.5, label="주의 기준선")
ax1.set_ylabel("주가")
ax2.set_ylabel("잔고율(%)")
ax1.set_xticklabels(df["date"], rotation=45, ha="right")
plt.title("주가 vs 융자 잔고율")
fig.tight_layout()
plt.show()

예시 데이터를 보면 잔고율이 1.47%까지 올라간 2월 11일을 정점으로, 이후 주가가 하락하면서 잔고율도 함께 줄어드는 전형적인 패턴을 확인할 수 있습니다.

해석 기준 (종목/업종별로 기준이 다를 수 있음):

  • 잔고율 평소 대비 급등: 신용 매수 과열 → 주의 필요
  • 잔고율 고점 유지 + 주가 하락: 반대매매 리스크 존재
  • 잔고율 급등 후 주가 하락: 반대매매 연쇄로 추가 하락 가능성

2. 신규(new) vs 상환(repayment) 추이로 수급 방향 파악

Section titled “2. 신규(new) vs 상환(repayment) 추이로 수급 방향 파악”

신규가 상환보다 많으면 신용 매수세가 유입되고 있다는 뜻이고, 반대면 청산이 진행 중입니다.

# 신규 - 상환 = 순신규
df["net_new"] = df["new"] - df["repayment"]
# 5일 이동평균
df["net_new_ma5"] = df["net_new"].rolling(5).mean()
fig, ax1 = plt.subplots(figsize=(12, 5))
ax2 = ax1.twinx()
ax1.plot(df["date"], df["close"], label="주가", color="black", marker="o", markersize=3)
colors = ["blue" if v >= 0 else "red" for v in df["net_new"]]
ax2.bar(df["date"], df["net_new"], alpha=0.3, color=colors)
ax2.plot(df["date"], df["net_new_ma5"], label="순신규 MA5", color="orange")
ax2.axhline(y=0, color="gray", linestyle="--")
ax1.set_ylabel("주가")
ax2.set_ylabel("순신규 (신규 - 상환)")
ax1.set_xticklabels(df["date"], rotation=45, ha="right")
plt.title("순신규 융자 추이")
fig.tight_layout()
plt.show()

예시에서 2월 첫째 주에는 순신규가 양수(파란색)로 신용 매수가 활발했지만, 2월 12일부터 순신규가 음수(빨간색)로 전환되면서 청산이 시작되었습니다. 이 시점이 주가 하락과 일치합니다.

해석:

  • 순신규 양수 지속: 개인의 레버리지 매수 증가 → 단기 상승 기대감, 하지만 과열 주의
  • 순신규 음수 전환: 신용 청산 시작 → 매도 압력 증가 가능

3. 잔고 변화와 주가 방향의 다이버전스

Section titled “3. 잔고 변화와 주가 방향의 다이버전스”

주가는 상승하는데 신용 잔고가 급증하는 경우, 또는 주가가 하락하는데 신용 잔고가 줄지 않는 경우는 위험 신호입니다.

# 주가 변화율 vs 잔고 변화율 비교
df["price_change"] = df["close"].pct_change()
df["balance_change"] = df["balance"].pct_change()
# 주가 하락 + 잔고 증가 = 위험 신호
df["danger_signal"] = (df["price_change"] < -0.01) & (df["balance_change"] > 0)
print(df[["date", "close", "price_change", "balance", "balance_change", "danger_signal"]])

예시 데이터에서 2월 12일을 보면, 주가가 54,000→54,200→53,000으로 하락하는데 잔고는 4,020→4,430→4,330으로 여전히 높은 수준을 유지합니다. 이런 구간이 반대매매 리스크가 높은 구간입니다.

시나리오주가신용 잔고해석
건전한 상승→ 또는 ↓자기자본 매수 → 안정적
과열 상승↑↑레버리지 의존 → 조정 시 급락 위험
위험 하락→ 또는 ↑물타기 or 미청산 → 반대매매 리스크
건전한 조정손절 진행 → 바닥 형성 가능

4. 융자와 대주 데이터 결합 분석

Section titled “4. 융자와 대주 데이터 결합 분석”

융자(조회구분=1)와 대주(조회구분=2)를 함께 보면 시장 참여자들의 방향성에 대한 더 입체적인 분석이 가능합니다.

# 융자 잔고 (위의 df에서 가져옴)
df_loan = df[["date", "balance", "balance_ratio"]].rename(
columns={"balance": "loan_balance", "balance_ratio": "loan_ratio"}
)
# 같은 종목의 대주 잔고 예시
df_borrow = pd.DataFrame({
"date": df["date"],
"borrow_balance": [
200, 210, 220, 250, 280,
300, 350, 400, 450, 500,
520, 530, 510, 480, 450,
420, 390, 370, 350, 330,
],
"borrow_ratio": [
0.07, 0.07, 0.07, 0.08, 0.09,
0.10, 0.12, 0.13, 0.15, 0.17,
0.17, 0.18, 0.17, 0.16, 0.15,
0.14, 0.13, 0.12, 0.12, 0.11,
],
})
df_combined = df_loan.merge(df_borrow, on="date")
df_combined["loan_borrow_ratio"] = df_combined["loan_balance"] / df_combined["borrow_balance"]
fig, ax1 = plt.subplots(figsize=(12, 5))
ax1.plot(df_combined["date"], df_combined["loan_borrow_ratio"], marker="o", markersize=3)
ax1.set_ylabel("융자/대주 비율")
ax1.set_xticklabels(df_combined["date"], rotation=45, ha="right")
plt.title("융자/대주 잔고 비율 추이")
fig.tight_layout()
plt.show()

해석:

  • 융자/대주 비율 상승: 매수 레버리지가 매도보다 우세 → 강세 심리
  • 융자/대주 비율 하락: 매도(대주) 비중 증가 → 약세 심리 또는 헷지 수요

5. 신용 금액(amount)으로 레버리지 규모 파악

Section titled “5. 신용 금액(amount)으로 레버리지 규모 파악”

잔고율과 함께 금액 항목을 보면 실제 레버리지의 절대 규모를 파악할 수 있습니다.

fig, ax1 = plt.subplots(figsize=(12, 5))
ax2 = ax1.twinx()
ax1.plot(df["date"], df["close"], label="주가", color="black", marker="o", markersize=3)
ax2.fill_between(range(len(df)), df["amount"], alpha=0.2, color="green", label="신용 금액")
ax2.plot(df["date"], df["amount"], color="green", alpha=0.7)
ax1.set_ylabel("주가")
ax2.set_ylabel("신용 금액 (백만원)")
ax1.set_xticklabels(df["date"], rotation=45, ha="right")
plt.title("주가 vs 신용 잔고 금액")
fig.tight_layout()
plt.show()

예시에서 신용 금액은 2월 11일 24,200백만원으로 최고치를 기록한 뒤, 주가 하락과 함께 15,745백만원까지 줄어들었습니다. 금액 감소가 잔고 감소보다 빠른 것은 주가 하락 효과가 더해졌기 때문입니다.

  1. 매수 전 체크리스트에 포함: 관심 종목의 잔고율이 급등하고 있다면 진입 시점을 늦추는 것이 안전합니다.

  2. 반대매매 임계점 인식: 잔고율이 높은 상태에서 주가가 5% 이상 하락하면 반대매매가 연쇄적으로 발생할 수 있습니다.

  3. 바닥 확인 신호: 신용 잔고가 충분히 줄어든 후(상환 > 신규 지속) 주가가 반등하면 건전한 바닥 형성의 신호일 수 있습니다.

  4. 섹터 단위 분석: 특정 섹터 전체의 신용 잔고율이 높아지면 해당 섹터의 과열을 의미할 수 있습니다.

  5. 시계열 피처로 활용: 머신러닝 모델의 입력 피처로 잔고율, 순신규 추이, 잔고 변화율 등을 추가하면 예측 성능 향상에 도움이 됩니다.

지표활용주의 사항
잔고율과열 판단, 반대매매 리스크업종별 평균 수준 고려 필요
신규/상환수급 방향 파악단일일 데이터보다 추세 중요
잔고 대비일별 변화 모니터링주가 방향과 함께 분석
금액레버리지 절대 규모시가총액 대비로 비교
공여율증권사 리스크 관리 수준증권사별 차이 존재

신용 거래 데이터는 단독으로 사용하기보다는 주가, 거래량, 투자자별 매매동향 등 다른 지표와 결합하여 분석할 때 훨씬 큰 인사이트를 얻을 수 있습니다. 특히 개인 투자자 중심의 한국 주식 시장에서는 융자 잔고율이 시장 과열과 조정의 선행 지표로 유용하게 활용됩니다.

MSCI 지수란 무엇인가? 글로벌 투자의 나침반

MSCI 글로벌 주가지수 대표 이미지

주식 투자를 하다 보면 뉴스나 경제 기사에서 **MSCI 지수(MSCI Index)**라는 용어를 자주 접하게 됩니다. 특히 “한국 증시의 MSCI 선진국 지수 편입”과 같은 기사는 매년 단골로 등장하는 주제이기도 합니다. 그렇다면 MSCI 지수는 정확히 무엇이며, 왜 전 세계 투자자들이 이 지수에 주목하는 것일까요?

이번 글에서는 MSCI 지수의 개념과 중요성, 그리고 주요 지수들을 확인하는 방법에 대해 알아보겠습니다.

MSCI(Morgan Stanley Capital International) 지수는 미국의 투자은행인 모건스탠리의 자회사인 모건스탠리 캐피털 인터내셔널이 발표하는 글로벌 주가지수입니다.

전 세계 주식 시장을 선진국(Developed Markets), 신흥국(Emerging Markets), 프론티어 시장(Frontier Markets) 등으로 분류하고, 각 국가의 상장 주식들을 조합하여 산출합니다. MSCI 지수는 글로벌 펀드 매니저들이 투자 포트폴리오를 구성하거나 성과를 평가할 때 사용하는 가장 대표적인 벤치마크(기준) 역할을 합니다.

MSCI 지수가 금융 시장에서 막대한 영향력을 가지는 이유는 패시브 자금(Passive Funds) 때문입니다.

최근 몇 년간 특정 지수의 수익률을 그대로 추종하는 ETF(상장지수펀드)나 인덱스 펀드의 규모가 기하급수적으로 커졌습니다. 이러한 펀드들은 MSCI 지수를 추종하는 경우가 많습니다. 따라서 특정 국가나 기업이 MSCI 지수에 새로 편입되거나 비중이 늘어나면, 해당 지수를 추종하는 글로벌 자금이 기계적으로 유입되어 주가 상승을 견인하는 효과가 발생합니다. 반대로 지수에서 제외되거나 비중이 줄어들면 대규모 자금 유출이 일어날 수 있습니다.

MSCI는 전 세계 시장을 경제 발전 수준, 시장 규모, 유동성, 시장 접근성 등을 기준으로 크게 세 가지로 분류합니다.

  1. MSCI 선진국 지수 (World Index)
    • 미국, 일본, 영국, 프랑스, 독일 등 금융 시장이 고도로 발달한 국가들이 포함됩니다. 전 세계 주식 시장 시가총액의 대부분을 차지합니다.
  2. MSCI 신흥국 지수 (Emerging Markets Index, EM)
    • 중국, 인도, 대만, 브라질, 그리고 한국 등이 포함됩니다. 선진국에 비해 변동성은 크지만 높은 성장 잠재력을 가진 시장으로 평가받습니다.
  3. MSCI 프론티어 시장 지수 (Frontier Markets Index)
    • 베트남, 카자흐스탄, 모로코 등 신흥국보다 경제 규모나 금융 시장 발달 정도가 상대적으로 낮은 국가들이 포함됩니다.

한국은 현재 MSCI 신흥국(EM) 지수에 속해 있습니다. 한국 경제의 규모나 위상을 고려할 때 선진국 지수에 편입되어야 한다는 목소리가 꾸준히 나오고 있으며, 정부 차원에서도 외환시장 개방, 영문 공시 확대 등 시장 접근성을 개선하여 선진국 지수로 승격하기 위한 노력을 지속하고 있습니다. 선진국 지수에 편입될 경우, 코리아 디스카운트 해소와 함께 안정적인 글로벌 장기 투자 자금의 유입을 기대할 수 있습니다.

MSCI 지수는 단순한 숫자의 나열이 아니라, 글로벌 자본이 어느 방향으로 흘러가고 있는지를 보여주는 중요한 지표입니다. 성공적인 투자를 위해 MSCI 지수의 흐름을 꾸준히 모니터링해 보시기 바랍니다.

업비트에서 실시간 가격 및 호가 데이터 받아오기 (코드 포함)

업비트 WebSocket 실시간 데이터 대표 이미지

암호화폐 트레이딩 봇이나 데이터 분석 시스템을 개발할 때 가장 중요한 것 중 하나는 실시간 시장 데이터를 빠르고 안정적으로 수집하는 것입니다. 이번 포스트에서는 업비트(Upbit) 거래소의 WebSocket API를 활용하여 실시간으로 가격과 호가 데이터를 받아오는 방법을 다룹니다.

업비트는 REST API와 WebSocket API 두 가지 방식을 제공합니다. 실시간 데이터 수집에는 WebSocket이 훨씬 효율적입니다.

REST API의 단점:

  • 주기적으로 요청(polling)해야 하므로 네트워크 오버헤드가 큽니다
  • API 호출 제한(rate limit)에 걸리기 쉽습니다
  • 실시간성이 떨어집니다

WebSocket의 장점:

  • 한 번 연결하면 서버가 데이터를 실시간으로 푸시합니다
  • 네트워크 효율성이 높고 지연시간이 적습니다
  • 여러 종목을 동시에 구독 가능합니다
Terminal window
pip install websocket-client keyring keyrings.alt
  • websocket-client: WebSocket 클라이언트 라이브러리
  • keyring: API 키를 안전하게 관리하기 위한 라이브러리
  • keyrings.alt: keyring의 파일 기반 백엔드

이번 예제 코드는 다음과 같은 구조로 설계되었습니다:

  1. WebSocket 기본 클래스: 스레드 기반으로 동작하며 재사용 가능한 WebSocket 연결 관리
  2. TickerWebSocket: 실시간 가격 정보 수신용
  3. OrderbookWebSocket: 실시간 호가 정보 수신용
  4. 비동기 처리: asyncio를 활용한 데이터 처리 루프
class WebSocket(threading.Thread):
def __init__(self, subscribe_type: str, codes: list):
super().__init__(daemon=True) # 데몬 스레드로 설정
self.ws = websocket.WebSocketApp(...)

daemon=True로 설정하면 메인 프로그램이 종료될 때 함께 종료됩니다.

업비트 WebSocket API는 다음 형식의 구독 메시지를 요구합니다:

subscribe_message = [
{"ticket": str(uuid.uuid4())}, # 고유 식별자
{"type": "ticker", "codes": ["KRW-BTC", "KRW-ETH"]}, # 구독 정보
]
  • ticket: 요청을 구분하는 고유 ID (UUID 사용 권장)
  • type: 데이터 타입 (ticker, orderbook, trade 등)
  • codes: 구독할 마켓 코드 리스트
self.ws.run_forever(ping_interval=30, ping_timeout=10, reconnect=2)
  • ping_interval=30: 30초마다 ping 메시지 전송
  • ping_timeout=10: ping 응답 타임아웃 10초
  • reconnect=2: 연결 끊김 시 2초 후 자동 재연결
async def process(self):
count = 0
last_time = 0
while True:
if self.last_data:
self.process_data() # 데이터 처리 로직
count += 1
await asyncio.sleep(1 - (time.time() - last_time))
last_time = time.time()

매 초마다 최신 데이터를 처리하면서도 정확한 시간 간격을 유지합니다.

공개 데이터(가격, 호가)는 API 키 없이도 사용 가능하지만, 개인 거래 정보에는 필요합니다:

import keyring
from keyrings.alt.file import PlaintextKeyring
keyring.set_keyring(PlaintextKeyring())
keyring.set_password("upbit", "access_key", "your_access_key")
keyring.set_password("upbit", "secret_key", "your_secret_key")
Terminal window
python your_script.py

실행하면 다음과 같은 출력을 볼 수 있습니다:

WebSocket created: ticker ['KRW-ETH']
WebSocket created: orderbook ['KRW-ETH']
Starting WebSocket thread: ticker ['KRW-ETH']
Starting WebSocket thread: orderbook ['KRW-ETH']
Inserted ticker data at timestamp 1707393600000 | Count: 1
Inserted orderbook data at timestamp 1707393600000 | Count: 1

이 코드를 기반으로 다음과 같은 기능을 추가할 수 있습니다:

  1. 데이터베이스 저장: process_data() 메서드에서 MongoDB, PostgreSQL 등에 저장
  2. 실시간 알림: 특정 가격 도달 시 알림 전송
  3. 차트 시각화: Plotly, Matplotlib 등으로 실시간 차트 업데이트
  4. 트레이딩 봇: 가격 변동에 따른 자동 매매 로직 구현
  5. ML 모델 학습: 실시간 데이터를 feature로 활용
import asyncio
import uuid
import websocket
import threading
import json
import time
from keyrings.alt.file import PlaintextKeyring
import keyring
keyring.set_keyring(PlaintextKeyring())
# codes
# https://docs.upbit.com/kr/reference/list-trading-pairs
BITCOIN = "KRW-BTC"
ETHEREUM = "KRW-ETH"
access_key = keyring.get_password("upbit", "access_key")
secret_key = keyring.get_password("upbit", "secret_key")
class WebSocket(threading.Thread):
def __init__(self, subscribe_type: str, codes: list):
super().__init__(daemon=True)
self.ws = websocket.WebSocketApp(
"wss://api.upbit.com/websocket/v1",
on_open=self.on_open,
on_message=self.on_message,
on_error=self.on_error,
on_close=self.on_close
)
self.last_data = None
self.subscribe_type = subscribe_type
self.codes = codes
def on_open(self, ws):
assert self.subscribe_type != "", "subscribe_type must be set before running the WebSocket"
assert self.codes, "codes must be set before running the WebSocket"
print(f"WebSocket created: {self.subscribe_type} {self.codes}")
subscribe_message = [
{"ticket": str(uuid.uuid4())},
{"type": self.subscribe_type, "codes": self.codes},
]
ws.send(json.dumps(subscribe_message))
def on_message(self, ws, message):
data = json.loads(message)
self.last_data = data
def on_error(self, ws, err):
print(f"Error in WebSocket {self.subscribe_type} {self.codes}:", err)
def on_close(self):
print(f"WebSocket closed: {self.subscribe_type} {self.codes}")
def run(self):
print(f"Starting WebSocket thread: {self.subscribe_type} {self.codes}")
self.ws.run_forever(ping_interval=30, ping_timeout=10, reconnect=2)
async def process(self):
count = 0
last_time = 0
while True:
if self.last_data:
self.process_data()
count += 1
print(f"\rInserted {self.subscribe_type} data at timestamp {self.last_data['timestamp']} | Count: {count}", end="", flush=True)
await asyncio.sleep(1 - (time.time() - last_time))
last_time = time.time()
def process_data(self):
pass
class TickerWebSocket(WebSocket):
def __init__(self):
super().__init__(subscribe_type="ticker", codes=[ETHEREUM])
def process_data(self):
# do something
pass
class OrderbookWebSocket(WebSocket):
def __init__(self):
super().__init__(subscribe_type="orderbook", codes=[ETHEREUM])
def process_data(self):
# do something
pass
async def main():
ticker_ws = TickerWebSocket()
orderbook_ws = OrderbookWebSocket()
ticker_ws.start()
orderbook_ws.start()
ticker_task = asyncio.create_task(ticker_ws.process())
orderbook_task = asyncio.create_task(orderbook_ws.process())
await asyncio.gather(ticker_task, orderbook_task)
if __name__ == "__main__":
asyncio.run(main())
  1. 연결 안정성: 네트워크 상태에 따라 연결이 끊길 수 있으므로 재연결 로직이 중요합니다.
  2. 메모리 관리: last_data를 계속 덮어쓰므로 메모리 누수는 없지만, 데이터를 저장하는 경우 메모리 관리에 주의해야 합니다.
  3. 에러 처리: 실제 운영 환경에서는 더 상세한 에러 처리와 로깅이 필요합니다.

이번 포스트에서는 업비트 WebSocket API를 활용한 실시간 데이터 수집 방법을 알아보았습니다.

핵심 포인트:

  • WebSocket은 실시간 데이터 수집에 효율적입니다
  • 스레드와 asyncio를 조합하여 안정적인 데이터 처리가 가능합니다
  • 자동 재연결 기능으로 연결 안정성을 확보할 수 있습니다

이 코드를 기반으로 여러분만의 트레이딩 시스템이나 분석 도구를 만들어보세요!

파이썬으로 IMF에서 각국의 GDP 수집하기 (v.2025)

이번 글에서는 파이썬을 사용하여 IMF(국제통화기금)에서 WEO(World Economic Outlook) 데이터베이스를 통해 세계 경제 데이터를 수집하고 GDP(국내총생산) 데이터를 조회하고 시각화하는 방법을 소개합니다.

WEO 데이터베이스에는 각국의 GDP, 인플레이션, 실업률 등 다양한 경제 지표가 포함되어 있습니다. 여기서는 GDP 데이터를 중심으로 다룹니다.

다음 내용을 다룹니다:

  • WEO 데이터를 SDMX 3.0 API를 통해 수집하는 방법
  • GDP 데이터 조회 및 시각화 방법

먼저 필요한 파이썬 라이브러리를 설치합니다. pandas, requests, matplotlib 라이브러리가 필요합니다.

Terminal window
pip install pandas requests matplotlib

IMF의 WEO 데이터는 SDMX 3.0 API를 통해 접근할 수 있습니다. 다음은 파이썬을 사용하여 GDP 데이터를 수집하는 예제 코드입니다.

import json
import requests
def get_weo_data():
# Dataset
# - Dataset name: World Economic Outlook (WEO)
# - ID: WEO
# - Agency: IMF.RES
# - Version: 9.0.0
"IMF.RES,WEO"
# Data Query
# https://api.imf.org/external/sdmx/3.0/data/{context}/{agencyID}/{resourceID}/{version}/{key}[?c][&updatedAfter][&firstNObservations][&lastNObservations][&dimensionAtObservation][&attributes][&measures][&includeHistory][&asOf]
url = "https://api.imf.org/external/sdmx/3.0/data/dataflow/IMF.RES/WEO/9.0.0/*"
res = requests.get(url)
data = json.loads(res.text)
return data

get_weo_data 함수를 호출하여 WEO 데이터를 수집할 수 있습니다.

import json
with open("weo_data.json", "w") as fout:
data = get_weo_data()
json.dump(data, fout)

수집한 데이터는 SDMX 3.0 형식으로 제공되서 파싱이 필요합니다.

데이터를 살펴보면 dataSets 키 아래에 여러 국가와 지표가 포함되어 있습니다. 그런데 키 값이 복잡하므로, 이를 해석하기 위해서는 structures 키 아래의 정보를 참고해야 합니다.

다음은 데이터를 파싱하여 판다스 데이터프레임으로 변환하는 예제 코드입니다.

output = []
for data_set in data_sets:
structure = structures[data_set["structure"]]
series_dims = structure["dimensions"]["series"]
obs_dims = structure["dimensions"]["observation"]
for series_key, series_content in data_set["series"].items():
# series dimensions 파싱
dim_indices = series_key.split(":")
series_info = {}
for i, dim_index in enumerate(dim_indices):
dim_id = series_dims[i]["id"]
dim_value_id = series_dims[i]["values"][int(dim_index)]["id"]
series_info[dim_id] = dim_value_id
# series attributes 파싱
attributes_info = {}
for attr_value, struct_attr in zip(series_content.get("attributes", []),
structure["attributes"]["series"]):
attr_id = struct_attr["id"]
# coded attribute는 index로 제공 => value id로 변환
if isinstance(attr_value, int):
attr_id_value = struct_attr["values"][attr_value]["id"]
else:
attr_id_value = attr_value # uncoded string
attributes_info[attr_id] = attr_id_value
# observations 처리
if "observations" not in series_content:
continue
for obs_key, obs_value in series_content["observations"].items():
obs_idx = int(obs_key)
obs_dim_value = obs_dims[0]["values"][obs_idx]["value"]
value = obs_value[0]
row = {
**series_info,
**attributes_info,
"TIME_PERIOD": obs_dim_value,
"VALUE": value
}
output.append(row)
# pandas DF 생성
import pandas as pd
df = pd.DataFrame(output)
df
.dataframe tbody tr th {
vertical-align: top;
}
.dataframe thead th {
text-align: right;
}
COUNTRY INDICATOR FREQUENCY SCALE DECIMALS_DISPLAYED OVERLAP COUNTRY_UPDATE_DATE TIME_PERIOD VALUE
0 ABW BCA A 9 3 OL 9/19/2025 1999 -435000000
1 ABW BCA A 9 3 OL 9/19/2025 2000 213000000
2 ABW BCA A 9 3 OL 9/19/2025 2001 310000000
3 ABW BCA A 9 3 OL 9/19/2025 2002 -333000000
4 ABW BCA A 9 3 OL 9/19/2025 2003 -167000000
... ... ... ... ... ... ... ... ... ...
354235 ZWE TXG_RPCH A 0 3 OL 9/5/2025 2026 -0.814
354236 ZWE TXG_RPCH A 0 3 OL 9/5/2025 2027 4.939
354237 ZWE TXG_RPCH A 0 3 OL 9/5/2025 2028 4.226
354238 ZWE TXG_RPCH A 0 3 OL 9/5/2025 2029 3.698
354239 ZWE TXG_RPCH A 0 3 OL 9/5/2025 2030 3.604

354240 rows × 9 columns

위 코드에서는 다음과 같은 작업을 수행합니다:

  • data_sets와 structures를 추출하여 각각의 시리즈와 관측치를 파싱합니다.
  • series_key를 ”:“로 분리하여 각 차원의 값을 추출합니다.
  • series_content의 attributes를 구조체의 attributes와 매핑하여 속성 값을 추출합니다.
  • observations를 순회하며 각 관측치의 시간과 값을 추출하여 최종적으로 판다스 데이터프레임으로 변환합니다.

이제 df 데이터프레임에는 각국의 GDP 데이터가 포함되어 있습니다. 이를 활용하여 다양한 분석과 시각화를 수행할 수 있습니다.

특정 데이터를 조회하기 위해서 국가 코드, 지표 코드 등을 알아야 합니다. 예를 들어, 미국은 “USA”, 한국은 “KOR”입니다. 주요 GDP 지표는 다음과 같습니다:

  • 실질 GDP (현재 가격): NGDP_R
  • 실질 GDP (전년 대비 증감률): NGDP_RPCH
  • GDP 갭 (실질 GDP - 잠재 GDP): NGAP_NPGDP

다음 링크에서 각국의 GDP 데이터를 직접 조회할 수도 있습니다: https://data.imf.org/en/Data-Explorer?datasetUrn=IMF.RES:WEO(9.0.0)

조회한 테이블 좌측의 ℹ️ 아이콘을 클릭하면 Timeseries code를 확인할 수 있는데, 여기서 국가 코드와 지표 코드를 알 수 있습니다. 예를 들어, Timeseries code: KOR.NGDP_RPCH.A는 한국(KOR)의 실질 GDP 성장률(NGDP_RPCH)을 의미합니다. A는 연간 데이터를 나타냅니다.

alt text

다음은 미국과 한국의 실질 GDP와 실질 GDP 성장률을 시각화하는 예제 코드입니다.

import matplotlib.pyplot as plt
# NGDP_R: 실질 GDP (현재 가격)
# NGDP_RPCH: 실질 GDP (전년 대비 증감률)
# NGAP_NPGDP: GDP 갭 (실질 GDP - 잠재 GDP)
fig, axes = plt.subplots(nrows=2, ncols=3, figsize=(12, 6))
# 미국
us_data = df[(df["COUNTRY"] == "USA") & (df["INDICATOR"] == "NGDP_R")].copy()
us_data["VALUE"] = pd.to_numeric(us_data["VALUE"])
us_data.plot(x="TIME_PERIOD", y="VALUE", title="US Real GDP Over Time", kind="line", ax=axes[0, 0])
us_data = df[(df["COUNTRY"] == "USA") & (df["INDICATOR"] == "NGDP_RPCH")].copy()
us_data["VALUE"] = pd.to_numeric(us_data["VALUE"])
us_data.plot(x="TIME_PERIOD", y="VALUE", title="US Real GDP Growth Rate Over Time", kind="line", ax=axes[0, 1])
us_data = df[(df["COUNTRY"] == "USA") & (df["INDICATOR"] == "NGAP_NPGDP")].copy()
us_data["VALUE"] = pd.to_numeric(us_data["VALUE"])
us_data.plot(x="TIME_PERIOD", y="VALUE", title="US GDP Gap Over Time", kind="line", ax=axes[0, 2])
# 한국
kr_data = df[(df["COUNTRY"] == "KOR") & (df["INDICATOR"] == "NGDP_R")].copy()
kr_data["VALUE"] = pd.to_numeric(kr_data["VALUE"])
kr_data.plot(x="TIME_PERIOD", y="VALUE", title="Korea Real GDP Over Time", kind="line", ax=axes[1, 0])
kr_data = df[(df["COUNTRY"] == "KOR") & (df["INDICATOR"] == "NGDP_RPCH")].copy()
kr_data["VALUE"] = pd.to_numeric(kr_data["VALUE"])
kr_data.plot(x="TIME_PERIOD", y="VALUE", title="Korea Real GDP Growth Rate Over Time", kind="line", ax=axes[1, 1])
kr_data = df[(df["COUNTRY"] == "KOR") & (df["INDICATOR"] == "NGAP_NPGDP")].copy()
kr_data["VALUE"] = pd.to_numeric(kr_data["VALUE"])
kr_data.plot(x="TIME_PERIOD", y="VALUE", title="Korea GDP Gap Over Time", kind="line", ax=axes[1, 2])
plt.tight_layout()

alt text

양국의 실질 GDP는 꾸준히 증가하는 추세를 보이며, 실질 GDP 성장률은 경기 변동에 따라 등락을 반복하는 모습을 확인할 수 있습니다.

GDP 갭 역시 경제 상황에 따라 변화하는 모습을 시각적으로 파악할 수 있습니다. 잠재 GDP는 경제가 완전 고용 상태에서 생산할 수 있는 최대 생산량을 나타내는데, GDP 갭이 양수일 경우 실제 GDP가 잠재 GDP를 초과하는 상태를 의미하며, 음수일 경우 그 반대를 의미합니다. GDP 갭이 양수로 크면 인플레이션 압력이 증가할 수 있고, 음수로 크면 경기 침체의 신호일 수 있습니다.

이와 같이 파이썬을 활용하여 IMF WEO 데이터베이스에서 각국의 GDP 데이터를 수집하고 분석할 수 있습니다. 미국, 한국 외에도 다양한 국가의 GDP 데이터를 동일한 방법으로 수집하여 비교 분석할 수 있습니다.