如何和 AI 交互構建 SPY 雙均線策略回測程序

手把手教你與 AI 對話,從零開始構建完整的量化回測系統

2026年2月4日
閱讀時間 20 分鐘
江景哲

1. 為什麼要用 AI 輔助編程?

2024 年以來,AI 編程助手(如 ChatGPT、Claude、GitHub Copilot)已經成為程序員的標配工具。對於量化交易開發來說,AI 可以幫你:

💡 本文使用的 AI 工具:

Claude 3.5 / ChatGPT-4o 都可以完成本教程。推薦使用 Claude,代碼質量更高。

接下來,我會展示完整的對話過程,你可以直接複製這些 Prompt 來復現整個開發流程。

2. 雙均線策略原理

在開始編程之前,先快速了解我們要實現的策略:

什麼是雙均線策略?

雙均線策略(Dual Moving Average)是最經典的趨勢跟蹤策略之一,使用兩條移動平均線:

交易信號

信號 條件 操作
🟢 金叉(Golden Cross) 快線從下方穿越慢線 買入
🔴 死叉(Death Cross) 快線從上方穿越慢線 賣出

好了,原理就這麼簡單。現在讓我們開始和 AI 對話!

3. 第一步:讓 AI 獲取數據

Prompt #1:獲取 SPY 歷史數據

📝 複製這段 Prompt
我想用 Python 獲取 SPY(標普500 ETF)最近 10 年的日 K 線數據。 要求: 1. 使用 yfinance 庫 2. 數據包含 date, open, high, low, close, volume 3. 保存為 CSV 文件 4. 打印數據預覽 請提供完整可運行的代碼。

AI 生成的代碼

import yfinance as yf
import pandas as pd
from datetime import datetime, timedelta

def download_spy_data():
    """下載 SPY 最近 10 年的日 K 線數據"""
    
    # 計算日期範圍
    end_date = datetime.now()
    start_date = end_date - timedelta(days=365*10)
    
    print(f"正在下載 SPY 數據...")
    print(f"日期範圍: {start_date.strftime('%Y-%m-%d')} 至 {end_date.strftime('%Y-%m-%d')}")
    
    # 使用 yfinance 下載數據
    spy = yf.Ticker("SPY")
    df = spy.history(start=start_date, end=end_date, interval="1d")
    
    # 重置索引,讓 date 成為一列
    df = df.reset_index()
    
    # 重命名列
    df = df.rename(columns={
        'Date': 'date',
        'Open': 'open',
        'High': 'high',
        'Low': 'low',
        'Close': 'close',
        'Volume': 'volume'
    })
    
    # 只保留需要的列
    df = df[['date', 'open', 'high', 'low', 'close', 'volume']]
    
    # 保存為 CSV
    filename = 'spy_daily_10years.csv'
    df.to_csv(filename, index=False)
    
    print(f"\n✅ 數據下載完成!共 {len(df)} 條記錄")
    print(f"已保存至: {filename}")
    print(f"\n數據預覽:")
    print(df.head(10))
    print(f"\n...\n")
    print(df.tail(5))
    
    return df

if __name__ == "__main__":
    df = download_spy_data()
✅ 運行結果:

成功獲取約 2500 條數據,保存在 spy_daily_10years.csv

4. 第二步:讓 AI 編寫策略邏輯

Prompt #2:實現雙均線策略

📝 複製這段 Prompt
現在我有了 SPY 的日 K 線數據(CSV 文件),請幫我實現一個雙均線策略回測。 策略邏輯: - 快線:10 日簡單移動平均線(SMA10) - 慢線:30 日簡單移動平均線(SMA30) - 金叉(快線上穿慢線)買入 - 死叉(快線下穿慢線)賣出 - 初始資金:100000 美元 - 每次全倉交易 要求: 1. 使用 Backtrader 框架 2. 輸出每筆交易記錄 3. 輸出最終收益率、年化收益率、最大回撤 4. 代碼結構清晰,有註釋 請提供完整代碼。

AI 生成的代碼

import backtrader as bt
import pandas as pd
from datetime import datetime

