2025年9月7日 星期日

Pandas/Numpy 寫 MACD 與 RSI

 

我幫你寫一個 完整範例,包含:

  • 均線 MA10 / MA50

  • MACD / MACD Signal / MACD Histogram

  • RSI

  • 日報酬率 / 累積報酬率

  • 繪圖

 

import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# -------------------------
# 下載股價資料
# -------------------------
htc = yf.download("2498.TW", start="2023-01-01", end="2025-09-01", auto_adjust=True)
nvda = yf.download("NVDA", start="2023-01-01", end="2025-09-01", auto_adjust=True)

# -------------------------
# 指標函數(純 Pandas/Numpy)
# -------------------------
def add_indicators(df):
    close = df['Close']
    
    # 均線
    df['MA10'] = close.rolling(10).mean()
    df['MA50'] = close.rolling(50).mean()
    
    # 報酬率
    df['Daily_Return'] = close.pct_change()
    df['Cumulative_Return'] = (1 + df['Daily_Return']).cumprod() - 1
    
    # -------------------------
    # MACD
    # -------------------------
    ema12 = close.ewm(span=12, adjust=False).mean()
    ema26 = close.ewm(span=26, adjust=False).mean()
    df['MACD'] = ema12 - ema26
    df['MACD_Signal'] = df['MACD'].ewm(span=9, adjust=False).mean()
    df['MACD_Hist'] = df['MACD'] - df['MACD_Signal']
    
    # -------------------------
    # RSI
    # -------------------------
    delta = close.diff()
    gain = delta.clip(lower=0)
    loss = -delta.clip(upper=0)
    
    avg_gain = gain.rolling(14).mean()
    avg_loss = loss.rolling(14).mean()
    
    # 平滑版 RSI
    rs = avg_gain / avg_loss
    df['RSI'] = 100 - (100 / (1 + rs))
    
    return df

# -------------------------
# 套用指標
# -------------------------
htc = add_indicators(htc)
nvda = add_indicators(nvda)

# -------------------------
# 畫圖函數
# -------------------------
def plot_stock(df, title="Stock Analysis"):
    fig, axs = plt.subplots(3,1, figsize=(14,12), sharex=True)
    
    # 收盤價 + 均線
    axs[0].plot(df.index, df['Close'], label='Close', color='blue')
    axs[0].plot(df.index, df['MA10'], label='MA10', color='orange')
    axs[0].plot(df.index, df['MA50'], label='MA50', color='green')
    axs[0].set_ylabel('Price')
    axs[0].legend()
    axs[0].grid(True)
    
    # MACD
    axs[1].plot(df.index, df['MACD'], label='MACD', color='red')
    axs[1].plot(df.index, df['MACD_Signal'], label='Signal', color='purple')
    axs[1].bar(df.index, df['MACD_Hist'], label='Hist', color='grey', alpha=0.3)
    axs[1].set_ylabel('MACD')
    axs[1].legend()
    axs[1].grid(True)
    
    # RSI
    axs[2].plot(df.index, df['RSI'], label='RSI', color='brown')
    axs[2].axhline(70, color='red', linestyle='--')
    axs[2].axhline(30, color='green', linestyle='--')
    axs[2].set_ylabel('RSI')
    axs[2].legend()
    axs[2].grid(True)
    
    plt.suptitle(title)
    plt.show()

# -------------------------
# 畫圖
# -------------------------
plot_stock(htc, title="HTC Stock Analysis")
plot_stock(nvda, title="NVDA Stock Analysis")

這個版本完全不用 ta 套件,指標都是 自己算 的:

  • MACD = EMA12 - EMA26

  • MACD Signal = MACD 9日 EMA

  • RSI = 14日平均漲幅 / 平均跌幅






沒有留言:

張貼留言