鉅額交易是警訊?用 TEJ API 分析內部人持股轉讓與股價之變化

本文重點概要

  • 文章難度:★☆☆☆☆
  • 分析台灣上市櫃公司股價與內部人持股轉讓

前言

在股市風起雲湧的今天,企業股價波動背後的謎團值得深入挖掘。內部人持股轉讓反映公司內部運營、管理層對未來發展的信心,以及對當前經濟環境的評估。透過分析內部人交易背後的動因,探討股價與內部人持股轉讓之關係。本文將運用TEJ API聚焦於內部人持股轉讓對台灣上市櫃公司股價進行量化分析。

編輯環境與模組需求

本文使用 Windows 11 作業系統以及 VS code 作為編輯器。

資料庫使用

資料導入

取得內部人申報轉讓資料,資料由董監申報轉讓資料庫導入,其中轉讓的方式包含很多種,如:一般交易、洽特定人、信託、贈與、鉅額交易、盤後定價,而我們從中抓取鉅額交易的資料。

import tejapi
import pandas as pd
import matplotlib.pyplot as plt
import plotly.graph_objects as go
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta

tejapi.ApiConfig.api_key  = "Your Key"
tejapi.ApiConfig.api_base = "https://api.tej.com.tw"
tejapi.ApiConfig.ignoretz = True

# 取得內部人申報轉讓資料,並篩選出鉅額交易的資料
data_trans = tejapi.get('TWN/ATRANS',        # 上市(櫃)董監申報轉讓資料庫
                        # 證券碼、申報日、股東身份、轉讓方式、申報轉讓股數
                        opts = {'columns':['coid', 'mdate', 'clnm_c', 'tpnm_c', 'tns2']},
                        paginate = True,
                        chinese_column_name = True)
data_trans = data_trans[data_trans['轉讓方式'].str.contains('鉅額')]  # 篩選鉅額交易資料

設置總發行股數函數,資料由上市(櫃)董監全體持股狀況資料庫導入。

# 取得總發行股數函數,將證券碼、日期設為變數
def data_total_stock(coid, date):
# 由於此資料庫將日期設為次月15號更新,本次實作2024/01的資料尚未發布,所以若有2023/12/01之後的事件都以2023/12/01取得總發行股數
    reference_date = datetime.strptime('2023-12-01', '%Y-%m-%d')
    date_object = datetime.strptime(date, '%Y-%m-%d')   # 將日期變數轉為datetime格式
# 判斷日期是否在2023/12/01之後,若在之後以2023/12/01取得總發行股數
    if date_object > reference_date:
        gte = reference_date
        lte = reference_date
# 若在2023/12/01之前,此資料是月頻率的資料,因此若日期不是1號,則取這個月到下個月之間的那個1號,反之則不用改變日期
    else:
        gte = date                    # 設置開始日期
        if date_object.day != 1:
            next_month_date = date_object + relativedelta(months=1)    # 加一個月
        else:
            next_month_date = date_object
        lte = next_month_date.strftime('%Y-%m-%d')         # 設置結束日期
    data_total = tejapi.get('TWN/ABSTN1',                  # 上市(櫃)董監全體持股狀況資料庫   
                            coid = coid,
                            mdate = {'gte':gte, 'lte':lte},
                            opts = {'columns':['coid','fld003']},    # 總發行股數
                            paginate = True,
                            chinese_column_name = True)    
    return data_total

設置股價函數,資料由上市(櫃)未調整股價(日)資料庫導入。

# 取得股價函數,將證券碼、起迄日期設為變數
def data_stock_price(coid, start, end):
    data_coid = tejapi.get('TWN/APRCD',  # 上市(櫃)未調整股價(日)資料庫
                            coid = coid,
                            mdate = {'gte':start, 'lte': end},
                            paginate = True,
                            chinese_column_name = True,
                            opts = {'columns':['coid','mdate','close_d']},
                            )
    return data_coid

資料合併與視覺化分析

考量到不同時間點,企業的總發行股數會有波動,因此設置公司碼、申報日為變數代入總發行股數函數,以得到對應時間點的總發行股數,並計算出申報股數(%)。

# 下面兩個欄位轉成list資料,以便後續帶入函數
coid = list(data_trans['公司碼'])
date = list(data_trans['申報日'])

# 設置總發行股數的dataframe
data_total = pd.DataFrame()

for x, y in zip(coid, date):
    data_stock = data_total_stock(x, str(y)[0:10]) # 將證券碼、日期轉成字串取年月日帶入函數
    if data_stock.size == 0:         # 若沒有資料不處理
        pass    
    else:
        data_total = pd.concat([data_total, data_stock], ignore_index=True)\
        
