주식 분석 프로젝트 총정리
🇰🇷 한국 주식 기반 기술적 분석 시리즈 (2~7편 요약)
이 문서는 2편부터 7편까지 다뤄온 전략 분석 흐름을 한국 주식(삼성전자, SK하이닉스 등)에 전면 적용한 통합 설명입니다.
처음 보는 사람도 쉽게 따라올 수 있도록 각 단계마다 배경 설명 → 코드 → 출력 예시 → 해석의 구조로 차근차근 정리합니다.
2편 – 이동평균선(MA) 분석
● 개념
이동평균선(Moving Average)은 일정 기간 동안의 종가 평균을 선으로 연결한 지표입니다. 주가의 일시적 등락(노이즈)을 줄이고, 전반적인 추세(상승/하락)를 부드럽게 보여주는 데 사용됩니다.
- 단기선: MA5, MA20 (최근 5일/20일 평균)
- 중기선: MA60
- 장기선: MA120
● 한국 주식 실습 예시 (삼성전자)
import FinanceDataReader as fdr
import matplotlib.pyplot as plt
df = fdr.DataReader("005930", '2023-10-01')
df['MA20'] = df['Close'].rolling(window=20).mean()
df['MA60'] = df['Close'].rolling(window=60).mean()
plt.figure(figsize=(14, 5))
plt.plot(df['Close'], label='종가')
plt.plot(df['MA20'], label='MA20')
plt.plot(df['MA60'], label='MA60')
plt.title('삼성전자 이동평균선')
plt.legend()
plt.grid(True)
plt.show()
● 해석
- MA20이 MA60을 상향 돌파: 골든크로스 (상승 신호)
- MA20이 MA60을 하향 돌파: 데드크로스 (하락 신호)
3편 – 볼린저 밴드 & RSI
● 볼린저 밴드 개념
20일 이동평균선을 기준으로, 위아래로 2표준편차 범위를 띄운 밴드를 구성합니다. 주가가 이 밴드를 벗어날 때를 과매수/과매도 구간으로 판단할 수 있습니다.
● RSI 개념
RSI(Relative Strength Index)는 최근 14일 간의 상승폭과 하락폭을 비교하여 주가의 힘(모멘텀)을 나타내는 지표입니다.
- RSI > 70: 과매수 (매도 고려)
- RSI < 30: 과매도 (매수 고려)
● 실습 코드
df['MA20'] = df['Close'].rolling(window=20).mean()
df['STD20'] = df['Close'].rolling(window=20).std()
df['Upper'] = df['MA20'] + 2 * df['STD20']
df['Lower'] = df['MA20'] - 2 * df['STD20']
delta = df['Close'].diff()
gain = delta.where(delta > 0, 0)
loss = -delta.where(delta < 0, 0)
avg_gain = gain.rolling(14).mean()
avg_loss = loss.rolling(14).mean()
rs = avg_gain / avg_loss
df['RSI'] = 100 - (100 / (1 + rs))
df['RSI'].tail()
Date
2025-04-21 38.666667
2025-04-22 37.662338
2025-04-23 43.624161
2025-04-24 48.507463
2025-04-25 61.904762
Name: RSI, dtype: float64
4편 – 매매 전략 정의
● 전략 조건
- 매수: RSI < 30 AND 종가 < 하단 밴드
- 매도: RSI > 70 OR 종가 > 상단 밴드
● 포지션 보유 구현
df['Position'] = 0
position = 0
for i in range(1, len(df)):
if (df['RSI'][i] < 30) and (df['Close'][i] < df['Lower'][i]) and position == 0:
df.loc[df.index[i], 'Position'] = 1
position = 1
elif ((df['RSI'][i] > 70) or (df['Close'][i] > df['Upper'][i])) and position == 1:
df.loc[df.index[i], 'Position'] = 0
position = 0
else:
df.loc[df.index[i], 'Position'] = df.loc[df.index[i-1], 'Position']
5편 – 여러 종목에 전략 확장
● 목적
전략은 종목마다 성과가 다르게 나타납니다. 한국의 대표 우량주들에 같은 전략을 적용해 성과를 비교합니다.
● 대상 종목
- 삼성전자 (005930)
- SK하이닉스 (000660)
- LG에너지솔루션 (373220)
- 현대차 (005380)
6편 – 전략 조건 최적화
전략 수익률 향상을 위해 RSI 기준값(25~35), 볼린저 표준편차(1.8~2.2) 범위를 바꾸어 실험합니다.
def run_strategy(df, rsi_buy=30, rsi_sell=70, std_n=2.0):
df = df.copy()
df['MA20'] = df['Close'].rolling(window=20).mean()
df['STD20'] = df['Close'].rolling(window=20).std()
df['Upper'] = df['MA20'] + (std_n * df['STD20'])
df['Lower'] = df['MA20'] - (std_n * df['STD20'])
delta = df['Close'].diff()
gain = delta.where(delta > 0, 0)
loss = -delta.where(delta < 0, 0)
avg_gain = gain.rolling(window=14).mean()
avg_loss = loss.rolling(window=14).mean()
epsilon = 1e-10
avg_loss = avg_loss.replace(0, epsilon)
rs = avg_gain / avg_loss
df['RSI'] = 100 - (100 / (1 + rs))
buy_signal = (df['RSI'] < rsi_buy) & (df['Close'] < df['Lower'])
sell_signal = (df['RSI'] > rsi_sell) | (df['Close'] > df['Upper'])
df['Position'] = 0
position = 0
for i in range(1, len(df)):
if buy_signal.iloc[i] and position == 0:
df.at[df.index[i], 'Position'] = 1
position = 1
elif sell_signal.iloc[i] and position == 1:
df.at[df.index[i], 'Position'] = 0
position = 0
else:
df.at[df.index[i], 'Position'] = df.at[df.index[i-1], 'Position']
df['Daily Return'] = df['Close'].pct_change()
df['Strategy Return'] = df['Daily Return'] * df['Position'].shift(1)
df['Cumulative Return'] = (1 + df['Strategy Return']).cumprod()
df['Cumulative BuyHold'] = (1 + df['Daily Return']).cumprod()
return df
results = []
for rsi_buy in [25, 30, 35]:
for std in [1.8, 2.0, 2.2]:
ret = run_strategy(df, rsi_buy=rsi_buy, std_n=std)
results.append({'RSI_Buy': rsi_buy, 'STD': std, 'Return': ret})
● 결과 정리
RSI_Buy STD Return
30 2.0 1.23
25 2.2 1.20
7편 – 전략 성과 평가
● 주요 지표
- Final Return: 누적 수익률
- Sharpe Ratio: 리스크 대비 수익
- Max Drawdown: 최대 낙폭
- Win Rate: 수익 거래 비율
● 평가 코드
df = yf.download("005930.KS", period="1y")
# 2. ✅ MultiIndex를 평탄화
if isinstance(df.columns, pd.MultiIndex):
df.columns = df.columns.get_level_values(0)
# 3. 전략 적용
df = run_strategy(df)
# 4. 평가
returns = df['Strategy Return'].dropna()
sharpe = (returns.mean() / returns.std()) * np.sqrt(252)
max_dd = ((1 + returns).cumprod().cummax() - (1 + returns).cumprod()).max()
win_rate = (returns > 0).sum() / len(returns)
print({
'수익률' : win_rate,
'Sharpe': sharpe,
'Max Drawdown': max_dd,
'Win Rate': win_rate
})
● 예시 출력
{
'수익률': 0.23140495867768596,
'Sharpe': 0.15301356064010455,
'Max Drawdown': 0.46449534541370807,
'Win Rate': 0.23140495867768596
}
✅ 결론
- 기술적 분석 전략은 한국 주식에서도 효과적으로 활용 가능
- 단계별로 전략 수립 → 확장 → 조건 변경 → 성과 평가 구조가 중요
- Sharpe/MDD 같은 리스크 지표를 반드시 포함해야 실전에서 활용 가능
'Python' 카테고리의 다른 글
[주식 분석 프로젝트] 9편 – 전략의 실전 적용 가능성 검토 & 체결 시뮬레이션 (0) | 2025.04.30 |
---|---|
[주식 분석 프로젝트] 7편 – 전략 성과 평가: 수익률 vs 리스크 (0) | 2025.04.28 |
[주식 분석 프로젝트] 6편 – 전략 조건 최적화 실험 (0) | 2025.04.27 |
[주식 분석 프로젝트] 5편 – 전략의 종목별 확장 및 비교 (0) | 2025.04.26 |
[주식 분석 프로젝트] 4편 – 기술적 지표 전략 백테스팅 (0) | 2025.04.25 |