TQuant Lab MACD交易策略

TQuant Lab MACD交易策略
Photo by Erda Estremera on Unsplash

本文重點概要

  • 文章難度:★★☆☆☆
  • TQuant Lab 設計MACD交易策略
  • TQuant Lab 生成績效報表與視覺化圖表

前言

MACD代表“移動平均收斂/發散指標”(Moving Average Convergence Divergence),是一種常用於技術分析的工具,用於衡量一個資產的趨勢變化和動能。

MACD由兩個主要組件組成:

  1. 短期移動平均線:這是一個較短的移動平均線,通常使用較短的時間期間,例如12日移動平均。
  2. 長期移動平均線:這是一個較長的移動平均線,通常使用較長的時間期間,例如26日移動平均。

MACD的計算步驟如下:

  1. 計算快線和慢線的移動平均。
  2. 從快線減去慢線,得到差值,也就是快線。
  3. 計算這些差值的移動平均,這就是MACD指標本身,也就是慢線。

MACD的值可以是正值、負值或零,它們之間的相對位置和變化提供了一些關於資產價格趨勢的信息。

主要的MACD信號包括:

  1. 黃金交叉:當快線上穿慢線時,通常被視為一個上升趨勢的信號,可能預示著價格上升。
  2. 死亡交叉:當快線下穿慢線時,通常被視為一個下降趨勢的信號,可能預示著價格下降。

此外,MACD的柱狀圖(MACD柱)是快線與慢線之間差值的表示,柱的高度顯示了快線和慢線之間的差異。當MACD柱由負變成正,可能暗示著趨勢可能正在轉為上升。

編輯環境、模組需求與價量資料導入

本文使用 Mac 作業系統以及 jupyter notebook 作為編輯器。
在進入文章主軸之前,我們先傳入域名與金鑰,接著進行資料導入,
本篇實作使用台積電(2330)作為範例,並設定時間區段為 2018/12/30 ~ 2023/05/26 。

import os
import pandas as pd
import numpy as np

os.environ['TEJAPI_BASE'] = 'https://api.tej.com.tw'
os.environ['TEJAPI_KEY'] = 'your_key'
os.environ['mdate'] = '20181230 20230526'
os.environ['ticker'] = '2330'

# 使用 ingest 將股價資料導入暫存,並且命名該股票組合 (bundle) 為 tquant
!zipline ingest -b tquant

import talib
from zipline.api import order_target, record, symbol
from zipline.finance import commission, slippage
import matplotlib.pyplot as plt

建立 initialize 函式

首先,我們先建立 initialize 函式inintialize 函式用於定義交易開始前的交易環境,與此例中我們設置:

  • 股票代號
  • 持有股數
  • 是否持有部位
  • 交易手續費
  • 流動性滑價
def initialize(context):
context.sym = symbol('2330')
context.i = 0
context.invested = False
context.set_commission(commission.PerDollar(cost=0.00285))
context.set_slippage(slippage.VolumeShareSlippage())

建立 handle_date 函式

handle_data 函式用於處理每天的交易策略或行動,其中:

  • condition1: 當快線往上突破慢線,且MACD柱由負轉正,視為買入信號。
  • condition2: 當快線向下跌破慢線,且MACD柱由正轉負,且持有部位不為0,視為賣出信號。

我們使用talib來計算移動平均,並設定短期平均窗口期為 12 日、長期平均窗口期為 26日、MACD 線的窗口期為 9 日。

而除了預設輸出的報表資訊,我們還想記錄在交易策略執行時的收盤價、快線指數、慢線指數、是否買入、是否賣出等資訊,因此在最後的record增加輸出欄位。

def handle_data(context, data):
trailing_window = data.history(context.sym, 'price', 35, '1d')#35 = 26 + 9
if trailing_window.isnull().values.any():
return

short_ema = talib.EMA(trailing_window.values, timeperiod = 12)
long_ema = talib.EMA(trailing_window.values, timeperiod = 26)
dif = short_ema - long_ema
MACD = talib.EMA(dif, timeperiod = 9)
bar = dif - MACD
buy = False
sell = False

# Trading logic
#condition1
if (dif[-2] < MACD[-2]) and (dif[-1] > MACD[-1]) and (bar[-2] < 0) and (bar[-1] > 0):

