iBetter Books
수정

Ch 04. 포트폴리오 분석 리포트

지금까지 단일 종목을 분석했습니다. 이제 여러 종목을 한 바구니에 담아 포트폴리오 관점에서 분석합니다. 좋은 포트폴리오는 단순히 수익률이 높은 종목들의 조합이 아닙니다. 서로 다르게 움직이는 종목을 섞어야 한 쪽이 떨어질 때 다른 쪽이 버텨줍니다. 이 챕터에서는 상관분석으로 종목 간 관계를 파악하고, 전체 분석을 하나의 리포트로 정리합니다.

분석 대상 종목 선정

빅테크 3종목과 ETF 1종목으로 포트폴리오를 구성합니다.

  • AAPL: Apple (기술주)
  • MSFT: Microsoft (기술주)
  • GOOGL: Alphabet/Google (기술주)
  • SPY: S&P 500 ETF (시장 벤치마크)
# 새 파일: analysis/portfolio_report.R

library(tidyquant)
library(tidyverse)
library(scales)
library(patchwork)
library(corrplot)   # 상관계수 히트맵

# 데이터 수집
tickers <- c("AAPL", "MSFT", "GOOGL", "SPY")

portfolio_raw <- tq_get(
  tickers,
  get  = "stock.prices",
  from = "2022-01-01",
  to   = "2024-12-31"
)

# 일일 수익률 계산
portfolio_returns <- portfolio_raw |>
  group_by(symbol) |>
  tq_transmute(
    select     = adjusted,
    mutate_fun = periodReturn,
    period     = "daily",
    col_rename = "daily_return"
  )

glimpse(portfolio_returns)

수익률 비교 시각화

# 누적 수익률 계산 및 비교
cum_returns <- portfolio_returns |>
  group_by(symbol) |>
  arrange(date) |>
  mutate(cum_return = cumprod(1 + daily_return) - 1)

# 누적 수익률 라인 차트
p_cum <- cum_returns |>
  ggplot(aes(x = date, y = cum_return, color = symbol)) +
  geom_line(linewidth = 0.8) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "gray50") +
  scale_y_continuous(labels = percent) +
  scale_color_manual(
    values = c(
      AAPL  = "#1976D2",
      MSFT  = "#388E3C",
      GOOGL = "#F57C00",
      SPY   = "#7B1FA2"
    )
  ) +
  labs(
    title    = "포트폴리오 누적 수익률 비교",
    subtitle = "2022년 1월 ~ 2024년 12월, SPY 대비 성과",
    x        = "날짜",
    y        = "누적 수익률",
    color    = "종목"
  ) +
  theme_minimal(base_family = "AppleGothic")

p_cum

연도별 수익률 막대 그래프

# 월별 수익률 계산 후 연간 집계
annual_returns <- portfolio_raw |>
  group_by(symbol) |>
  tq_transmute(
    select     = adjusted,
    mutate_fun = periodReturn,
    period     = "yearly",
    col_rename = "annual_return"
  ) |>
  mutate(year = year(date))

# 연도별 수익률 막대 그래프
p_bar <- annual_returns |>
  ggplot(aes(x = factor(year), y = annual_return, fill = symbol)) +
  geom_col(position = "dodge", alpha = 0.85) +
  geom_hline(yintercept = 0, color = "gray40") +
  scale_y_continuous(labels = percent) +
  scale_fill_manual(
    values = c(
      AAPL  = "#1976D2",
      MSFT  = "#388E3C",
      GOOGL = "#F57C00",
      SPY   = "#7B1FA2"
    )
  ) +
  labs(
    title = "연도별 수익률 비교",
    x     = "연도",
    y     = "연간 수익률",
    fill  = "종목"
  ) +
  theme_minimal(base_family = "AppleGothic")

p_bar

상관분석

서로 다른 종목의 수익률이 얼마나 함께 움직이는지를 상관계수로 측정합니다. 상관계수가 1에 가까우면 같은 방향으로 움직이고, 0에 가까우면 독립적이며, -1에 가까우면 반대 방향으로 움직입니다.

# wide 형식으로 변환 (종목을 열로)
returns_wide <- portfolio_returns |>
  pivot_wider(
    names_from  = symbol,
    values_from = daily_return
  ) |>
  drop_na()

# 상관계수 행렬 계산
cor_matrix <- returns_wide |>
  select(-date) |>
  cor()

round(cor_matrix, 3)
# corrplot으로 상관계수 히트맵
corrplot(
  cor_matrix,
  method  = "color",
  type    = "upper",
  order   = "hclust",
  addCoef.col = "black",
  tl.col  = "black",
  tl.srt  = 45,
  col     = colorRampPalette(c("#1976D2", "white", "#E53935"))(200),
  title   = "종목 간 수익률 상관계수",
  mar     = c(0, 0, 2, 0)
)
# ggplot2로 상관계수 히트맵 (corrplot 대안)
cor_df <- as.data.frame(cor_matrix) |>
  rownames_to_column("symbol1") |>
  pivot_longer(-symbol1, names_to = "symbol2", values_to = "correlation")

