揭開投資大師的選股密碼:麥克.喜偉收益型投資四大準則解析

收益型投資

Photo from Unflash by Markus Spiske

前言

在投資的世界裡,準確的預測和系統性的分析是取得長期成功的關鍵,而能夠洞悉市場趨勢的策略家,更是投資者們爭相學習的對象。麥克.喜偉(Michael Sivy)無疑是其中的佼佼者。他以精準的市場預測和獨到的投資見解,在美國投資界樹立了卓越的聲譽。

從1987年預警美國股市大崩盤,到1995年預言股市轉機,再到1999年洞察科技股泡沫的破滅,麥克.喜偉以數十年的市場研究和實戰經驗,證明了其卓越的投資洞察力。他的作品《投資金律》更成為眾多投資者必讀的經典,透過系統性的分析和清晰的準則,為不同類型的投資者提供了實用的選股指南。

本篇文章將聚焦於麥克.喜偉的投資理念,特別是他為收益型投資者制定的四大準則:高收益率、穩健成長率、健康財務狀況和合理估值。我們將結合其經典案例,探索這些原則如何在現實投資中實現收益最大化,並為當前的投資環境提供指引。

麥克.喜偉(Michael Sivy)的擇股條件

麥克.喜偉重視公司在各種收益率的表現,因此使用了較多的收益相關資料進行股票的篩選。同時也關心公司的營運方的表現,我們將採用舉債情況以及資產的流動程度來作為首要依據,去評估公司營運方是否有將公司為實在良好的體質當中。

  • 股利收益率加上獲利(營收)成長率大於10%
  • 股利收益率大於市場平均值
  • 本益比小於市場平均值
  • 流動比例大於市場平均值
  • 負債佔股東權益小於20%

策略簡介

通過上述的五個條件進行選股,於每季最後一天交易日更換部位,最後查看麥克.喜偉(Michael Sivy)的擇股策略是否可以應用於台灣股市。

程式範例

基本的模組輸入以及apikey 的設定

import pandas as pd
import numpy as np
import tejapi
import os
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'Arial'
tej_key ='your tejapi key'
tejapi.ApiConfig.api_key = tej_key
os.environ['TEJAPI_BASE'] = "your tej base"
os.environ['TEJAPI_KEY'] = tej_key

利用TEJToolAPI 抓取股票的財務以及交易資料

選擇回測時間之前就存在的股票(2019年就存在的股票),避免出現前視偏誤問題,並選擇上市股票作為研究目標

from zipline.sources.TEJ_Api_Data import get_universe
pool = get_universe(start = pd.Timestamp('2019-01-01', tz = 'UTC'),
                   end = pd.Timestamp('2019-12-31', tz = "UTC"),
                   mkt_bd_e = 'TSE', stktp_e = 'Common Stock')

關於 get_universe 用法可以參考 TQuant Lab Github 官網:https://github.com/tejtw/TQuant-Lab/blob/main/lecture/get_universe說明.ipynb

利用TEJToolAPI的get_history函數抓取需要的財務會計資料,這裡抓取麥克.喜偉(Michael Sivy)的擇股條件所需要的會計資料。

例如:本益比、流動比率、營收成長率等等。

import TejToolAPI


columns = ['Industry', '本益比', '收盤價', '流動比率', '股東權益總計', '負債總額', '營收成長率','eps','mt_div','現金股利率']


start_dt = pd.Timestamp('2015-12-29', tz = 'UTC')
end_dt = pd.Timestamp('2023-12-31', tz = "UTC")


data__ = TejToolAPI.get_history_data(start = start_dt,
                                  end = end_dt,
                                  ticker = pool,
                                  fin_type = 'A', # 為累計資料
                                  columns = columns,
                                  transfer_to_chinese = True)

計算出每期換部位的時間(每季的最一天交易日):

通過選取台積電的資料當作樣本,來篩選出每季的最後一天交易日日期,之後會根據這個日期進行新一輪的換股以及選股。

# 找尋每年當中的12月以及6月的最後一天交易日日期
sample = data__[data__['股票代碼'] == '2330']
last_day_ = list(sample.groupby(sample['日期'].dt.year)['日期'].max())


june_data = sample[sample['日期'].dt.month == 6]
last_june_day = list(june_data.groupby(june_data['日期'].dt.year)['日期'].max())


