Ch 03. 이동평균과 기술 지표
주식 차트를 보면 가격선 위아래로 물결처럼 따라가는 선들이 있습니다. 이동평균선입니다. 단기 이동평균이 장기 이동평균을 뚫고 올라가는 순간을 "골든 크로스"라 부르고, 많은 트레이더가 매수 신호로 봅니다.
이번 챕터에서는 이동평균을 직접 계산하고 주가 차트 위에 오버레이합니다. RSI와 MACD도 계산해서 어떤 정보를 담고 있는지 확인합니다.
단순이동평균 (SMA)
단순이동평균(Simple Moving Average)은 최근 N일간 종가의 평균입니다. N이 작으면 가격에 민감하게 반응하고, N이 크면 장기 추세를 부드럽게 보여줍니다.
# 새 파일: analysis/technical_indicators.R
library(tidyquant)
library(tidyverse)
library(TTR) # SMA(), EMA(), RSI(), MACD() 제공
# 애플 데이터 수집
aapl <- tq_get(
"AAPL",
get = "stock.prices",
from = "2023-01-01",
to = "2024-12-31"
)
# SMA 계산: 20일 단기, 60일 중기, 120일 장기
aapl_sma <- aapl |>
arrange(date) |>
mutate(
sma_20 = SMA(adjusted, n = 20),
sma_60 = SMA(adjusted, n = 60),
sma_120 = SMA(adjusted, n = 120)
)
head(aapl_sma |> select(date, adjusted, sma_20, sma_60, sma_120), 25)
SMA() 함수는 TTR 패키지에서 옵니다. tidyquant를 로드하면 TTR도 함께 로드됩니다. 처음 N-1일은 평균을 낼 데이터가 부족하므로 NA가 됩니다.
주가 차트 + SMA 오버레이
# SMA 오버레이 시각화
aapl_sma |>
drop_na(sma_120) |> # 120일 SMA가 만들어진 이후 구간만
ggplot(aes(x = date)) +
geom_line(aes(y = adjusted), color = "gray50", linewidth = 0.5, alpha = 0.8) +
geom_line(aes(y = sma_20, color = "SMA 20"), linewidth = 0.8) +
geom_line(aes(y = sma_60, color = "SMA 60"), linewidth = 0.8) +
geom_line(aes(y = sma_120, color = "SMA 120"), linewidth = 0.8) +
scale_color_manual(
values = c(
"SMA 20" = "#E53935",
"SMA 60" = "#1E88E5",
"SMA 120" = "#43A047"
)
) +
labs(
title = "Apple (AAPL) 주가 + 이동평균",
x = "날짜",
y = "수정 종가 (USD)",
color = "이동평균"
) +
theme_minimal(base_family = "AppleGothic")
지수이동평균 (EMA)
단순이동평균은 N일 전 데이터와 오늘 데이터를 동등하게 취급합니다. 지수이동평균(Exponential Moving Average)은 최근 데이터에 더 큰 가중치를 줍니다. 최신 가격 변화에 더 빠르게 반응합니다.
# EMA 계산: 12일, 26일 (MACD에서 사용하는 기준값)
aapl_ema <- aapl |>
arrange(date) |>
mutate(
ema_12 = EMA(adjusted, n = 12),
ema_26 = EMA(adjusted, n = 26)
)
# SMA vs EMA 비교
aapl_compare <- aapl |>
arrange(date) |>
mutate(
sma_20 = SMA(adjusted, n = 20),
ema_20 = EMA(adjusted, n = 20)
)
aapl_compare |>
drop_na(sma_20) |>
pivot_longer(
cols = c(adjusted, sma_20, ema_20),
names_to = "type",
values_to = "price"
) |>
ggplot(aes(x = date, y = price, color = type)) +
geom_line(linewidth = 0.7, alpha = 0.9) +
scale_color_manual(
values = c(adjusted = "gray70", sma_20 = "#1976D2", ema_20 = "#E53935"),
labels = c(adjusted = "종가", sma_20 = "SMA(20)", ema_20 = "EMA(20)")
) +
labs(
title = "SMA vs EMA 비교 (20일)",
x = "날짜",
y = "가격 (USD)",
color = ""
) +
theme_minimal(base_family = "AppleGothic")
EMA가 SMA보다 주가 변화에 빠르게 반응하는 모습을 확인할 수 있습니다. 가격이 급락하면 EMA가 먼저 꺾이고, SMA는 그보다 늦게 따라옵니다.
RSI (상대강도지수)
RSI(Relative Strength Index)는 0부터 100 사이 값을 가지는 모멘텀 지표입니다. 최근 N일간 상승과 하락의 비율로 계산됩니다.
- RSI > 70: 과매수 구간 (가격이 너무 많이 올랐을 수 있음)
- RSI < 30: 과매도 구간 (가격이 너무 많이 내렸을 수 있음)
# RSI 계산 (14일 기준)
aapl_rsi <- aapl |>
arrange(date) |>
mutate(
rsi_14 = RSI(adjusted, n = 14)
) |>
drop_na(rsi_14)
# RSI 시각화
p_price <- aapl_rsi |>
ggplot(aes(x = date, y = adjusted)) +
geom_line(color = "#1976D2", linewidth = 0.6) +
labs(title = "AAPL 주가와 RSI", x = NULL, y = "종가 (USD)") +
theme_minimal(base_family = "AppleGothic")
p_rsi <- aapl_rsi |>
ggplot(aes(x = date, y = rsi_14)) +
geom_line(color = "#7B1FA2", linewidth = 0.6) +
geom_hline(yintercept = 70, linetype = "dashed", color = "#E53935", alpha = 0.7) +
geom_hline(yintercept = 30, linetype = "dashed", color = "#1E88E5", alpha = 0.7) +
geom_ribbon(
aes(ymin = ifelse(rsi_14 > 70, 70, rsi_14), ymax = rsi_14),
fill = "#E53935", alpha = 0.2
) +
geom_ribbon(
aes(ymin = rsi_14, ymax = ifelse(rsi_14 < 30, 30, rsi_14)),
fill = "#1E88E5", alpha = 0.2
) +
annotate("text", x = min(aapl_rsi$date), y = 72, label = "과매수(70)",
hjust = 0, size = 3, color = "#E53935") +
annotate("text", x = min(aapl_rsi$date), y = 28, label = "과매도(30)",
hjust = 0, size = 3, color = "#1E88E5") +
labs(x = "날짜", y = "RSI") +
theme_minimal(base_family = "AppleGothic")
# 두 차트 세로로 합치기
library(patchwork)
p_price / p_rsi + plot_layout(heights = c(2, 1))
patchwork 패키지가 없으면 install.packages("patchwork")로 설치합니다. / 연산자로 차트를 세로로 쌓습니다.
MACD (이동평균 수렴·발산)
MACD(Moving Average Convergence Divergence)는 단기 EMA와 장기 EMA의 차이로 만드는 지표입니다. 흔히 사용하는 설정은 12일 EMA - 26일 EMA입니다.
- MACD 선: EMA(12) - EMA(26)
- 시그널 선: MACD의 9일 EMA
- 히스토그램: MACD - 시그널. 양수면 상승 모멘텀, 음수면 하락 모멘텀
# MACD 계산 (TTR 패키지)
macd_result <- MACD(
aapl$adjusted,
nFast = 12,
nSlow = 26,
nSig = 9,
maType = "EMA"
)
# 데이터프레임에 합치기
aapl_macd <- aapl |>
arrange(date) |>
bind_cols(as_tibble(macd_result)) |>
rename(macd_line = macd, signal_line = signal) |>
mutate(
histogram = macd_line - signal_line,
bar_color = ifelse(histogram >= 0, "#43A047", "#E53935")
) |>
drop_na(signal_line)
# MACD 시각화
p_price2 <- aapl_macd |>
ggplot(aes(x = date, y = adjusted)) +
geom_line(color = "#1976D2", linewidth = 0.6) +
labs(title = "AAPL 주가와 MACD", x = NULL, y = "종가 (USD)") +
theme_minimal(base_family = "AppleGothic")
p_macd <- aapl_macd |>
ggplot(aes(x = date)) +
geom_col(aes(y = histogram, fill = bar_color), alpha = 0.7, width = 1) +
geom_line(aes(y = macd_line), color = "#1976D2", linewidth = 0.7) +
geom_line(aes(y = signal_line), color = "#E53935", linewidth = 0.7, linetype = "dashed") +
geom_hline(yintercept = 0, color = "gray40", linewidth = 0.3) +
scale_fill_identity() +
labs(x = "날짜", y = "MACD") +
theme_minimal(base_family = "AppleGothic")
p_price2 / p_macd + plot_layout(heights = c(2, 1))
tidyquant로 기술 지표 한 번에
tidyquant의 tq_mutate()를 사용하면 TTR 함수들을 파이프라인 안에서 바로 호출할 수 있습니다.
# tq_mutate()로 SMA, EMA, RSI 한 번에
aapl_all_indicators <- aapl |>
tq_mutate(
select = adjusted,
mutate_fun = SMA,
n = 20,
col_rename = "sma_20"
) |>
tq_mutate(
select = adjusted,
mutate_fun = EMA,
n = 12,
col_rename = "ema_12"
) |>
tq_mutate(
select = adjusted,
mutate_fun = RSI,
n = 14,
col_rename = "rsi_14"
)
glimpse(aapl_all_indicators)
tq_mutate()는 원래 데이터프레임에 새 컬럼을 추가합니다. tq_transmute()는 선택한 컬럼만 남기고 변환합니다.
이 챕터를 마치며
이동평균(SMA, EMA)은 추세를 파악하고, RSI는 현재 가격이 과매수·과매도 구간인지 알려주며, MACD는 모멘텀의 변화를 보여줍니다. 세 가지를 함께 보면 주가 흐름을 다각도로 이해할 수 있습니다.
다음 챕터에서는 여러 종목을 한 화면에 놓고 비교하는 포트폴리오 분석을 완성합니다. 상관분석으로 종목 간 관계를 수치로 표현하고, 분석 결과를 하나의 리포트로 정리합니다.