order_target(context.sym, 1000)
context.invested = True
buy = True

#condition2
elif (dif[-2] > MACD[-2]) and (dif[-1] < MACD[-1]) and (bar[-2] > 0) and (bar[-1] < 0) and context.invested:
order_target(context.sym, 0)
context.invested = False
sell = True

# Save values for later inspection
record(TSMC = data.current(symbol('2330'), 'close'),
dif = dif[-1],
MACD = MACD[-1],
bar = bar[-1],
buy = buy,
sell = sell)

建立 analyze 函式

analyze中使用 matplotlib.pyplot 繪製 投資組合價值折線圖 與 MACD 指標圖。

我們計畫輸出兩張圖表,第一張為投資組合價值折線圖,負責記錄投資組合價值的變化趨勢;第二張為 MACD 指標圖,負責記錄 快線、慢線、MACD柱的趨勢變化,以及買賣點的標記。

# Note: this function can be removed if running
# this algorithm on quantopian.com
def analyze(context=None, results=None):
import matplotlib.pyplot as plt
import logbook
logbook.StderrHandler().push_application()
log = logbook.Logger('Algorithm')

fig = plt.figure()
ax1 = fig.add_subplot(211)
results.portfolio_value.plot(ax=ax1)
ax1.set_ylabel('Portfolio value (TWD)')
ax2 = fig.add_subplot(212)
ax2.set_ylabel('MACD')
# If data has been record()ed, then plot it.
# Otherwise, log the fact that no data has been recorded.
if 'dif' in results and 'MACD' in results:
results[['dif', 'MACD']].plot(ax=ax2)
ax2.plot(
results.index[results["buy"] == True],
results.loc[results["buy"] == True, 'MACD'],
'^',
markersize=10,
color='m',
)
ax2.plot(
results.index[results["sell"] == True],
results.loc[results["sell"] == True, 'MACD'],
'v',
markersize=10,
color='k',
)
ax3 = ax2.twinx()
colors = ["red" if i > 0 else "green" for i in results['bar']]
ax3.bar(results.index, results['bar'], color=colors, alpha=0.5, width=0.4, label='MACD Bar')

lines, labels = ax2.get_legend_handles_labels()
bars, bar_labels = ax3.get_legend_handles_labels()
ax2.legend(lines + bars, labels + bar_labels, loc='upper right')

plt.gcf().set_size_inches(18, 8)
else:
msg = 'TSMC - dif and MACD data not captured using record().'
ax2.annotate(msg, xy=(0.1, 0.5))
log.info(msg)
plt.show()

執行交易策略

使用 run_algorithm 執行上述所編撰的交易策略,設置交易期間為 2018-12-30 到 2023-05-26,初始資金為 100,000 元,所使用資料集為 tquant,其中輸出的變數 results 就是每日績效與交易的明細表。

from zipline import run_algorithm

start_date = pd.Timestamp('2018-12-30',tz='utc')
end_date = pd.Timestamp('2023-05-26',tz='utc')
results = run_algorithm(start= start_date,
end=end_date,
initialize=initialize,
capital_base=1e6,
analyze=analyze,
handle_data=handle_data,
data_frequency='daily',
bundle='tquant'
)
投資組合價值折線圖 與 MACD 指標圖
投資組合價值折線圖 與 MACD 指標圖

績效報表

交易策略績效報表
交易策略績效報表

結論

由上述報表中,我們可以看到投組價值約增加了百分之三十,而經由MACD 指標圖可以明確了解每個交易動作的時間點及趨勢表現。透過TQuant Lab,能大幅度的減少程式碼的複雜度,使用少量程式碼即可實現複雜回測系統。然而需要注意的是,雖然MACD是一個流行的技術分析工具,但它並非絕對可靠,單獨使用可能會產生虛假的信號。通常,技術分析者會將MACD與其他指標和分析方法結合使用,以做出更準確的判斷。

溫馨提醒,本次策略與標的僅供參考,不代表任何商品或投資上的建議。之後也會介紹使用TEJ資料庫來建構各式指標,並回測指標績效,所以歡迎對各種交易回測有興趣的讀者,選購 TEJ E-Shop 的相關方案,用高品質的資料庫,建構出適合自己的交易策略。

原始碼

延伸閱讀

相關連結

返回總覽頁
Procesing