2025年9月8日 星期一

Backtrader 回測環境-計算資產增減

 

📖 使用說明

  1. 安裝必要套件:

    pip install yfinance mplfinance pandas openpyxl
  2. 打開 Jupyter Notebook / VS Code 執行此程式。

  3. 修改 symbol = "NVDA" → 你想要的股票代號。

  4. 執行後會看到:

    • K 線圖(附均線)

    • Excel 檔案(每日操作表)

    • 回測結果(初始 vs 最終資金)

  • 下載股票資料(MultiIndex 自動攤平)

  • 建立簡單均線交叉策略(MA10 與 MA50)

  • Backtrader 回測環境

  • 畫出回測圖表

  • 生成每日操作表 Excel

  • 這份程式碼的流程就是:

    1. 下載歷史股價。

    2. 計算移動平均線。

    3. 生成買賣訊號。

    4. 畫出 K 線圖。

    5. 存成 Excel。

    6. 根據訊號進行簡單回測,計算資產增減。

  • ==================================

    %matplotlib inline

    # -*- coding: utf-8 -*-
    import yfinance as yf
    import pandas as pd
    import mplfinance as mpf

    # -------------------------
    # 1️⃣ 下載歷史資料
    # -------------------------
    symbol = "NVDA"
    df = yf.download(symbol, start="2024-06-01", end="2025-09-01", auto_adjust=False)

    # 確認欄位
    print("欄位名稱:", df.columns)

    # 如果是 MultiIndex,去掉 Ticker 層級
    if isinstance(df.columns, pd.MultiIndex):
        df.columns = df.columns.get_level_values(0)

    # -------------------------
    # 2️⃣ 計算移動平均線
    # -------------------------
    df['MA10'] = df['Close'].rolling(10).mean()
    df['MA50'] = df['Close'].rolling(50).mean()

    # -------------------------
    # 3️⃣ 生成買賣信號
    # -------------------------
    df['Signal'] = 0
    df.iloc[10:, df.columns.get_loc('Signal')] = (
        (df['MA10'].iloc[10:] > df['MA50'].iloc[10:]).astype(int)
    )

    # -------------------------
    # 4️⃣ 畫 K 線圖
    # -------------------------
    mpf.plot(
        df,
        type='candle',
        style='yahoo',
        title=f"{symbol} K 線圖",
        volume=True,
        mav=(10, 50)
    )

    # -------------------------
    # 5️⃣ 存成 Excel
    # -------------------------
    df[['Open','High','Low','Close','Volume','MA10','MA50','Signal']].to_excel(f"{symbol}_daily_signals.xlsx")
    print(f"已生成每日操作表: {symbol}_daily_signals.xlsx")

    # -------------------------
    # 6️⃣ 簡單回測策略
    # -------------------------
    initial_cash = 100_000
    cash = initial_cash
    position = 0  # 持股數量
    for i in range(len(df)):
        if df['Signal'].iloc[i] == 1 and position == 0:
            # 買進全部資金
            position = cash / df['Close'].iloc[i]
            cash = 0
        elif df['Signal'].iloc[i] == 0 and position > 0:
            # 全部賣出
            cash = position * df['Close'].iloc[i]
            position = 0

    # 最後資產價值
    final_value = cash + position * df['Close'].iloc[-1]
    print(f"初始資金: {initial_cash:,.2f}")
    print(f"回測後資金: {final_value:,.2f}")

    ==================================



    ==================================

    1️⃣ 設定 Notebook 繪圖模式

    %matplotlib inline
    • 這行指令是 Jupyter Notebook 的魔法指令。

    • 作用:讓你畫的圖(例如 K 線圖)可以直接嵌入 Notebook 裡顯示,而不是跳出新視窗。


    2️⃣ 匯入套件

    import yfinance as yf import pandas as pd import mplfinance as mpf
    • yfinance: 從 Yahoo Finance 下載歷史股價資料。

    • pandas: 用來整理和操作資料表。

    • mplfinance: 畫股票的 K 線圖和成交量圖。


    3️⃣ 下載歷史股價

    symbol = "NVDA" df = yf.download(symbol, start="2024-06-01", end="2025-09-01", auto_adjust=False)
    • symbol 是股票代號(NVDA = Nvidia)。

    • start / end 是資料的時間範圍。

    • auto_adjust=False 保留原始股價,不自動調整除權息。

    • df 是一個 DataFrame,裡面有 Open, High, Low, Close, Volume, Adj Close 等欄位。


    4️⃣ 處理 MultiIndex

    if isinstance(df.columns, pd.MultiIndex): df.columns = df.columns.get_level_values(0)
    • 有時 yfinance 會回傳 MultiIndex 欄位,例如 ('Close', 'NVDA')。

    • 這裡把欄位簡化成單層名稱:Close, Open, High, Low, Volume, Adj Close。


    5️⃣ 計算移動平均線

    df['MA10'] = df['Close'].rolling(10).mean() df['MA50'] = df['Close'].rolling(50).mean()
    • MA10:10 日簡單移動平均(近 10 天的收盤價平均)。

    • MA50:50 日簡單移動平均。

    • 移動平均線常用於判斷趨勢:短期平均線在上,代表股價可能上升;短期在下,代表股價可能下降。


    6️⃣ 生成買賣信號

    df['Signal'] = 0 df.iloc[10:, df.columns.get_loc('Signal')] = ( (df['MA10'].iloc[10:] > df['MA50'].iloc[10:]).astype(int) )
    • 新增 Signal 欄位,初始值全部為 0(賣出/空倉)。

    • 規則:如果短期 MA10 > 長期 MA50 → 買入訊號(1),否則保持 0。

    • .iloc[10:] 是從第 10 行之後才開始計算,避免前面移動平均資料不足。


    7️⃣ 畫 K 線圖

    mpf.plot( df, type='candle', style='yahoo', title=f"{symbol} K 線圖", volume=True, mav=(10, 50) )
    • type='candle':畫 K 線圖。

    • style='yahoo':使用 Yahoo 風格顏色。

    • volume=True:顯示成交量。

    • mav=(10,50):在圖上疊加 10 日與 50 日移動平均線。


    8️⃣ 存成 Excel

    df[['Open','High','Low','Close','Volume','MA10','MA50','Signal']].to_excel(f"{symbol}_daily_signals.xlsx")
    • 將股價、移動平均線和買賣信號存成 Excel,方便後續分析。


    9️⃣ 簡單回測策略

    initial_cash = 100_000 cash = initial_cash position = 0 # 持股數量 for i in range(len(df)): if df['Signal'].iloc[i] == 1 and position == 0: position = cash / df['Close'].iloc[i] # 全部資金買進 cash = 0 elif df['Signal'].iloc[i] == 0 and position > 0: cash = position * df['Close'].iloc[i] # 全部賣出 position = 0 final_value = cash + position * df['Close'].iloc[-1]
    • 初始資金:100,000。

    • 策略:

      1. Signal=1 → 買入全部資金。

      2. Signal=0 → 賣出所有持股。

    • 最後資產 = 現金 + 持股市值。


    10️⃣ 顯示回測結果

    print(f"初始資金: {initial_cash:,.2f}") print(f"回測後資金: {final_value:,.2f}")
    • 顯示初始資金與策略回測後的總資產。



    # -------------------------
    # 7️⃣ 自動產生回測小報告
    # -------------------------
    report = f"""
    📊 回測報告 - {symbol}

    測試區間:{df.index[0].date()} ~ {df.index[-1].date()}
    策略:10日均線與50日均線黃金交叉

    初始資金:${initial_cash:,.2f}
    結束資金:${final_value:,.2f}
    報酬率:{(final_value/initial_cash - 1)*100:.2f}%

    交易次數:約 {df['Signal'].diff().abs().sum()/2:.0f} 次
    說明:
    - 當 MA10 上穿 MA50 → 產生買進訊號
    - 當 MA10 下穿 MA50 → 產生賣出訊號
    - 本策略為最簡單的「均線交叉」範例,僅示範 AI+Python 如何快速驗證想法。

    📖 小結:
    這份回測顯示,在此區間內策略的報酬率為 {(final_value/initial_cash - 1)*100:.2f}%。
    可進一步搭配 **停損機制、資金管理** 或 **TA-Lib 技術指標** 做優化。
    """

    print(report)



    ================================

    假設初始資金 100,000,最後變成 117,500,你會看到:

    📊 回測報告 - NVDA 測試區間:2024-06-03 ~ 2025-09-05 策略:10日均線與50日均線黃金交叉 初始資金:$100,000.00 結束資金:$117,500.00 報酬率:17.50% 交易次數:約 8 次 說明: - 當 MA10 上穿 MA50 → 產生買進訊號 - 當 MA10 下穿 MA50 → 產生賣出訊號 - 本策略為最簡單的「均線交叉」範例,僅示範 AI+Python 如何快速驗證想法。 📖 小結: 這份回測顯示,在此區間內策略的報酬率為 17.50%。 可進一步搭配 **停損機制、資金管理** 或 **TA-Lib 技術指標** 做優化。

    沒有留言:

    張貼留言