台積電如何買?用 Python 研發投資策略

最近股票圈最熱門的話題,不外乎就是「台積電」,以前我們都說,市值太大的股票,上漲的幅度有限。但是台積電果然是國家棟梁,身為台股最大市值的股票,竟然可以漲停板!然而現在這麼高了,還安全嗎?怎麼才能安全的享受台積電的上漲的獲利,又可以在下跌時加碼呢?我們可以針對台積電,用 Python 研發擇時買賣,文末附上完整程式範例!

台積電
台積電要如何買賣呢?

3步驟帶你分析台積電

這篇文章會分享怎麼研發台積電的投資策略,主要有三個步驟:

  1. 使用 Colab 並安裝 yfinance 、 backtesting、talib 的函式庫
  2. 下載台積電股價歷史紀錄,研發買賣訊號
  3. 回測交易結果分析,並且研究策略如何優化

1. 使用 Colab 並下載環境

要建構一個股票策略,只要會基本的 Python ,就可以開始了,我們使用 Colab 來當作撰寫 Python 的平台,這是 Google 佛心推出的,讓我們可以線上撰寫程式,而且完全免費!我自己已經把幾乎所有程式碼搬到 Colab 上了!雖然速度比桌機稍慢,但是可以雲端任何地點編輯,就算換電腦也不用擔心!

安裝 Package

我們今天要用的 Package,有兩個,一個是 yfinance ,負責下載 yahoo finance 上的股價資料,另外一個是 backtesting,顧名思義就是用來研發策略用的!但研發策略,有時候會需要製作技術指標,並根據技術指標來交易,所以需要用到 talib 這個 Package,我們可以用簡單的三行指令完成安裝:

!pip install yfinance
!pip install Backtesting
!pip install talib-binary

上述三行,只要在程式碼輸入欄輸入,系統就會幫你安裝好這三款 package,這三行的第一個字符是驚嘆號,代表我們要執行 Shell 的語法,不是 Python 的語法!假如你不是用 Colab,而是用個人電腦,也可以在打開 Shell 輸入這些指令,記得將指令的驚嘆號移除喔!

2. 下載台積電股價,研發買賣訊號!

首先,我們先來下載台積電的歷史紀錄,在下方的程式碼中,我們已經幫大家寫好一個函式,叫做「get_historical_data」,可以直接呼叫它來獲取股價。由於 yfinance 的歷史紀錄算是滿豐富的,所以有很多股票都可以下載,包含美股台股,例如蘋果(AAPL),特斯拉(TSLA),微軟(MSFT),然而台股的部分,比較可惜的地方,就是只有上市資料,如台積電(2330.TW),以下是完整的範例。你可以 參考 yahoo finance 來下載你有興趣股票!

import yfinance as yf
import pandas as pd

def get_historical_data(ticker):
  d = yf.Ticker(ticker)
  df = d.history(period="max")
  df.columns = df.columns.str.lower()
  df.columns = pd.Series(df.columns).str.capitalize().values
  return df.dropna()

df = get_historical_data('2330.TW')
df
Screen Shot 2020 07 29 at 11.57.25 AM

策略訊號研發

有了股票的歷史紀錄,就可以來研發策略了,由於 Python 是個執行速度很慢的語言(比起 C、C++),所以我們不太使用 for 迴圈 來回測,而是用向量矩陣的方式產生訊號,速度會快很多,其中的「sma1」、「sma2」、「signal_long」、「signal_short」都是時間序列,下方為均線為範例,假如你不喜歡均線,可以參考 talib 來製作你有興趣的技術指標喔

import talib

# compute simple moving average using talib
sma1 = talib.SMA(df.Close, timeperiod=20)
sma2 = talib.SMA(df.Close, timeperiod=60)

# compute buy and sell signals (golden cross and death cross)
signal_long = (sma1 > sma2) & (sma1.shift() < sma2.shift())
signal_short = (sma1 < sma2) & (sma1.shift() > sma2.shift())

# combine long and short signals
signal = signal_long.copy()
signal[signal_short] = -1

程式碼看不懂嗎?沒關係,我們將這些時間序列 2020 年的數值繪製出來:

df.Close['2020'].plot()
sma1['2020'].plot()
sma2['2020'].plot()
signal['2020'].astype(int).plot(secondary_y=True)
Screen Shot 2020 07 29 at 12.08.26 PM
  • 藍色:df.Close —–> 台積電的股價(一飛沖天!)
  • 黃色:sma1 —-> 20日均線
  • 綠色:sma2 —-> 60日均線
  • 紅色:signal —-> 買賣訊號

接下來,我們就可以根據上圖中,紅色訊號為 1 時買入, -1 時賣出,這樣的的方式來交易,但是效果會如何呢?沒有人知道,所以我們還要進行「回測」,也就是將此策略放在歷史上模擬交易的報酬率!

3. 回測和參數優化

接下來我們就可以來測測看,究竟這樣子買台積電效果如何?我們可以用 backtesting 這個工具來幫我們回測,完整的程式碼如下,雖然有點長,但你會發現核心程式碼,跟剛剛是非常類似的!所以不用擔心太複雜!你也可以參考 backtesting 的官方教學,來獲得更詳細的用法喔!