class DualSMAStrategy(bt.Strategy):
    """雙均線策略"""
    
    params = (
        ('fast_period', 10),   # 快線周期
        ('slow_period', 30),   # 慢線周期
    )
    
    def __init__(self):
        # 計算均線
        self.fast_sma = bt.indicators.SMA(
            self.data.close, 
            period=self.params.fast_period
        )
        self.slow_sma = bt.indicators.SMA(
            self.data.close, 
            period=self.params.slow_period
        )
        
        # 交叉信號
        self.crossover = bt.indicators.CrossOver(self.fast_sma, self.slow_sma)
        
        # 記錄訂單
        self.order = None
        
    def log(self, txt, dt=None):
        """日誌輸出"""
        dt = dt or self.datas[0].datetime.date(0)
        print(f'{dt.isoformat()} {txt}')
    
    def notify_order(self, order):
        """訂單狀態通知"""
        if order.status in [order.Completed]:
            if order.isbuy():
                self.log(f'🟢 買入執行: 價格={order.executed.price:.2f}, '
                        f'成本={order.executed.value:.2f}, '
                        f'手續費={order.executed.comm:.2f}')
            else:
                self.log(f'🔴 賣出執行: 價格={order.executed.price:.2f}, '
                        f'成本={order.executed.value:.2f}, '
                        f'手續費={order.executed.comm:.2f}')
        self.order = None
    
    def next(self):
        """每個 bar 執行的邏輯"""
        # 如果有未完成訂單,不操作
        if self.order:
            return
        
        # 沒有持倉
        if not self.position:
            # 金叉買入
            if self.crossover > 0:
                self.log(f'📈 金叉信號! 快線={self.fast_sma[0]:.2f}, 慢線={self.slow_sma[0]:.2f}')
                self.order = self.buy()
        else:
            # 死叉賣出
            if self.crossover < 0:
                self.log(f'📉 死叉信號! 快線={self.fast_sma[0]:.2f}, 慢線={self.slow_sma[0]:.2f}')
                self.order = self.sell()


def run_backtest():
    """運行回測"""
    # 創建回測引擎
    cerebro = bt.Cerebro()
    
    # 添加策略
    cerebro.addstrategy(DualSMAStrategy)
    
    # 加載數據
    data = bt.feeds.GenericCSVData(
        dataname='spy_daily_10years.csv',
        datetime=0,
        open=1,
        high=2,
        low=3,
        close=4,
        volume=5,
        dtformat='%Y-%m-%d',
        fromdate=datetime(2016, 1, 1),
        todate=datetime(2026, 1, 1)
    )
    cerebro.adddata(data)
    
    # 設置初始資金
    cerebro.broker.setcash(100000.0)
    
    # 設置手續費
    cerebro.broker.setcommission(commission=0.001)  # 0.1%
    
    # 設置全倉交易
    cerebro.addsizer(bt.sizers.AllInSizer, percents=95)
    
    # 添加分析器
    cerebro.addanalyzer(bt.analyzers.Returns, _name='returns')
    cerebro.addanalyzer(bt.analyzers.DrawDown, _name='drawdown')
    cerebro.addanalyzer(bt.analyzers.TradeAnalyzer, _name='trades')
    
    # 運行回測
    print('=' * 60)
    print('SPY 雙均線策略回測')
    print('=' * 60)
    print(f'初始資金: ${cerebro.broker.getvalue():,.2f}')
    print('=' * 60)
    
    results = cerebro.run()
    strat = results[0]
    
    # 輸出結果
    print('=' * 60)
    print('回測結果')
    print('=' * 60)
    
    final_value = cerebro.broker.getvalue()
    print(f'最終資金: ${final_value:,.2f}')
    print(f'總收益率: {(final_value/100000 - 1)*100:.2f}%')
    
    # 年化收益率
    returns = strat.analyzers.returns.get_analysis()
    print(f'年化收益率: {returns["rnorm100"]:.2f}%')
    
    # 最大回撤
    drawdown = strat.analyzers.drawdown.get_analysis()
    print(f'最大回撤: {drawdown["max"]["drawdown"]:.2f}%')
    
    # 交易統計
    trades = strat.analyzers.trades.get_analysis()
    if trades.total.total > 0:
        print(f'總交易次數: {trades.total.total}')
        print(f'盈利次數: {trades.won.total}')
        print(f'虧損次數: {trades.lost.total}')
        print(f'勝率: {trades.won.total/trades.total.total*100:.1f}%')
    
    return cerebro, results


if __name__ == "__main__":
    cerebro, results = run_backtest()

運行結果示例