cor_df |>
  ggplot(aes(x = symbol1, y = symbol2, fill = correlation)) +
  geom_tile(color = "white", linewidth = 0.5) +
  geom_text(aes(label = round(correlation, 2)), size = 4, fontface = "bold") +
  scale_fill_gradient2(
    low  = "#1976D2",
    mid  = "white",
    high = "#E53935",
    midpoint = 0,
    limits = c(-1, 1)
  ) +
  coord_fixed() +
  labs(
    title = "종목 간 수익률 상관계수",
    x     = NULL,
    y     = NULL,
    fill  = "상관계수"
  ) +
  theme_minimal(base_family = "AppleGothic") +
  theme(axis.text = element_text(size = 11))

위험-수익률 산점도

# 종목별 위험-수익률 요약 통계
risk_return_summary <- portfolio_returns |>
  group_by(symbol) |>
  summarise(
    ann_return = mean(daily_return) * 252 * 100,
    ann_vol    = sd(daily_return) * sqrt(252) * 100,
    sharpe     = (mean(daily_return) * 252) / (sd(daily_return) * sqrt(252))
  ) |>
  mutate(across(where(is.numeric), \(x) round(x, 2)))

risk_return_summary

샤프 지수(Sharpe Ratio)는 단위 위험 대비 수익률입니다. 값이 클수록 같은 위험을 감수하고 더 많은 수익을 얻은 것입니다.

# 위험-수익률 산점도 + 샤프 지수 레이블
library(ggrepel)

risk_return_summary |>
  ggplot(aes(x = ann_vol, y = ann_return)) +
  geom_point(aes(size = sharpe), color = "#1976D2", alpha = 0.8) +
  geom_text_repel(
    aes(label = paste0(symbol, "\n샤프:", sharpe)),
    size = 3.5,
    fontface = "bold"
  ) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "gray50") +
  scale_size_continuous(range = c(4, 12), guide = "none") +
  labs(
    title    = "위험-수익률 포지셔닝",
    subtitle = "점 크기 = 샤프 지수",
    x        = "연간화 변동성 (%)",
    y        = "연간화 수익률 (%)"
  ) +
  theme_minimal(base_family = "AppleGothic")

최종 분석 리포트 작성

지금까지의 분석을 R Markdown 리포트로 정리합니다. 아래는 리포트 구조를 코드로 표현한 것입니다. 실제 .Rmd 파일로 만들면 HTML 문서로 렌더링됩니다.

# 새 파일: reports/portfolio_report.Rmd
# (아래는 Rmd 파일 전체 내용)
---
title: "포트폴리오 분석 리포트"
subtitle: "AAPL · MSFT · GOOGL · SPY | 2022-2024"
author: "R 데이터 분석 실습"
date: "`r Sys.Date()`"
output:
  html_document:
    toc: true
    toc_float: true
    theme: flatly
    highlight: tango
    code_folding: hide
---

## 1. 분석 개요

본 리포트는 빅테크 3종목(AAPL, MSFT, GOOGL)과 시장 벤치마크(SPY)의
2022~2024년 성과를 비교 분석합니다.

## 2. 수익률 비교

`r ''`​```{r cum-returns, fig.width=10, fig.height=5}
# 누적 수익률 차트 코드
`r ''`​```

## 3. 위험 분석

`r ''`​```{r volatility}
# 변동성 분석 코드
`r ''`​```

## 4. 상관분석

`r ''`​```{r correlation, fig.width=6, fig.height=6}
# 상관계수 히트맵 코드
`r ''`​```

## 5. 핵심 지표 요약

`r ''`​```{r summary-table}
knitr::kable(
  risk_return_summary,
  caption = "종목별 핵심 지표 요약",
  col.names = c("종목", "연간수익률(%)", "연간변동성(%)", "샤프지수")
)
`r ''`​```

## 6. 결론

- MSFT는 세 빅테크 중 가장 안정적인 위험-수익률 균형을 보였습니다.
- GOOGL은 변동성이 가장 높았으나 2023년 이후 강한 반등을 기록했습니다.
- SPY 대비 세 종목 모두 초과 수익을 달성했습니다.

리포트를 렌더링하려면 RStudio에서 파일을 열고 "Knit" 버튼을 누르거나, 콘솔에서 rmarkdown::render("reports/portfolio_report.Rmd")를 실행합니다.

전체 요약 대시보드

patchwork로 핵심 차트를 한 화면에 배치합니다.

# 최종 대시보드 레이아웃
dashboard <- (p_cum | p_bar) / (cor_heatmap | risk_scatter) +
  plot_annotation(
    title    = "포트폴리오 종합 분석 대시보드",
    subtitle = "AAPL · MSFT · GOOGL · SPY | 2022-2024",
    theme    = theme(
      plot.title    = element_text(size = 16, face = "bold"),
      plot.subtitle = element_text(size = 12, color = "gray40")
    )
  )

# 고해상도 저장
ggsave(
  "reports/portfolio_dashboard.png",
  plot   = dashboard,
  width  = 16,
  height = 10,
  dpi    = 150
)

이 챕터를 마치며

단일 종목 분석에서 시작해 포트폴리오 분석까지 이어지는 전체 흐름을 완성했습니다. 수익률 계산, 변동성 측정, 상관분석, 샤프 지수, R Markdown 리포트까지 실전 금융 분석에 필요한 핵심 도구들을 모두 사용했습니다.

PART 06은 여기서 끝납니다. 마지막 PART 07에서는 전체 교재를 돌아보고, 다음 단계로 나아갈 방향을 정리합니다.