효율적 시장 가설과 랜덤워크, 그리고 개인투자자의 생존법
"주가는 술 취한 사람의 걸음걸이와 같다." - 버튼 말킬
많은 초보 투자자들이 "세력이 있다", "차트에 패턴이 있다"라고 믿으며 주가를 예측하려 합니다. 하지만 노벨 경제학상 수상자 유진 파마(Eugene Fama)는 "시장 가격은 이미 이용 가능한 모든 정보를 반영하고 있다"는 '효율적 시장 가설(EMH)'을 주장했습니다. 정말 그럴까요? 파이썬을 통해 시장이 얼마나 무작위적인지 확인해 봅시다.
만약 어제 주가가 올랐다는 사실이 오늘 주가 상승에 영향을 준다면, 우리는 과거 데이터를 통해 돈을 벌 수 있습니다. 이를 통계적으로 '자기 상관(Autocorrelation)'이 있다고 합니다. 하지만 효율적인 시장이라면 어제의 움직임과 오늘의 움직임은 관계가 없어야(Random) 합니다.
우리는 파이썬을 이용해 실제 주가 데이터가 얼마나 예측 불가능한지 시각화해 볼 수 있습니다. 마치 삼성전자 주가처럼 가파르게 상승하다가 하락을 합니다.
위 그림을 실행해 보면 주가는 마치 어떤 추세가 있는 것처럼 보입니다. 하지만 이것은 완전히 무작위로 생성된 난수의 합일뿐입니다. 우리의 뇌는 무질서 속에서 질서를 찾으려 하기 때문에 우연한 등락을 '패턴'으로 착각하곤 합니다. 그리고 자 투자가의 입장이라면 이 주가가 계속 하락을 할까? 아니면 반등을 해서 계속 올라갈까? 는 절체절명의 위기를 구할 중요한 질문이 생깁니다. 예측의 문제이지요?
다음은 아래에 제공한 python를 한번 실행해서 구한 향후 주가 시나리오입니다.
그리고 또 다음은 python를 다시 한번 실행해서 구한 향후 주가 시나리오입니다. 결과가 매번 전혀 다르죠?
그리고 "또 다음은 python를 다시 한번 실행해서 구한 향후 주가 시나리오입니다." 수백 번 실행을 하면 그래프가 수백 번 바뀐다는 것도 여러분은 이해하셔야 합니다. 그리고 결론은 15만 전자인데 50일 후에는 오르기도 하고 폭락을 하기도 하고.... 그리고 200일은 시간이 긴 전망이라 그렇다 치고, 당자 내일 삼성전자의 가격은?, 오늘의 시가는? 오늘의 종가는? 그 대답은 하느님도 알 수 없고, 용하다는 점쟁이도 알 수 없고, 이재용 회장도 이재명 대통령도 알 수 없습니다. 그리고 만일 점장이가 매일 주가를 맞춘다면 점방은 문을 닫아야겠죠?
제 고등학교 때 담임선생님이 지리과목 선생님이었는데, 어디를 가도
A: "야 이 동네 철물물이 어디에 있어?
B: "몰라"
A: "지리 선생이 그것도 모르냐?
B: 내가 무슨 복덕방이냐~~~
이런 푸념을 하셨는데, 저도 박사에 주변에 친구들이 "당신은 과거 큰돈을 굴리던 금융전문가이고 경제학 박시이면서 매일 5시간씩 주가예측 예측 공부를 한다며? 그럼 내일 삼성전자 주가 얼마로 올라? "
이렇게 질문을 한다면 이제 여러분도 혈압부터 오르죠?
전문가란 특정시점의 주식가격 예측하는 것이 아니라, 저는 미국주식, 반도체시황, 한국의 경제여건, 일본과 중국의 수출입, 외환보유고, 각국의 금리상황, 외국인 투자자등 동향, 개인신용잔고 등 여러 변수들을 데이터로 분석을 해서 종합적으로 결론을 내리는데, 가령 시장에 붕괴조짐이 있다, 반도체 호황이 끝나면, 데이터썬터 호황, 그리고 데이터센터에는 막대한 전기가 들어가는데 전력산업에 대한 투자를 해야겠다 뭐 이런 투자논리의 개발하는 사람이죠. 저는 "시장에 붕괴가 오겠구나"를 분석하는 조기경보 또는 거품에 대한 연구자입니다. 가령 지금 너무 많이 사네 그런 분석을 해서 브런치글로도 올리고 신문기고도 하고 유튜브 방송도 구상 중입니다.
시장이 정말 효율적이라면, 개인이 정보를 통해 초과 수익을 내는 것은 거의 불가능에 가깝습니다. 하지만 시장은 완벽하지 않습니다. 때로는 공포와 탐욕으로 인해 '비효율적'인 구간이 발생합니다.
핵심 메시지: 시장을 이기려고(Market Timing) 애쓰기보다, 시장의 예측 불가능성을 인정하고 장기적으로 우상향 하는 자산에 머물러 있는 것이 초보 투자자가 가져야 할 가장 강력한 무기입니다.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rcParams
# LaTeX 폰트 및 스타일 설정
rcParams ['font.family'] = 'serif'
rcParams ['font.size'] = 12
rcParams ['text.usetex'] = False # Changed to False to fix the error
plt.style.use('seaborn-v0_8-whitegrid')
# 고정된 800일 데이터 (선형 상승)
days_fixed = np.arrange(800)
price_fixed = 100 + 0.05 * days_fixed
# 랜덤워크 함수
def random_walk(start_price, steps=200):
changes = np.random.normal(loc=0, scale=1, size=steps)
return start_price + np.cumsum(changes)
# 플롯 생성
fig, axes = plt.subplots(1, 3, figsize=(15, 5), sharey=True)
for i, ax in enumerate(axes, 1):
ax.plot(days_fixed, price_fixed, color='blue', lw=1.5, label=r'Fixed trend $(0 \leq t < 800)$')
days_random = np.arrange(800, 1000)
price_random = random_walk(price_fixed [-1], steps=len(days_random)) # Fixed: steps should match len(days_random)
ax.plot(days_random, price_random, color='orange', lw=1.5, label=r'Random walk $(800 \leq t < 1000)$')
ax.axvline(x=800, color='red', linestyle='--', lw=1.2, label=r'Prediction boundary $t=800$')
ax.set_title(rf"Simulation {i}", fontsize=14)
ax.set_xlabel(r"Days ($t$)", fontsize=12)
ax.set_ylabel(r"Price ($P_t$)", fontsize=12)
ax.legend(fontsize=10)
plt.tight_layout()
plt.show(block=False) # 실행 후 바로 종료되도록 설정
코드가 난해할 수 있어서 COLAB에서 GEMINI가 제공하는 코드 해설 기능을 통해 만든 해설입니다. 이 코드 많이 반복해보세요. 여러분도 구글등에서 유용한 코드를 구하면, COLAB에 paste에서, 코드로 수정받고, 설명도 들을 수 있어요.
이 셀의 코드는 주식 가격의 무작위 행보를 시뮬레이션하고 시각화하는 파이썬 코드입니다. 이전 단계에서 성공적으로 실행되었으며, 주요 내용은 다음과 같습니다:
라이브러리 임포트 및 설정: numpy와 matplotlib.pyplot을 임포트 하여 수치 계산 및 그래프 그리기에 사용합니다. matplotlib의 rcParams를 이용하여 폰트 스타일을 'serif'로 설정하고, 텍스트 렌더링에 LaTeX를 사용하지 않도록 text.usetex=False로 설정하여 발생할 수 있는 오류를 방지했습니다. 또한 seaborn-v0_8-whitegrid 스타일을 적용하여 그래프의 미적인 부분을 개선했습니다.
고정된 추세 데이터 생성: days_fixed = np.arrange(800)를 통해 0부터 799까지의 800일 데이터를 생성하고, price_fixed = 100 + 0.05 * days_fixed를 통해 초기 가격 100에서 시작하여 하루에 0.05씩 선형적으로 상승하는 가격 경로를 만듭니다. 이는 예측 가능한 고정된 시장 추세를 나타냅니다.
랜덤워크 함수 정의: random_walk(start_price, steps) 함수는 start_price에서 시작하여, 평균 0, 표준편차 1의 정규분포를 따르는 steps 개수만큼의 무작위 변화를 누적하여 새로운 가격 경로를 반환합니다. 이는 예측하기 어려운 시장의 무작위적인 움직임을 모방합니다.
시뮬레이션 및 시각화: plt.subplots(1, 3, figsize=(15, 5), sharey=True)를 사용하여 가로로 3개의 서브플롯을 가지는 그림을 생성합니다. 각 서브플롯(ax)에 대해: days_fixed와 price_fixed를 사용하여 고정된 추세선(파란색)을 그립니다. 800일 이후 1000일까지(days_random = np.arrange(800, 1000))의 200일 동안의 데이터를 위해 random_walk 함수를 호출하여 무작위 가격 경로(주황색)를 생성합니다. 이때 steps=len(days_random)을 사용하여 days_random의 길이와 price_random의 길이가 일치하도록 합니다. 이 부분은 이전에 발생했던 ValueError를 해결한 핵심 수정 사항입니다. t=800 지점에 수직 점선(빨간색)을 추가하여 고정된 추세와 랜덤워크가 만나는 '예측 경계'를 시각적으로 표시합니다. 각 서브플롯에 제목, x축 및 y축 레이블, 그리고 각 선의 의미를 설명하는 범례를 추가하여 가독성을 높입니다.
마지막으로
plt.tight_layout()
은 플롯 요소들이 겹치지 않도록 자동으로 조정하며,
plt.show(block=False)
는 그래프를 표시하고 코드 실행을 계속 진행하도록 합니다.
결론적으로 이 코드는 800일까지는 고정된 추세를 따르다가 800일 이후에는 랜덤워크를 따르는 세 가지 다른 주식 가격 시뮬레이션 경로를 시각화하여, 시장의 예측 가능 부분과 예측 불가능 부분을 동시에 보여주는 데 사용됩니다.