============================================================
SPY 雙均線策略回測
============================================================
初始資金: $100,000.00
============================================================
2016-02-16 📈 金叉信號! 快線=187.23, 慢線=186.95
2016-02-16 🟢 買入執行: 價格=187.50, 成本=99,750.00, 手續費=99.75
2016-06-27 📉 死叉信號! 快線=202.15, 慢線=202.48
2016-06-27 🔴 賣出執行: 價格=201.85, 成本=107,382.50, 手續費=107.38
...
============================================================
回測結果
============================================================
最終資金: $215,832.50
總收益率: 115.83%
年化收益率: 8.12%
最大回撤: 23.45%
總交易次數: 42
盈利次數: 18
虧損次數: 24
勝率: 42.9%

5. 第三步:讓 AI 完善回測框架

基礎版跑通了,但我們想要更多功能。繼續向 AI 提需求:

Prompt #3:添加參數優化

📝 複製這段 Prompt
很好!現在請幫我添加參數優化功能: 1. 遍歷不同的快線周期(5, 10, 15, 20) 2. 遍歷不同的慢線周期(20, 30, 40, 50, 60) 3. 找出收益率最高的參數組合 4. 輸出一個結果對比表格 在原有代碼基礎上修改。

AI 補充的優化代碼

def optimize_parameters():
    """參數優化"""
    results_list = []
    
    fast_periods = [5, 10, 15, 20]
    slow_periods = [20, 30, 40, 50, 60]
    
    total = len(fast_periods) * len(slow_periods)
    count = 0
    
    print("開始參數優化...")
    print(f"共 {total} 種組合\n")
    
    for fast in fast_periods:
        for slow in slow_periods:
            # 快線必須小於慢線
            if fast >= slow:
                continue
                
            count += 1
            
            # 創建回測引擎
            cerebro = bt.Cerebro()
            cerebro.addstrategy(DualSMAStrategy, 
                              fast_period=fast, 
                              slow_period=slow)
            
            # 加載數據
            data = bt.feeds.GenericCSVData(
                dataname='spy_daily_10years.csv',
                datetime=0, open=1, high=2, low=3, close=4, volume=5,
                dtformat='%Y-%m-%d',
                fromdate=datetime(2016, 1, 1),
                todate=datetime(2026, 1, 1)
            )
            cerebro.adddata(data)
            cerebro.broker.setcash(100000.0)
            cerebro.broker.setcommission(commission=0.001)
            cerebro.addsizer(bt.sizers.AllInSizer, percents=95)
            cerebro.addanalyzer(bt.analyzers.Returns, _name='returns')
            cerebro.addanalyzer(bt.analyzers.DrawDown, _name='drawdown')
            
            # 運行
            result = cerebro.run()[0]
            
            final_value = cerebro.broker.getvalue()
            returns = result.analyzers.returns.get_analysis()
            drawdown = result.analyzers.drawdown.get_analysis()
            
            results_list.append({
                'fast': fast,
                'slow': slow,
                'return': (final_value/100000 - 1) * 100,
                'annual_return': returns.get('rnorm100', 0),
                'max_drawdown': drawdown['max']['drawdown']
            })
            
            print(f"[{count}/{total}] SMA({fast},{slow}): "
                  f"收益={results_list[-1]['return']:.1f}%, "
                  f"回撤={results_list[-1]['max_drawdown']:.1f}%")
    
    # 轉為 DataFrame 並排序
    df = pd.DataFrame(results_list)
    df = df.sort_values('return', ascending=False)
    
    print("\n" + "=" * 60)
    print("參數優化結果(按收益率排序)")
    print("=" * 60)
    print(df.to_string(index=False))
    
    # 最優參數
    best = df.iloc[0]
    print(f"\n🏆 最優參數: SMA({int(best['fast'])}, {int(best['slow'])})")
    print(f"   收益率: {best['return']:.2f}%")
    print(f"   年化收益: {best['annual_return']:.2f}%")
    print(f"   最大回撤: {best['max_drawdown']:.2f}%")
    
    return df

# 運行優化
optimize_parameters()

6. 第四步:讓 AI 添加可視化

Prompt #4:繪製策略圖表

📝 複製這段 Prompt
最後,請幫我添加可視化功能: 1. 繪製 K 線圖 + 雙均線 2. 標記買賣點 3. 繪製資金曲線 4. 繪製回撤曲線 使用 matplotlib,圖表要美觀專業。

