Try   HackMD

輕鬆學會程式交易 | Chapter 5 | 建立自己的交易系統

5-4 Ta-lib

下載步驟

請依序嘗試以下三種方法

  1. windows或Mac作業系統可直接在Ipython Console中下載
pip install TA-Lib
  1. Mac可以使用brew下載,不過需注意要加上!
!brew install ta-lib
  1. windows還可以直接使用wheel檔下載:
    (a) 請點網址
    (b) 找尋適合的版本的檔案
    ex:
    TA_Lib‑0.4.17‑cp37‑cp37m‑win_amd64.whl (cp右邊的是python版本,‑win_amd右邊是windows位元)

    ​​​​如何看python版本
    ​​​​    1.spyder視窗上方
    ​​​​    2.IPython console顯示
    
    ​​​​如何看windows位元
    ​​​​    1.點選左下角搜尋
    ​​​​    2.搜尋'系統資訊'
    ​​​​    3.一堆項目中找到系統類型
    

測試

import talib import pandas as pd tech = pd.Series([1,2,3,4,5,6,7,8]) print(talib.MA(tech,5))

github、文檔

(1)英文github
https://github.com/mrjbq7/ta-lib
文檔
https://mrjbq7.github.io/ta-lib/doc_index.html

(2)中文翻譯github
https://github.com/HuaRongSAO/talib-document

5-5 技術指標

呼叫套件

import talib import pandas_datareader as pdr import numpy as np

取得數據

data = pdr.DataReader('0050.TW', 'yahoo') # 從yahoo數據庫得到數據 close = data['Close'] # 股票收盤價 # 印出來看看! ma5 = talib.MA(close,5) # 5日均線 print(ma5)

缺失值處理

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
talib遇到缺失值,後面算出來得都會是缺失值
先做實驗,將倒數第10個值改成缺失值,並填補空缺

補充
numpy的np.nan在pandas中視為None(空)值。
不過使用bool()函數轉型,python視為True

# 將倒數第10個值改成缺失值 close.iloc[-10] = np.nan # np.nan類似None # 查看是不是變成缺失值了 print(close.tail(11)) # tail可以看尾端的數據 ma5 = talib.MA(close,5) print(ma5.tail(11)) close = close.ffill() # 將缺失值變成前一個數 data = data.ffill() # 或者將每一欄的缺失值變成前一個數 # 查看是不是變成缺失值了 print(close.tail(11)) ma5 = talib.MA(close,5).tail(11) print(ma5)

RSI

RSI是經典的轉折指標。傳統將RSI>70視為行情過熱,RSI<30視為行情過冷。

rsi = talib.RSI(close,14) #印出來看看! print(rsi)

KD

KD需要用到高低收三種資料,詳細KD原理可以參考文章
傳統方法是將K黃金交叉(向上交叉)D,視為買進訊號,反之為賣出訊號。

high = data['High'] low = data['Low'] close = data['Close'] slowk, slowd = talib.STOCH(high, low, close, slowk_period=5, slowd_period=5, fastk_period=9) #印出來看看! print(slowk) print(slowd)

5-6 繪製技術指標圖

matplotlib

matplotlib是一個簡單好用的python視覺化繪圖庫。
後面的範例我們會直接使用pandas搭配其中的功能

安裝

pip install matplotlib

qt5

試著在IPyton console 輸入 %matplotlib qt5, 可以切換圖形介面
而用完之可以輸入 %matplotlib inline 換回原本圖形介面

MA

一次執行兩行,輕鬆繪出美美的圖

close.plot() ma5.plot()

RSI

畫子圖方法一

使用pandas DataFrame的plot功能繪圖,可輕鬆達到效果

ploter = pd.DataFrame({'Close':close,'RSI':rsi}) ploter.plot(subplots=True) # subplots 功能可以將內容分開成不同圖片(子圖)


加上水平線

ax = ploter.plot(subplots=True) print(ax) ax[1].axhline(70) ax[1].axhline(30)

KD

畫子圖方法二

較正統,也比較靈活

# 製作兩個畫板 fig, ax = plt.subplots(2, 1) # 2*1的子圖 # -----畫第一張圖---- # close.plot(ax=ax[0], sharex=True) # 加上標題與圖例 # close.plot(title='Close',legend=True,ax=ax[0]) # -----畫第二張圖----- # # k,d要先fillna(將缺失值填補)x軸才不會錯呦! slowk.fillna(0).plot(ax=ax[1], sharex=True) slowd.fillna(0).plot(ax=ax[1], sharex=True) # 加上標題與圖例 # slowk.fillna(0).plot(sharex=True,title='KD',legend=True,ax=ax[1]) # slowd.fillna(0).plot(sharex=True,legend=True,ax=ax[1]) ax[1].axhline(30) # 30水平線 ax[1].axhline(70) # 70水平線 plt.tight_layout() # 加上這個可以調整成舒適的格式

5-7 建立條件(condition)

撰寫策略時,策略的邏輯核心就是條件
條件最終都會以TrueFalse的方式呈現。
由於這些條件是可以重複拿出來被使用的,所以我們可以用DataFrame整理寫過的條件。

比較法

將數值互相比大小,即為比較法。或者達到

設定條件庫的步驟

  1. 建立空的DataFrame名叫“condition”
  2. 取名並設定條件

    其中命名以簡單清楚為主,也可以使用參數作為命名以利最佳化

