NumPy 是 Python 進行技術分析和量化交易的根本,其高效的陣列操作能力至關重要。技術分析仰賴對歷史資料的處理與模式識別,因此熟練運用 NumPy 操作陣列,包含新增或刪除欄位、列,以及調整數值精確度等,是不可或缺的技能。同時,理解如何建構訊號函式,並將其視覺化,才能有效地評估交易策略。最後,透過計算命中率和回報率等績效指標,才能客觀地檢視策略的有效性,並據此調整最佳化。
陣列操作與數值處理函式
在進行技術分析與量化交易時,陣列操作與數值處理是不可或缺的技能。Python 提供了一個強大的工具 NumPy,使得陣列操作變得簡單高效。本章將介紹幾個重要的函式,用於陣列的欄位增刪、列的增刪以及數值的四捨五入。
新增欄位至陣列的函式
有時候,我們需要在現有的陣列中新增欄位以儲存額外的資訊。以下函式 add_column 實作了這一功能:
def add_column(data, times):
for i in range(1, times + 1):
new = np.zeros((np.shape(data)[0], 1), dtype=float)
data = np.hstack((data, new))
return data
內容解密:
- 迴圈執行
times次,每次新增一個新的欄位。 - 使用
np.zeros建立一個全零的陣列,其行數與原始資料相同,欄位數為 1。 - 使用
np.hstack將新的欄位堆積疊到原始資料的右側。
從陣列中刪除欄位的函式
有時候,我們需要從現有的陣列中刪除某些欄位。以下函式 delete_column 實作了這一功能:
def delete_column(data, index, times):
for i in range(1, times + 1):
data = np.delete(data, index, axis=1)
return data
內容解密:
- 迴圈執行
times次,每次刪除一個指定的欄位。 - 使用
np.delete刪除指定的欄位,axis=1表示刪除欄位。 - 索引
index指定了要刪除的起始欄位。
新增列至陣列的函式
有時候,我們需要在現有的陣列末尾新增列以儲存額外的資訊。以下函式 add_row 實作了這一功能:
def add_row(data, times):
for i in range(1, times + 1):
columns = np.shape(data)[1]
new = np.zeros((1, columns), dtype=float)
data = np.append(data, new, axis=0)
return data
內容解密:
- 迴圈執行
times次,每次新增一個新的列。 - 使用
np.shape(data)[1]取得原始資料的欄位數,並建立一個全零的新列。 - 使用
np.append將新的列附加到原始資料的末尾。
從陣列中刪除列的函式
在計算技術指標時,有時候需要刪除陣列開頭的某些列以避免無效值。以下函式 delete_row 實作了這一功能:
def delete_row(data, number):
data = data[number:, ]
return data
內容解密:
- 直接從指定的索引
number開始保留資料,忽略之前的列。
基本陣列語法與操作
在 Python 中參照資料需要熟悉以下基本語法:
my_data:參照整個陣列。my_data[:100, ]:參照前 100 行。my_data[:100, 0:2]:參照前 100 行的前兩個欄位。my_data[:, 6]:參照所有行的第七個欄位。my_data[-500:, ]:參照最後 500 行。
四捨五入函式
在某些技術分析模式中,需要對資料進行四捨五入。以下函式 rounding 實作了這一功能:
def rounding(data, how_far):
data = data.round(decimals=how_far)
return data
內容解密:
- 使用內建的
round方法對資料進行四捨五入。 how_far指定了小數點後的位數。
練習與應用
假設你有一個 OHLC(開、高、低、收)陣列,以下是一些範例操作:
- 新增兩個欄位:
my_data = add_column(my_data, 2) - 從第二個欄位開始刪除三個欄位:
my_data = delete_column(my_data, 1, 3) - 在陣列末尾新增 11 列:
my_data = add_row(my_data, 11) - 刪除前四列:
my_data = delete_row(my_data, 4)
透過這些基本的陣列操作與數值處理函式,你可以更靈活地處理和分析金融資料,為進一步的量化分析奠定基礎。
建立訊號演算法
本章節將探討如何建立訊號演算法,以識別有效的交易訊號。首先,我們需要定義一個假設的K線圖形態(Alpha Pattern),然後根據其條件編寫訊號函式。
Alpha Pattern的定義
Alpha Pattern是一種假設的技術分析形態,根據特定的條件生成買入或賣出訊號。其條件如下:
- 當目前的最低價低於5個週期前的最低價和13個週期前的最低價,但高於21個週期前的最低價,同時目前的收盤價高於3個週期前的收盤價時,在下一個開盤價生成買入訊號。
- 當目前的最高價高於5個週期前的最高價和13個週期前的最高價,但低於21個週期前的最高價,同時目前的收盤價低於3個週期前的收盤價時,在下一個開盤價生成賣出訊號。
編寫訊號函式
訊號函式(signal function)負責掃描每行資料並根據設定的條件留下買入或賣出的痕跡。以下是實作Alpha Pattern的訊號函式:
def signal(data):
data = add_column(data, 2) # 為買入和賣出訊號新增兩列
for i in range(len(data)):
try:
# Bullish Alpha(看漲Alpha)
if data[i, 2] < data[i - 5, 2] and data[i, 2] < data[i - 13, 2] and data[i, 2] > data[i - 21, 2] and data[i, 3] > data[i - 3, 3] and data[i, 4] == 0:
data[i + 1, 4] = 1 # 在下一行生成買入訊號
# Bearish Alpha(看跌Alpha)
elif data[i, 1] > data[i - 5, 1] and data[i, 1] > data[i - 13, 1] and data[i, 1] < data[i - 21, 1] and data[i, 3] < data[i - 3, 3] and data[i, 5] == 0:
data[i + 1, 5] = -1 # 在下一行生成賣出訊號
except IndexError:
pass
return data
程式碼解析:
data = add_column(data, 2):為原始資料新增兩列,用於儲存買入和賣出訊號。for i in range(len(data))::遍歷資料的每一行。try-except區塊:用於捕捉IndexError,避免因在最後一行資料生成訊號而導致索引錯誤。if和elif條件:根據Alpha Pattern的定義檢查每行資料是否滿足買入或賣出的條件。data[i + 1, 4] = 1和data[i + 1, 5] = -1:分別在下一行資料中標記買入和賣出訊號。
練習:簡化訊號條件
現在,讓我們來實作一個更簡單的訊號條件:
- 當目前的收盤價高於2個週期前的收盤價時,在下一個開盤價生成買入訊號。
- 當目前的收盤價低於2個週期前的收盤價時,在下一個開盤價生成賣出訊號。
def signal(data):
data = add_column(data, 2)
for i in range(len(data)):
try:
if data[i, 3] > data[i - 2, 3]:
data[i + 1, 4] = 1
elif data[i, 3] < data[i - 2, 3]:
data[i + 1, 5] = -1
except IndexError:
pass
return data
程式碼解析:
- 此函式實作了根據收盤價與2個週期前收盤價比較的簡單交易策略。
- 買入訊號在收盤價上漲時生成,賣出訊號在收盤價下跌時生成。
訊號視覺化:技術分析的核心步驟
在技術分析中,訊號的視覺化是至關重要的一步。透過視覺化的方式,可以直觀地觀察到訊號的產生和變化,從而更好地理解交易策略的有效性。本章將介紹如何使用Python來視覺化交易訊號。
建立訊號圖表
當建立並套用多頭和空頭訊號後,需要對其進行主觀和客觀的評估。主觀評估涉及視覺檢查多個訊號圖表,以檢測可能存在的異常,從而發現編碼錯誤。客觀評估則是計算績效指標,如命中率,以量化交易策略的有效性。
簡單柱狀圖的繪製
首先,介紹如何使用ohlc_plot_bars()函式繪製簡單的柱狀圖。該函式定義如下:
def ohlc_plot_bars(data, window):
sample = data[-window:, ]
for i in range(len(sample)):
plt.vlines(x=i, ymin=sample[i, 2], ymax=sample[i, 1], color='black', linewidth=1)
if sample[i, 3] > sample[i, 0]:
plt.vlines(x=i, ymin=sample[i, 0], ymax=sample[i, 3], color='black', linewidth=1)
if sample[i, 3] < sample[i, 0]:
plt.vlines(x=i, ymin=sample[i, 3], ymax=sample[i, 0], color='black', linewidth=1)
if sample[i, 3] == sample[i, 0]:
plt.vlines(x=i, ymin=sample[i, 3], ymax=sample[i, 0] + 0.00003, color='black', linewidth=1.00)
plt.grid()
內容解密:
sample = data[-window:, ]:擷取最近的window筆資料進行繪圖。plt.vlines():繪製垂直線以表示每個交易週期的最高價和最低價。- 根據收盤價和開盤價的比較,繪製不同的柱狀圖。
新增訊號箭頭
接下來,介紹如何使用signal_chart()函式在柱狀圖上新增訊號箭頭。該函式定義如下:
def signal_chart(data, position, buy_column, sell_column, window=500):
sample = data[-window:, ]
fig, ax = plt.subplots(figsize=(10, 5))
ohlc_plot_bars(data, window)
for i in range(len(sample)):
if sample[i, buy_column] == 1:
x = i
y = sample[i, position]
ax.annotate(' ', xy=(x, y), arrowprops=dict(width=9, headlength=11, headwidth=11, facecolor='green', color='green'))
elif sample[i, sell_column] == -1:
x = i
y = sample[i, position]
ax.annotate(' ', xy=(x, y), arrowprops=dict(width=9, headlength=-11, headwidth=-11, facecolor='red', color='red'))
內容解密:
ohlc_plot_bars(data, window):先繪製柱狀圖。ax.annotate():在指定的位置新增箭頭以表示多頭或空頭訊號。arrowprops引數用於設定箭頭的樣式。
使用範例
呼叫signal_chart()函式以繪製訊號
signal_chart(my_data, 0, 4, 5, window=250)
這將在最近的250筆資料上繪製柱狀圖和訊號箭頭。
績效評估函式的編碼
視覺化訊號只是第一步,您需要客觀的資料來判斷您的交易系統是贏還是輸。
績效評估的重要性
為此,您需要進行績效評估,即計算不同的指標和比率,以瞭解過去的表現。您的任務是解釋這些指標並嘗試調整模式的使用以改善指標。
交易策略與績效評估
請記住,交易策略可以輕易地成為幾個導致某種模式的條件。因此,儘管本文討論了K線圖模式的細節,但也會簡要回顧交易策略。第10章和第11章將討論一些自然涉及K線圖模式的策略。
命中率(Hit Ratio)
人類喜歡比錯誤更頻繁地正確。通常,我們為自己的成就感到自豪,並為失敗感到羞恥,這就是為什麼當我們發現大多數決定都帶來了預期和理想的結果時,我們會感到安慰。大部分時間都是正確的,這提供了每個人都歡迎的自我增強。畢竟,誰不想被視為成功?
交易術語中的命中率是指過去獲利交易次數除以已實作的過去交易總次數。這意味著命中率衡量的是您對未來方向的正確預測百分比。70%的命中率意味著平均而言,您傾向於在每100筆交易中賺取70筆,這不錯,但您必須絕對小心,因為這是一把雙刃劍,稍後您就會明白為什麼。
命中率的數學表示
[ \text{Hit ratio} = \frac{\text{Number of profitable trades}}{\text{Number of total trades}} ]
顯然,交易總次數包括獲利和虧損交易的次數。命中率是最受關注和分析的績效指標之一,因為它對接收者有心理影響。請務必根據已實作的交易總數(不包括待處理交易)計算比率。
回報率(Rate of Return)
當您投資100美元,一年後變成105美元,您如何描述您的回報率?您可以透過以下方式計算您的利潤作為初始投資的回報: [ \text{Rate of return} = \left( \frac{\text{New balance}}{\text{Initial balance}} \right) - 1 ]
這意味著您的回報率是5%。以百分比表示盈利能力可以更好地瞭解投資組合的收益和損失幅度。例如,考慮以下兩個假設情況:
- 投資組合A賺取了125,000美元。
- 投資組合B回報了10%。
乍一看,投資組合A似乎更令人印象深刻,但如果我告訴您兩個投資組合的初始餘額都是2,000,000美元呢?這使得投資組合A變成了表現較差的一個,因為它只賺取了6.25%,而投資組合B賺取了10%(200,000美元)。
總回報率與淨回報率
您還可以計算幾種型別的回報率,即總回報率和淨回報率。毫無疑問,您最關心的是淨回報率,因為它扣除了費用。讓我們透過下面的例子來看看兩者之間的區別:
- 2021年1月1日的初始餘額 = 1,000,000美元
- 2021年12月31日的總期末餘額 = 1,175,000美元
- 2021年期間發生的未付手續費和費用總計 = 35,000美元
- 2021年期間未付的研究提供者費用 = 10,000美元
在此例中,不考慮支付給經紀商和其他第三方供應商的費用的總回報率是: [ \text{Gross rate of return} = \left( \frac{1,175,000}{1,000,000} \right) - 1 = 17.5% ]
淨回報率更接近您的實際收益,透過以下計算得出: [ \text{Net rate of return} = \left( \frac{1,175,000 - 35,000 - 10,000}{1,000,000} \right) - 1 = 13% ]
程式碼實作績效評估
def hit_ratio(profitable_trades, total_trades):
return profitable_trades / total_trades
def rate_of_return(new_balance, initial_balance):
return (new_balance / initial_balance) - 1
def gross_rate_of_return(final_balance, initial_balance):
return (final_balance / initial_balance) - 1
def net_rate_of_return(final_balance, fees, initial_balance):
return ((final_balance - fees) / initial_balance) - 1
# 使用範例
profitable_trades = 70
total_trades = 100
new_balance = 105
initial_balance = 100
final_balance = 1175000
fees = 35000 + 10000
print("Hit Ratio:", hit_ratio(profitable_trades, total_trades))
print("Rate of Return:", rate_of_return(new_balance, initial_balance))
print("Gross Rate of Return:", gross_rate_of_return(final_balance, 1000000))
print("Net Rate of Return:", net_rate_of_return(final_balance, fees, 1000000))
程式碼解密:
- hit_ratio函式:計算命中率,即獲利交易次數除以交易總次數。
- rate_of_return函式:計算回報率,用於評估單筆交易的盈利能力。
- gross_rate_of_return函式:計算總回報率,不考慮任何費用。
- net_rate_of_return函式:計算淨回報率,考慮了費用,提供更真實的收益情況。
- 使用範例:展示如何使用上述函式計算不同的績效指標。