實作交易策略:黃金交叉與定期定額
有了技術指標之後,我們可以開始實作交易策略了!這一章我們將實作兩個最經典的策略,並比較它們的績效。
策略一:黃金交叉策略 (Golden Cross)
黃金交叉是技術分析中最經典的趨勢跟隨策略。當短期移動平均線向上突破長期移動平均線時,代表上升趨勢確立,是買進信號。
實作黃金交叉策略
import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 載入資料
df = yf.download("2330.TW", start="2020-01-01", end="2024-12-31")
close = df['Close']
# 計算移動平均線
df['MA10'] = close.rolling(window=10).mean()
df['MA30'] = close.rolling(window=30).mean()
# 產生交易信號
# 當 MA10 > MA30 時持倉 (1),否則空倉 (0)
df['Signal'] = 0
df.loc[df['MA10'] > df['MA30'], 'Signal'] = 1
# 計算每日報酬率
df['Return'] = close.pct_change()
# 策略報酬 = 信號 * 每日報酬(信號會在收盤後產生,所以用 shift 延遲一天)
df['Strategy_Return'] = df['Signal'].shift(1) * df['Return']
# 計算累積報酬
df['Cum_Strategy'] = (1 + df['Strategy_Return']).cumprod() - 1
df['Cum_BuyHold'] = (1 + df['Return']).cumprod() - 1
# 畫圖
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(14, 10), gridspec_kw={'height_ratios': [2, 1]})
# 上圖:價格與買賣點
ax1.plot(df.index, close, label='收盤價', alpha=0.5)
ax1.plot(df.index, df['MA10'], label='MA10', linewidth=1)
ax1.plot(df.index, df['MA30'], label='MA30', linewidth=1)
# 標示買進點
buy_signals = df[df['Signal'] == 1]
ax1.scatter(buy_signals.index, buy_signals['MA10'],
marker='^', color='g', s=50, label='買進信號', alpha=0.7)
sell_signals = df[df['Signal'] == 0]
sell_indices = sell_signals.index.difference(buy_signals.index)
ax1.scatter(sell_indices, sell_signals['MA30'].loc[sell_indices],
marker='v', color='r', s=50, label='賣出信號', alpha=0.7)
ax1.set_title('台積電 - 黃金交叉策略')
ax1.legend()
ax1.grid(True, alpha=0.3)
# 下圖:累積報酬率比較
ax2.plot(df.index, df['Cum_Strategy'] * 100, label='黃金交叉策略', color='green', linewidth=2)
ax2.plot(df.index, df['Cum_BuyHold'] * 100, label='買入持有', color='blue', linewidth=2, linestyle='--')
ax2.axhline(y=0, color='black', linestyle='-', alpha=0.2)
ax2.set_title('累積報酬率比較 (%)')
ax2.legend()
ax2.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
績效評估
# === 計算績效指標 ===
total_return_strategy = df['Cum_Strategy'].iloc[-1]
total_return_buyhold = df['Cum_BuyHold'].iloc[-1]
# 年化報酬率
trading_days = len(df)
annual_return_strategy = (1 + total_return_strategy) ** (252 / trading_days) - 1
annual_return_buyhold = (1 + total_return_buyhold) ** (252 / trading_days) - 1
# 夏普比率(假設無風險利率為 0)
sharpe_strategy = np.sqrt(252) * df['Strategy_Return'].mean() / df['Strategy_Return'].std()
sharpe_buyhold = np.sqrt(252) * df['Return'].mean() / df['Return'].std()
# 最大回撤
cumulative = (1 + df['Strategy_Return']).cumprod()
rolling_max = cumulative.cummax()
drawdown = (cumulative - rolling_max) / rolling_max
max_drawdown = drawdown.min()
print(f"=== 黃金交叉策略 vs 買入持有 ===")
print(f"\n策略總報酬率: {total_return_strategy*100:.2f}%")
print(f"買入持有總報酬率: {total_return_buyhold*100:.2f}%")
print(f"\n策略年化報酬率: {annual_return_strategy*100:.2f}%")
print(f"買入持有年化報酬率: {annual_return_buyhold*100:.2f}%")
print(f"\n策略夏普比率: {sharpe_strategy:.2f}")
print(f"買入持有夏普比率: {sharpe_buyhold:.2f}")
print(f"\n策略最大回撤: {max_drawdown*100:.2f}%")
策略二:定期定額 (Dollar Cost Averaging)
定期定額是最適合散戶的策略:每個月固定日期買入固定金額的股票,不管價格高低。
# === 定期定額回測 ===
monthly_investment = 10000 # 每個月投入 1 萬元
# 取得每月第一個交易日的索引
monthly_dates = df.resample('ME').first().index
# 模擬定期定額
total_shares = 0
total_invested = 0
portfolio_value = []
for date in df.index:
# 如果是每月第一個交易日,買入
if date in monthly_dates:
shares_bought = monthly_investment / close.loc[date]
total_shares += shares_bought
total_invested += monthly_investment
# 計算目前市值
current_value = total_shares * close.loc[date]
portfolio_value.append(current_value)
df['DCA_Value'] = portfolio_value
df['DCA_Return'] = (df['DCA_Value'] - total_invested) / total_invested
# 比較
print(f"=== 定期定額績效 ===")
print(f"總投入: {total_invested:,} 元")
print(f"最終市值: {df['DCA_Value'].iloc[-1]:,.0f} 元")
print(f"總報酬率: {df['DCA_Return'].iloc[-1]*100:.2f}%")
三種策略最終比較
plt.figure(figsize=(14, 7))
plt.plot(df.index, df['Cum_Strategy'] * 100, label='黃金交叉策略', linewidth=2)
plt.plot(df.index, df['Cum_BuyHold'] * 100, label='買入持有', linewidth=2, linestyle='--')
plt.plot(df.index, df['DCA_Return'] * 100, label='定期定額', linewidth=2, linestyle=':')
plt.axhline(y=0, color='black', alpha=0.2)
plt.title('三種策略累積報酬率比較 (%)')
plt.xlabel('日期')
plt.ylabel('累積報酬率 (%)')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
使用 Vibe Coding 實作交易策略
🔥 【交易策略詠唱範例】
「請幫我回測「MACD 金叉死叉策略」:1. 抓取 TSLA 過去 3 年的日資料。2. 計算 MACD (12, 26, 9)。3. 當 MACD 線向上突破訊號線時買進,向下突破時賣出。4. 計算策略的總報酬率、夏普比率與最大回撤。5. 畫出權益曲線與買賣點。6. 與買入持有策略比較。」
本日總結
在本章中,你學到了:
- ✅ 黃金交叉策略:根據移動平均線的交叉產生交易信號
- ✅ 定期定額策略:固定金額定期買入
- ✅ 績效比較:總報酬率、年化報酬率、夏普比率、最大回撤
- ✅ 權益曲線:視覺化策略的盈虧變化
- ✅ 三種策略比較:了解不同策略的優劣
下一章,我們將使用回測框架來更專業地評估策略!