data_trans = data_trans[data_trans['公司碼'] != '5261']   # 申報轉讓資料刪除上方沒有資料的證券碼(經查詢已下櫃)
data_trans.reset_index(inplace=True)
data_trans = data_trans.drop(columns='None')

# 將總發行股數併入申報轉讓資料,並新增欄位申報股數(%)
data_outstanding = [outstanding for outstanding in data_total['總股數']]
data_trans['總股數'] = data_outstanding
stock_pct = [(j/i)*100 for i, j in zip(data_trans['總股數'], data_trans['申報轉讓股數'])]
data_trans['申報股數(%)'] = stock_pct

提取每支股票申報比例最高的資料

# 取出每支股票申報股數(%)最高的資料
max_percentage_coid = data_trans.groupby('公司碼')['申報股數(%)'].idxmax()
final_data = data_trans.loc[max_percentage_coid]
內部人持股轉讓
每支股票申報股數(%)最高的資料

提取證券代碼與設置時間區間

綜合以上數據與相關新聞,本文歸納出以下四種結果,並取 3036、6452、3017、2311、2597、2723 為例:

  1. 股價隨之暴跌,在內部人鉅額交易後企業沒有發布任何的說明
  • 文曄(3036) (2023/11/10)
    • 文曄主要從事半導體相關零組件代理經銷業務,公司透過合併多家IC通路商的方式擴大公司規模,將著重於三大研發目標,分別為AI 深度學習與智慧影像辨識、光電系統設計、馬達控制。
內部人持股轉讓
  • 康友-KY(6452) (2018/10/16)
    • 康友製藥因掏空案鬧得沸沸揚揚,高層集體出走,財報難產導致被暫停交易,於2021年4月1日終止下市。
內部人持股轉讓
  1. 股價稍有波動或基本不受轉讓消息影響,有發布新聞說明為何進行鉅額轉讓
  • 奇鋐(3017) (2021/03/23) → 奇鋐
    • 奇鋐為全球DT、NB散熱大廠,原先產品以PC散熱為主,近年來轉向發展利基型產品,如通訊設備、伺服器應用散熱領域。
    • 針對大股東日商古河電工釋股,奇鋐表示因 2020 面臨疫情衝擊,日本企業營運普遍欠佳,大股東以處分轉投資改善資產項目。
內部人持股轉讓
  • 日月光(2311) (2018/02/14) → 日月光
    • 日月光副董張洪本申讓持有的全數日月光股票,日月光表示,這是張洪本個人信託理財規劃考量,並無實質出售或釋出日月光股份。
內部人持股轉讓
  1. 股價微微上漲,發布利多新聞說明:
  • 潤弘(2597) (2019/10/23) → 潤弘
    • 潤泰集團為簡化集團組織架構以鉅額交易方式認購子公司出售之潤弘股票,潤泰全對潤弘精密持股將提升至1.26萬張,持股比例為9.35%。
    • 潤弘(2597)的股價看起來是微微的上漲,推測是發布新聞說明內部人鉅額交易是母公司認購股票。
內部人持股轉讓
  1. 股價大幅下跌,在發布新聞後有回穩趨勢:
  • 美食-KY(2723) (2023/03/24) → 美食-KY
    • 美食-KY為知名咖啡烘焙連鎖 85°C 集團之控股公司,主營產品分為咖啡、麵包、西點,為複合式餐飲連鎖通路商。
    • 美食-KY發布說明,表示此「內部人持股轉讓」轉讓理由是「引進國際長期投資人」,且申報股數已於昨日全數完成轉讓。
內部人持股轉讓
內部人持股轉讓

觀察各股申報日與下一個工作日之股價與報酬率變化

我們想知道各股申報轉讓後股價與報酬率的變化,算出申報日的下一個工作日,來觀察是正向變動還是負向變動的多,又或者是股價不受影響。

# 找出申報日的下一個工作日,以利進行申報轉讓前後之對比
next_workdays = []
for c in range (len(all_data)):
    next_work_day = all_data['申報日'][c] + timedelta(days=1)
    next_working = str(next_work_day)[0:10]
    ROC_data = data_stock_price(all_data['公司碼'][c], str(all_data['申報日'][c])[0:10], next_working)
    while True:
        if len(ROC_data) < 2: # 如果資料少於兩筆代表目前只抓到申報日這天的股價資料,所以日期再繼續往後抓
            next_work_day += timedelta(days=1)
            next_working = str(next_work_day)[0:10]
            ROC_data = data_stock_price(all_data['公司碼'][c], str(all_data['申報日'][c])[0:10], next_working)
        else:
            break
    next_workdays.append(next_working)

all_data['下一個工作日'] = next_workdays

找到下一個工作日後,設置日報酬率函數,資料由上市(櫃)股價報酬(日)-報酬率資料庫導入。

