ostock-backend / model /src /data /technical_indicators.py
johnaness's picture
Deploy OStock FastAPI backend to HF Space (Docker SDK, port 7860)
4be2d4d
"""
๊ธฐ์ˆ ์  ์ง€ํ‘œ ๊ณ„์‚ฐ ๊ด€๋ จ ํ•จ์ˆ˜ ๋ชจ์Œ
"""
import numpy as np
import pandas as pd
def calculate_ema_series(series, span):
"""์ฃผ์–ด์ง„ Series์— ๋Œ€ํ•ด ์ง€์ˆ˜์ด๋™ํ‰๊ท (EMA)์„ ๊ณ„์‚ฐ"""
return series.ewm(span=span, adjust=False).mean()
def calculate_macd(data, short_span, long_span, signal_span):
"""MACD, Signal Line ๊ณ„์‚ฐ"""
ema_short = calculate_ema_series(data['Close'], short_span)
ema_long = calculate_ema_series(data['Close'], long_span)
macd = ema_short - ema_long
signal = calculate_ema_series(macd, signal_span)
return macd, signal
def calculate_cmf(data, period):
"""Chaikin Money Flow ๊ณ„์‚ฐ"""
high = data['High']
low = data['Low']
close = data['Close']
volume = data['Volume']
# Money Flow Multiplier
mf_multiplier = ((close - low) - (high - close)) / (high - low).replace(0, 0.0001)
# Money Flow Volume
mf_volume = mf_multiplier * volume
# Chaikin Money Flow
cmf = mf_volume.rolling(window=period).sum() / volume.rolling(window=period).sum()
# ๊ฒฐ๊ณผ ์ €์žฅ
data[f'CMF_{period}'] = cmf
return data
def calculate_rsi(data, period=14):
"""RSI ๊ณ„์‚ฐ"""
close = data['Close']
delta = close.diff()
# ์ƒ์Šน/ํ•˜๋ฝ ๋ถ„๋ฆฌ
gain = delta.where(delta > 0, 0)
loss = -delta.where(delta < 0, 0)
# ํ‰๊ท  ๊ณ„์‚ฐ
avg_gain = gain.rolling(window=period).mean()
avg_loss = loss.rolling(window=period).mean()
# RS ๊ณ„์‚ฐ
rs = avg_gain / avg_loss.replace(0, 1e-10) # 0์œผ๋กœ ๋‚˜๋ˆ„๊ธฐ ๋ฐฉ์ง€
# RSI ๊ณ„์‚ฐ
rsi = 100 - (100 / (1 + rs))
# ๊ฒฐ๊ณผ ์ €์žฅ
data[f'RSI_{period}'] = rsi
return data
# -----------------------------
# ๊ธฐ์ˆ ์  ์ง€ํ‘œ ์ถ”๊ฐ€ ํ•จ์ˆ˜
# -----------------------------
def add_technical_indicators(df, ema_params, macd_params, cmf_period, rsi_params):
"""
์ฃผ๊ฐ€ ๋ฐ์ดํ„ฐ์— ์ตœ์ ํ™”๋œ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ชจ๋“  ๊ธฐ์ˆ ์  ์ง€ํ‘œ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ํ•จ์ˆ˜
"""
# EMA ๊ณ„์‚ฐ
df['EMA_short'] = calculate_ema_series(df['Close'], ema_params['short'])
df['EMA_long'] = calculate_ema_series(df['Close'], ema_params['long'])
df['EMA_diff'] = df['EMA_short'] - df['EMA_long']
# MACD ๊ณ„์‚ฐ
ema_fast = calculate_ema_series(df['Close'], macd_params['fast'])
ema_slow = calculate_ema_series(df['Close'], macd_params['slow'])
df['MACD'] = ema_fast - ema_slow
df['MACD_signal'] = calculate_ema_series(df['MACD'], macd_params['signal'])
df['MACD_diff'] = df['MACD'] - df['MACD_signal']
# CMF ๊ณ„์‚ฐ
df = calculate_cmf(df, cmf_period)
df['CMF'] = df[f'CMF_{cmf_period}']
df.drop(columns=[f'CMF_{cmf_period}'], inplace=True)
# RSI ๊ณ„์‚ฐ
df = calculate_rsi(df, rsi_params['period'])
df['RSI'] = df[f'RSI_{rsi_params["period"]}']
df.drop(columns=[f'RSI_{rsi_params["period"]}'], inplace=True)
# RSI ์ž„๊ณ„๊ฐ’ ์ €์žฅ
df['RSI_upper'] = rsi_params['upper_threshold']
df['RSI_lower'] = rsi_params['lower_threshold']
# ์ˆ˜์ต๋ฅ  ๊ณ„์‚ฐ
df['Return'] = df['Close'].pct_change()
return df