from backtesting import Backtest, Strategy

class Strategy(Strategy):
    
    n1 = 20
    n2 = 60
    
    def init(self):
        super().init()
        
        # Precompute the two moving averages
        close = pd.Series(self.data.Close)
        sma1 = talib.SMA(close, timeperiod=self.n1)
        sma2 = talib.SMA(close, timeperiod=self.n2)

        # Precompute signal
        signal_long = (sma1 > sma2) & (sma1.shift() < sma2.shift())
        signal_short = (sma1 < sma2) & (sma1.shift() > sma2.shift())

        # combine signal
        signal = signal_long
        signal[signal_short] = -1
        
        # plot sma
        self.I(lambda x: sma1, 'sma1')
        self.I(lambda x: sma2, 'sma2')

        # set signal to trade
        self.signal = self.I(lambda x: signal, 'signal')

    def next(self):
        super().next()

        entry_size = self.signal[-1]

        if entry_size > 0:
            self.buy()
        elif entry_size < 0:
          for trade in self.trades:
              trade.close()

bt = Backtest(df, Strategy)
result1 = bt.run()
bt.plot()
Screen Shot 2020 07 29 at 12.13.35 PM

上圖就是我們的回測結果,這是一個動態的圖表,所以我們可以將一部分放大:

Screen Shot 2020 07 29 at 12.20.57 PM

上圖從上到下,總共有五個小圖,我們一張一張解釋:

圖一:為最後的總績效結果(藍色線段),代表策略的報酬率,從2000到現在可以獲利約400%,而當中的紅色水平線段,代表最久沒有創新高的時間段,這段時間可能會讓你懷疑,這個策略有沒有效果,而放棄策略,這段時間當然是越短越好!

圖二:有很多的三角形,假如是正三角就是做多,倒三角就是做空,我們這次寫的策略是做多的策略!所以不會有做空的倒三角喔!另外顏色代表獲利或是虧損,綠色為獲利,紅色為虧損,這些三角形的高度代表獲利或虧損的程度,以虛線做區分,虛線上方是獲利,而虛線下方式虧損,可以看到這種交易方法 2008 年以後每次虧損不會太多,獲利有時候還滿驚人的!

圖三是交易的明細,除了股價 K 棒外,我們也看到了兩條均線(藍色跟橘色),方便我們核對交易的時間,另外我們可以看到綠色和紅色的虛線,每一條虛線都代表一次交易,虛線的起始和結束,代表交易的價格跟時間,綠色代表獲利,而紅色代表虧損。

第四和第五張圖,則是成交量以及 signal 訊號,此策略就是模擬 signal 訊號為 1 時買進,而 -1 時賣出,比對其他圖片的數據,非常合理!

策略效果不夠好?尋找最佳參數!

剛剛我們用的均線是20日跟60日,來做交易,然而這是最好的均線嗎?我們可以將這兩個參數,當成策略的參數,分別叫 n1 和 n2 ,透過暴力枚舉(range(5, 200)),來從 5 到 200 裡面挑出 Sharpe ratio 比較好的參數:

result2 = bt.optimize(n1=range(5, 200, 10),
                      n2=range(5, 200, 10))
result2._strategy
# 程式碼顯示結果:
<Strategy Strategy(n1=165,n2=5)>

以上,就是整個優化的過程,程式碼非常簡潔,最後優化完的數字是

  • n1 = 165
  • n2 = 2

眼尖的人會發現,奇怪怎麼長短週期倒過來了?代表我們死亡交叉買入,而黃金交叉賣出,這種交易比較像是均值回歸,在低點買,高點賣,屬於逆勢策略,我們用這兩個新的參數,來測測看結果如何?

Screen Shot 2020 07 29 at 12.32.06 PM

雖然報酬率雖然比較低,但是交易的風險小滿多的,我們可以將順勢跟逆勢策略結合,獲得更穩定的報酬率,下方就是程式碼

((result1._equity_curve.Equity + 
result2._equity_curve.Equity)/2).plot()
Screen Shot 2020 07 29 at 12.40.45 PM
績效合併後的結果

基本上2008 到現在,沒什麼虧損過,台積電上漲時,會追蹤到漲幅,而下跌時也會危機入市,算是一個非常簡單,但績效很舒服的策略,分享給大家,現在就打開現成的 Colab 直接運行程式碼。假如大家對於我們這樣的分享有興趣,可以幫我們推廣一下!我們也有其他類似的文章可以參考:

FinLab - 韓承佑

嗨大家好,我是韓承佑,FinLab創辦人,畢業於巴黎薩克雷大學資工博士,目前擔任臺灣量化交易協會 學術顧問、台北商業大學 創新育成中心 創業技術顧問與上市科技公司 量化交易顧問。當初,我喜歡寫程式、無意間因為軟體比賽接觸Fintech,從此開始了財經跟程式的學習之路。我們成立 FinLab 量化投資部落格,用自己研發的軟體,對台灣股市做大量快速的實驗。希望可以在量化投資的路上,當大家的「武器製造商」!