# 取得日報酬率函數,將證券碼、起迄日期設為變數
def data_rate_of_return(coid, start, end):
    data_return = tejapi.get('TWN/APRCD2',                  # 上市(櫃)股價報酬(日)-報酬率資料庫   
                            coid = coid,
                            mdate = {'gte':start, 'lte':end},
                            opts = {'columns':['coid','mdate','zclose','roia']},    
                            # 證券碼、日期、收盤價、日報酬率%
                            paginate = True,
                            chinese_column_name = True)
    return data_return

將申報日、下一個工作日與證券代碼代入日報酬率函數

# 將申報日、下一個工作日與證券代碼代入日報酬率函數
ROC_df = pd.DataFrame(columns=['證券代碼', '年月日', '未調整收盤價(元)', '日報酬率 %'])
for count in range (len(all_data)):
    ROC_data = data_rate_of_return(all_data['公司碼'][count], 
                                    str(all_data['申報日'][count])[0:10], 
                                    str(all_data['下一個工作日'][count])[0:10])
    ROC_df = pd.concat([ROC_df, ROC_data], ignore_index=True)
內部人持股轉讓

統計結果與內部人持股轉讓分析

計算日報酬率的數量,大於 0 歸納在positive、小於 0 歸納在negative、等於 0 歸納在zero

# 計算正向、反向及無變動的數量
positive = 0
negative = 0
zero = 0
for i in range(1, len(ROC_df), 2):
    rate = ROC_df['日報酬率 %'][i]
    if rate == 0:
        zero += 1
    elif rate > 0:
        positive += 1
    elif rate < 0:
        negative += 1

total = zero+positive+negative # 計算資料筆數

# 利用plotly套件畫出圓餅圖
labels = ['Zero', 'Positive', 'Negative']
values = [zero, positive, negative]
colors = ['gold', 'mediumturquoise', 'darkorange']

fig = go.Figure(data=[go.Pie(labels=labels, values=values)])
fig.update_traces(hoverinfo='label+percent+value',
                    textinfo='percent+value+label',
                    textfont_size=15,
                    marker=dict(colors=colors, line=dict(color='#000000', width=1.5)))

title_text = ("內部人持股轉讓後,下一個工作日股市變動情形圓餅圖,總資料筆數為{}筆" .format(total))  
fig.update_layout(title_text=title_text)
fig.show()
內部人持股轉讓
內部人持股轉讓後,下一個工作日股市報酬率變動情形圓餅圖,總資料筆數為488筆
其中負向變動佔 49.2% 為最多,達到將近一半的比例;正向變動佔 42.8% 為次多;無變動佔約 8%

上圖呈現的是申報日後的下一個工作日之收盤價的變動率比例圖,可以看到還是以負向變動居多,佔比將近 50%,可以直覺看出投資人在面對不確定性時第一時間較傾向將資金撤出。正向變動或者無變動也都有發生的可能,推測是根據企業有無說明或者說明的內容,會造成不同的股市波動。舉前面的例子來說,若企業沒有發布新聞說明,就有造成下跌的可能;反之若企業第一時間進行說明原因,就有無變動或者上漲的可能。

結論

從數據上來看,鉅額交易對股價產生的影響確實是一個值得關注的議題。我們發現內部人持股轉讓後,股價短期變動主要呈現負向趨勢,顯示市場對於這類交易存在著一定程度的擔憂與不確定性。

然而,有趣的是企業在面對內部人鉅額交易時,是否主動發布新聞說明,成為了影響股價波動的一個重要因素。以文曄、康友-KY為例,缺乏說明導致股價暴跌;而日月光、奇鋐則因及時發布說明而較不受影響。潤弘則透過母公司認購股票的解釋,成功平穩股價波動。美食-KY在交易後雖有暴跌,但引進國際長期投資人的新聞說明使股價逐漸回穩。

總體而言,鉅額交易確實是市場的一個警訊,但企業在處理內部人交易時,透明度與及時的說明對於減緩市場擔憂、維護投資者信心起著重要作用。因此,投資者在追蹤鉅額交易的同時,也需密切關注企業的公開說明,以更全面地評估其對股價波動的影響。

本次實作透過 TEJ API 實現內部人持股轉讓分析,僅用 TEJ API 所提供的有效資料和視覺化的套件,就可以做出這樣的結果並實作自身所想像的各類型之視覺化分析,省時又省力的情況下,也能提供投資人更多元的評估指標。選購 TEJ E-Shop 的相關方案,用高品質的資料庫,建構出適合自己的分析應用或交易策略。

溫馨提醒,本次策略僅供參考,不代表任何商品或投資上的建議

Github 原始碼

內部人持股轉讓與股價變化研究

延伸閱讀

相關連結

返回總覽頁