AI 生成的可視化代碼

import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import numpy as np

def plot_strategy_result(cerebro, results):
    """繪製策略結果圖表"""
    
    # 設置中文字體
    plt.rcParams['font.sans-serif'] = ['Arial Unicode MS', 'SimHei']
    plt.rcParams['axes.unicode_minus'] = False
    
    # 創建圖表
    fig, axes = plt.subplots(3, 1, figsize=(14, 10), 
                             gridspec_kw={'height_ratios': [3, 1, 1]})
    
    # 圖1: K線 + 均線 + 買賣點
    ax1 = axes[0]
    
    # 獲取數據
    strat = results[0]
    data = strat.data
    
    dates = [bt.num2date(x) for x in data.datetime.array]
    closes = data.close.array
    fast_sma = strat.fast_sma.array
    slow_sma = strat.slow_sma.array
    
    ax1.plot(dates, closes, label='SPY', color='#1f77b4', linewidth=1)
    ax1.plot(dates, fast_sma, label=f'SMA{strat.params.fast_period}', 
             color='#ff7f0e', linewidth=1.5)
    ax1.plot(dates, slow_sma, label=f'SMA{strat.params.slow_period}', 
             color='#2ca02c', linewidth=1.5)
    
    ax1.set_title('SPY 雙均線策略回測', fontsize=14, fontweight='bold')
    ax1.set_ylabel('價格 ($)')
    ax1.legend(loc='upper left')
    ax1.grid(True, alpha=0.3)
    
    # 圖2: 資金曲線
    ax2 = axes[1]
    # ... 資金曲線繪製代碼
    ax2.set_ylabel('資金 ($)')
    ax2.set_title('資金曲線', fontsize=12)
    ax2.grid(True, alpha=0.3)
    
    # 圖3: 回撤曲線
    ax3 = axes[2]
    # ... 回撤曲線繪製代碼
    ax3.fill_between(dates, drawdown_pct, 0, color='red', alpha=0.3)
    ax3.set_ylabel('回撤 (%)')
    ax3.set_title('回撤曲線', fontsize=12)
    ax3.grid(True, alpha=0.3)
    
    plt.tight_layout()
    plt.savefig('spy_dual_sma_backtest.png', dpi=150, bbox_inches='tight')
    plt.show()
    
    print("\\n📊 圖表已保存至: spy_dual_sma_backtest.png")
💡 運行完整代碼:

將以上所有代碼整合,運行後會生成專業的回測報告和圖表。完整代碼已上傳至 GitHub

7. 與 AI 交互的技巧總結

7.1 如何寫好 Prompt

技巧 說明 示例
明確目標 告訴 AI 你要做什麼 「實現一個雙均線策略回測」
指定技術棧 告訴 AI 用什麼庫/框架 「使用 Backtrader 框架」
列出要求 用列表說明具體需求 「1. 輸出交易記錄 2. 計算最大回撤」
給出示例 如果有具體格式要求 「輸出格式:日期 | 信號 | 價格」
迭代改進 逐步添加功能 「很好,現在請添加參數優化」

7.2 常見問題處理

⚠️ AI 生成的代碼報錯了?

直接把錯誤信息複製給 AI:「運行報錯:[粘貼錯誤信息],請修復」

⚠️ AI 理解錯了你的需求?

更具體地描述:「不是這樣,我的意思是 [更詳細的說明]」

7.3 完整工作流程

  1. 第一輪:讓 AI 生成基礎框架代碼
  2. 運行測試:先跑起來看看效果
  3. 第二輪:針對問題讓 AI 修改/優化
  4. 第三輪:添加新功能(可視化、參數優化等)
  5. 最終:整理代碼,添加註釋
🎉 總結:

通過 4 輪對話,我們完成了一個完整的 SPY 雙均線策略回測程序,包括:數據獲取 → 策略實現 → 參數優化 → 可視化。這就是 AI 輔助編程的威力!

想要更系統地學習量化交易?在我的課程中,你將學會更多策略和實戰技巧。課程中也會大量使用 AI 輔助編程,讓你快速上手。

江景哲

江景哲

Zero2Quant 課程講師 · 全職量化交易者

想要更系統地學習量化交易?

10節實戰課程,AI 輔助教學,從零基礎到自動化交易系統

了解完整課程 →