march_data = sample[sample['日期'].dt.month == 3]
last_march_day = list(march_data.groupby(march_data['日期'].dt.year)['日期'].max())


sep_data = sample[sample['日期'].dt.month == 9]
last_sep_day = list(sep_data.groupby(sep_data['日期'].dt.year)['日期'].max())


last_day_ = last_day_ + last_june_day  + last_march_day + last_sep_day
modified_day = []
for i in last_day_:
   modified_day.append(i.date())


modified_day
日期輸出格式:
[datetime.date(2015, 12, 31),
 datetime.date(2016, 12, 30),
 datetime.date(2017, 12, 29),
 datetime.date(2018, 12, 28),
 datetime.date(2019, 12, 31),
 datetime.date(2020, 12, 31),
 datetime.date(2021, 12, 30),
 datetime.date(2022, 12, 30),
 datetime.date(2023, 12, 29),
 datetime.date(2016, 6, 30),
 datetime.date(2017, 6, 30),
 datetime.date(2018, 6, 29),
 datetime.date(2019, 6, 28),
 datetime.date(2020, 6, 30),
 datetime.date(2021, 6, 30),
 datetime.date(2022, 6, 30),
 datetime.date(2023, 6, 30),
 datetime.date(2016, 3, 31),
 datetime.date(2017, 3, 31),
 datetime.date(2018, 3, 31),
 datetime.date(2019, 3, 29),
 datetime.date(2020, 3, 31),
 datetime.date(2021, 3, 31),

設定回測架構

先將需要的股票資料匯入浸會側系統當中,這裡除了剛剛獲取的股票池之外,會加入台股大盤(IR0001)資料當作選股策略的比較對象。回測的時間設定為2019/12/30至2024/11/31。

pools = pool + ['IR0001']
from zipline.data.run_ingest import simple_ingest
# 價量資料
simple_ingest(name = 'tquant' , tickers = pools , start_date = '20191231' , end_date = '20241131')

匯入回測需要的模組及函數

from zipline.api import set_slippage, set_commission, set_benchmark,  symbol,  record, order_target_percent
from zipline.finance import commission, slippage
from zipline import run_algorithm

設定benchmark為台灣大盤指數(IR0001)來進行最終策略的比較,同時設定手續費以及滑價模型。

def initialize(context):
   set_slippage(slippage.TW_Slippage(spread = 1 , volume_limit = 1))
   # 設定為台灣股票手續費計算方法
   set_commission(commission.Custom_TW_Commission(min_trade_cost=20, discount=1.0, tax = 0.003))
   # 設定台灣大盤為比較基準
   set_benchmark(symbol('IR0001'))
   context.i = 0
   context.state = False
   context.order_tickers = []
   context.last_tickers = []

交易策略設定為在每一年的最後一天交易日進行上一期股票的賣出,同時對下一期的股票進行買入。買入的部位比例為等權重的比例買進。

def compute_stock(date, data):  # 創建一個函數,在指定的日期進行選股,輸出篩選出的股票列表。
   # 提取出調整部位當日的股票資訊
   df = data[data['日期'] == pd.Timestamp(date)].reset_index(drop = True)


   # 本益比小於市場平均值
   df['產業平均本益比'] = df.groupby('主產業別_中文')['本益比'].transform('mean')
   set_1 = set(df[df['本益比'] < df['產業平均本益比']]['股票代碼'])


   # 流動比例大於市場平均值
   df['產業平均流動比率'] = df.groupby('主產業別_中文')['流動比率_A'].transform('mean')
   set_2 = set(df[df['流動比率_A'] > df['產業平均流動比率']]['股票代碼'])


   # 負債佔股東權益小於20%
   df['負債佔股東權益'] = df['負債總額_A'] / df['股東權益總計_A']
   set_3 = set(df[df['負債佔股東權益'] < 0.2]['股票代碼'])


   # 現金股利率大於市場平均值
   df['產業平均現金股利率'] = df.groupby('主產業別_中文')['現金股利率'].transform('mean')
   set_4 = set(df[df['現金股利率'] > df['產業平均現金股利率']]['股票代碼'])


   # 股利收益率加上獲利成長率大於10%
   set_5 = set(df[df['營收成長率_A']*0.01 + df['現金股利率']*0.01 > 0.1]['股票代碼'])  # 因為單位問題進行調整,將%調整為正確單位


   tickers = list(set_1 & set_2 & set_3 & set_4 & set_5)


   return tickers

def handle_data(context, data):
   # 避免前視偏誤,在篩選股票下一交易日下單
   if context.state == True:
       print(f"下單日期:{data.current_dt.date()}, 擇股股票數量:{len(context.order_tickers)}")


       for i in context.last_tickers:
           if i not in context.order_tickers:
               order_target_percent(symbol(i), 0)
      
              
       for i in context.order_tickers:
           order_target_percent(symbol(i), 1 / len(context.order_tickers))


           curr = data.current(symbol(i), 'price')
           record(price = curr, days = context.i)
      
       context.last_tickers = context.order_tickers


   context.state = False
  
   backtest_date = data.current_dt.date()
  


   # 查看回測時間是否符合指定日期
   for idx, j in enumerate(modified_day):
       if backtest_date == j:
           # 調整狀態,在下一個交易下單
           context.state = True
           context.order_tickers = compute_stock(date = backtest_date, data = data__)
   context.i += 1

def analyze(context, perf):
   # plt.style.use('dark_background')
   # 重置為預設樣式
   plt.style.use('default')


   plt.title(f'Portfolio Value')
   plt.plot(perf['portfolio_value'], label='Portfolio Value')
   plt.legend()
   plt.show()


   cumulative_returns = (1 + perf['returns']).cumprod() - 1
   plt.title(f'Period Return Portfolio & Benchmark')
   plt.plot(perf.index, cumulative_returns, label = 'Portfolio')
   plt.plot(perf.index, perf['benchmark_period_return'], label = 'Benchmark')
   plt.legend()
   plt.show()

capital_base = 1e7


results = run_algorithm(
   start = pd.Timestamp('20191231', tz = 'utc'),
   end = pd.Timestamp('20231130', tz = 'utc'),
   initialize = initialize,
   handle_data = handle_data,
   analyze = analyze,
   bundle = 'tquant',
   capital_base = capital_base)
results

策略績效圖表分析

收益型投資

回測期間設定為2019年底~2023年底,從累積報酬圖中看出選股策略的績效是略微優於大盤,表示這個策略有挑選出股市中上漲潛力較高的標的。但是在市場下行時,策略的下行幅度更加劇烈,在應對市場的系統性風險上相對缺乏韌性。從槓桿使用圖來看,只有在換股的幾天會出現槓桿的波動,其餘情況是維持在無槓桿的情況,使得策略在週轉資金上不會有過多的問題。策略年化報酬率為18.74%,略高於台灣大盤的年化報酬12-15%。

收益型投資

從移動波動度以及移動夏普值圖表中,可以刊到在2021年的下半年出現比較大的波動性。那段時間正好處於牛市結尾的回檔,台灣股票市場出現明顯的下跌段並且波動性較高,但策略的波動度卻明顯大於市場波動,我認為是這個選股方法是選出市場中上漲潛力較大的股票,這種股票市場處於熊市時,因為投資人的資金入場,因此叫沒有動能推升這類型股價。所以在該時間對中策略的下跌情形以及波動度都會較大,算是這個策略的市場風險。因此如果可以在整體股票市場基期較高時(牛市尾段)減少這個策略的操作,可以避開較大的波動時段。

以不同的換股頻率去進行相同邏輯的策略,我們採用每年、每半年以及每季為單位進行回測。從圖中可以看到換股頻率愈頻繁所帶來的整題績效會於高。經過篩選出的股票會在一個季度的內,股票價格反應公司的價值,因此進行高頻率的換股會對整體績效有顯著的提升。

在平衡天數的績效表格

統計量3month6monthyearlyBenchmark
年化報酬18.74%16.058%17.635%14.92%
累積報酬94.499%78.025%87.581%71.362%
夏普值0.950.890.940.86
年化波動度20.318%18.805%19.311%18.02%
最大回撤-29.274%-28.394%-28.394%-28.553%

完整程式碼連結:程式碼連結

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

【TQuant Lab 回測系統】解決你的量化金融痛點

全方位提供交易回測所需工具

延伸閱讀

程式交易是什麼?程式交易教學、優缺點及常見策略懶人包 – TEJ台灣經濟新報
用 Alphalens 剖析因子表現,價量因子篇

相關連結

返回總覽頁
Procesing