5-8 建立條件

程式碼,以黃金交叉為例

condition = pd.DataFrame([]) # 將數值放進condition中並命名 condition['股價>均線5'] = close > ma5 condition['標準差>1.5'] = close.rolling(10).std() > 1.5 # 黃金交叉做法 a1 = k b1 = d a2 = a1.shift(1) b2 = b1.shift(1) crossover = (a1>a2) & (a1>b1) & (b2>a2) condition['KD黃金交叉'] = crossover

以下為黃金交叉及死亡交叉函數,可直接取用

def crossover(over,down):
    a1 = over
    b1 = down
    a2 = a1.shift(1)
    b2 = b1.shift(1)
    crossover =  (a1>a2) & (a1>b1) & (b2>a2)
    return crossover
# 死亡交叉
def crossunder(down,over):
    a1 = down
    b1 = over
    a2 = a1.shift(1)
    b2 = b1.shift(1)
    crossdown =  (a1<a2) & (a1<b1) & (b2<a2)
    return crossdown

5-9 為什麼要建立「訊號」

信號是將各種條件濃縮成進場和出場的唯一條件

交易方法種類

  • 進場
    1. 買進(buy)
    2. 放空(sellshort)
  • 出場
    1. 賣出(sell)
    2. 回補(buytocover)

5-10 建立進出場訊號

建立條件

condition = pd.DataFrame([]) condition['KD黃金交叉'] = crossover(k,d) condition['KD死亡交叉'] = crossunder(k,d)

生成訊號

建立一個空的訊號DataFrame表,存放買進及賣出訊號

signal = pd.DataFrame([]) # 各項條件用'&'方式處理 # '*1'是為了轉成數字訊號方便大家看 signal['買進'] = (condition['KD黃金交叉'] & condition['D值低檔']) * 1 signal['賣出'] = condition['KD死亡交叉'] * -1

信號處理

交易策略:買進一單位,並續抱到直到賣出訊號出現為止
這邊的操作是讓買進與賣出訊號變成一進一出(pair)的訊號

此操作可有可無,供學員大家參考

signal['持有'] = signal['買進'] + signal['賣出'] signal['持有'] = signal['持有'].replace(0,method='ffill') signal['持有'] = signal['持有'].replace(-1, 0) def tool(x): if x[0]==1 and x[1]==0: return 1 else: return x[-1] signal['持有'] = signal['持有'].rolling(2).apply(tool, raw=True).fillna(0)

5-12 買賣權益生成

回測+記錄的資訊

建立一個總資料表research將所需資訊放在一起

research = pd.DataFrame([]) research = research.join([data['Open']],how='outer') # 開盤價資訊 research = research.join([close],how='outer') # 收盤價資訊 research = research.join([signal],how='outer') # 訊號 research['權益'] = np.nan # 拿來紀錄權益用的欄位

回測變數

# 計入初始資金 capital = 100000 # 記錄權益(目前現金+部位價值) equity = capital # 記錄部位狀況 marketposition=0 # 記錄買入股數 share=0 # 記錄入場價得 entryprice = 0 """ research = research.to_dict('record') 使用這行會加快速度很多。 原理是把dataframe轉成成list+字典形式, 不過在下面for要改成: for values in research: """

策略邏輯撰寫

for index,values in research.iterrows(): '''step3,賣出''' if marketposition == 1 and values['賣出'] == -1: # sell this bar at close # 賣在什麼價格 exitprice = values['Close'] # 帳戶處理:收款 capital += exitprice * share * 1000 # share就是上一次買進的股數 marketposition=0 share = 0 '''step1,買進''' if marketposition == 0 and values['買進'] == 1: #buy this bar at close #買了多少股 share = capital // (values['Close']*1000) #買在什麼價格 entryprice = values['Close'] #帳戶處理:扣款 capital -= entryprice * share * 1000 # 將狀態改為"買進" marketposition=1 '''step2,記錄權益狀況''' if marketposition == 1: #權益就是假設直接賣出可以獲得多少錢(目前現金+部位價值) equity = capital + (share * values['Close'] * 1000) else: equity = capital # 在research中記錄權益 research.loc[index,'權益'] = equity

繪圖

# 將訊號產生的地方塗上顏色 hold = close.copy() hold[signal['持有']==0] = np.nan fig, ax = plt.subplots(4, 1)# 4*1的子圖 ax[0].set_title('Equity') # 將0號圖標上標題 research['權益'].plot(ax=ax[0]) # 繪出權益 ax[1].set_title('Close') # 將1號圖標上標題 close.plot(ax=ax[1]) # 繪出股價 hold.plot(ax=ax[1]) # 將買進的區域塗上顏色 #k,d要先fillna(將缺失值填補)x軸才不會錯呦! ax[2].set_title('KD') # 將2號圖標上標題 k.fillna(0).plot(sharex=True,ax=ax[2]) # 繪出K值 d.fillna(0).plot(sharex=True,ax=ax[2]) # 繪出D值 ax[3].set_title('Signal') # 將3號圖標上標題 signal['持有'].plot(sharex=True,ax=ax[3]) # 繪出訊號 plt.tight_layout() # 將畫板調成適合的大小

5-13 第三次作業

制定一個策略,與大盤比較績效,並產生權益圖

請說明比大盤績效好或壞的原因
試說明,有沒有讓績效更好的做法