Python 기술적 지표 5가지: 초기값·준비 기간·경계값까지 계산
TECH INSIGHT / EXPLAINED
지표 이름만으로 계산 방식이 완전히 정해지지는 않습니다. 초기값·준비 기간·표준편차 규칙·빠진 봉에 따라 같은 기간 숫자도 결과가 달라질 수 있습니다.
실제 프로젝트의 로컬 실행 화면
기존 프로젝트의 화면 또는 함수를 로컬에서 실행해 촬영했습니다. 개인정보 없는 샘플 입력을 사용했으며, 실행한 범위는 각 이미지 아래에 설명했습니다.
다섯 측정값과 계산 규약
SMA는 고정 구간 평균, EMA는 최근 관측에 재귀적으로 가중하는 평균입니다. RSI는 평활한 상승·하락 폭을 비교하고, MACD는 두 EMA의 차이와 신호 평균을 비교합니다. 볼린저밴드는 평균 주위에 표준편차 배수를 더하며 ATR은 전 종가와의 갭을 포함한 true range를 평활합니다. 정의 자체가 매매 수익을 뜻하지는 않습니다.
아래 구현은 RSI·ATR에 SMA로 초기화한 Wilder 평활, 밴드에 모집단 표준편차(ddof=0), EMA에 첫 관측값으로 초기화한 재귀 방식(adjust=False)을 사용합니다. EMA를 SMA로 초기화하는 라이브러리와는 결과가 다를 수 있습니다.
import numpy as np
import pandas as pd
def wilder(values, period):
if not isinstance(period, int) or isinstance(period, bool) or period < 1:
raise ValueError('positive integer period required')
values = pd.Series(values, dtype=float)
if not np.isfinite(values).all():
raise ValueError('finite contiguous input required')
out = pd.Series(np.nan, index=values.index, dtype=float)
if len(values) < period: return out
out.iloc[period-1] = values.iloc[:period].mean()
for i in range(period, len(values)):
out.iloc[i] = (out.iloc[i-1]*(period-1)+values.iloc[i])/period
return out
def indicators(frame, period=14):
x = frame[['high','low','close']].astype(float)
if x.empty or not np.isfinite(x.to_numpy()).all():
raise ValueError('finite OHLC data required')
if not ((x.low <= x.close) & (x.close <= x.high) & (x.low > 0)).all():
raise ValueError('invalid price bounds')
c = x.close
out = pd.DataFrame(index=x.index)
out['sma20'] = c.rolling(20, min_periods=20).mean()
out['ema20'] = c.ewm(span=20, adjust=False, min_periods=20).mean()
d = c.diff().iloc[1:]
g, l = wilder(d.clip(lower=0), period), wilder(-d.clip(upper=0), period)
rsi = 100*g/(g+l)
rsi = rsi.mask((g == 0) & (l == 0), 50) # explicit flat-market convention
out['rsi'] = rsi.reindex(x.index)
fast = c.ewm(span=12, adjust=False, min_periods=12).mean()
slow = c.ewm(span=26, adjust=False, min_periods=26).mean()
out['macd'] = fast-slow
out['signal'] = out.macd.ewm(span=9, adjust=False, min_periods=9).mean()
out['hist'] = out.macd-out.signal
sd = c.rolling(20, min_periods=20).std(ddof=0)
out['bb_low'], out['bb_high'] = out.sma20-2*sd, out.sma20+2*sd
prev = c.shift(1)
tr = pd.concat([x.high-x.low,(x.high-prev).abs(),(x.low-prev).abs()],axis=1).max(axis=1)
out['atr'] = wilder(tr.iloc[1:],period).reindex(x.index)
return out작은 수를 넣기보다 경계 규칙 명시
14개 RSI 변화량에는 종가 15개가 필요합니다. 상승만 있으면 RSI는 100, 하락만 있으면 0입니다. 둘 다 없으면 이 예제는 명시적으로 50을 선택합니다. 다른 라이브러리는 0이나 정보 없음을 쓸 수 있으므로 규약 확인 없이 차트와 같다고 할 수 없습니다. 하락 0을 일괄 1e-9로 바꾸면 이 선택이 숨겨지고 규모에 따른 차이도 생깁니다.
여기 ATR은 직전 종가가 존재하는 첫 봉부터 사용하므로 초기 구간에 한 봉이 더 필요합니다. 입력은 이미 시간순·중복 없음이어야 하고 정한 결측 봉 규칙도 반영되어야 합니다.
해석하기 전에 손계산과 비교
종가 10,11,10,12와 기간 3이면 상승 평균 1, 하락 평균 1/3으로 RSI는 75입니다. 일정한 종가는 모집단 밴드 폭이 0이며 고저폭이 계속 2라면 준비 구간 뒤 ATR도 2입니다. 긴 차트 전에 이런 작은 사례를 먼저 맞춰 보세요.
좁은 밴드가 돌파 방향·시기를 예측하지 않으며 RSI 임계값도 매수 지시가 아닙니다. 완료 봉의 신호는 이후 실행 가능한 가격에 적용하고, 주변 파라미터와 별도 평가 데이터에서 비용까지 검증합니다. 상관성이 큰 지표 여러 개가 독립된 확인 여러 개를 뜻하지는 않습니다.
공식 자료와 함께 읽기
TA-Lib RSI formula · TA-Lib Wilder smoothing · pandas ewm conventions · Bollinger original explanation
내용·예제 검토: 2026-09-29
댓글
댓글 쓰기