透過永豐證券 API 找出短線交易潛力股

BY PJ. -2025 年 4 月 30 日
(最後更新於: 2025 年 5 月 10 日)


對於短期交易者來說,股票的成交量股價波動是最重要的參考指標。透過程式,我們可以快速、方便地自動統整要觀察的股票清單。本文將介紹如何使用永豐證券的 API,抓取近期成交量大且股價波動高的股票,並篩選出適合短線交易的股票。

永豐API(Shioaji)說明

  • 開戶並申請

首先需要在永豐證券開戶並申請 API,流程可參考: API開戶及申請流程

完成申請後,會獲得 api_keysecret_key

永豐api管理

  • API 登入

使用 API管理 取得的 api_keysecret_key,登入Shioaji。

import shioaji as sj

api = sj.Shioaji(simulation=True)  # 使用模擬環境即可

api.login(
    api_key="your_api_key", 
    secret_key="your_secret_key", 
    receive_window=60000
)


* 取得股價和成交量資料

假設我們要查詢某支股票(以 2330 為例)的 30 天股價和成交量資料,可以使用kbar函數來抓取。

相關函數可參考:永豐Python API參考文件

import datetime
import pandas as pd

# 設定查詢的起始日和結束日
start_date = (datetime.datetime.now() - datetime.timedelta(days=30)).strftime('%Y-%m-%d')
end_date = datetime.datetime.now().strftime('%Y-%m-%d')

kbars = api.kbars(
    contract=api.Contracts.Stocks['2330'],
    start=start_date,
    end=end_date,
)

df = pd.DataFrame({**kbars})
df.ts = pd.to_datetime(df.ts)
df['year'] = df['ts'].dt.year 
df['month'] = df['ts'].dt.month
df['day'] = df['ts'].dt.day

print(df.head(5))  # 顯示前五筆資料
完整程式碼 - 篩選股票

我們會篩選出近期成交量大、股價波動大的股票,並排除 ETF,作為短線交易的觀察清單。以下是篩選股票的完整程式碼:

我們分別建立兩個 Python 檔案:main.py 和 history.py ,負責登入 API 和處理股票資料。

main.py

import shioaji as sj
import history

# 登入永豐證券 API
api = sj.Shioaji(simulation=True)
api.login(
    api_key="your_api_key",
    secret_key="your_secret_key",
    receive_window=60000
)

# 執行篩選過程並將結果存為 Excel 檔案
hty = history.history_stock(api)
history_data = hty.return_df()
history_data.to_excel("stock.xlsx", index=False)

history.py

import pandas as pd
import datetime
import numpy as np

class history_stock:
    def __init__(self, api):
        self.api = api
        # 篩選股票價格範圍
        self.low_price = 100.5
        self.high_price = 139

        # 查詢開始日和結束日
        search_days = 30
        self.start_date = (datetime.datetime.now() - datetime.timedelta(days=search_days)).strftime('%Y-%m-%d')
        self.end_date = datetime.datetime.now().strftime('%Y-%m-%d')

        # 取得可當日沖銷的股票清單
        self.total_stock()
        # 計算各股開、高、收、低價及成交均量
        self.update_data()
        # 篩選符合條件的股票
        self.condition()

    def total_stock(self):
        item_name = []
        item_code = []
        for item in self.api.Contracts.Stocks.TSE:
            if item['day_trade'] == 'Yes':  # 篩選可當日沖銷的股票
                item_name.append(item['name'])
                item_code.append(item['code'])

        self.history_df = pd.DataFrame({'name': item_name, 'symbol': item_code})
        self.history_df['avg_volume'] = ''
        self.history_df['high'] = ''
        self.history_df['low'] = ''
        self.history_df['open'] = ''
        self.history_df['close'] = ''
        self.history_df['price_change'] = ''

    def update_data(self):
        for i in self.history_df.index:
            avg_volume, High, Low, Open, Close = self.kbar(self.history_df['symbol'].iloc[i], self.start_date, self.end_date)
            self.history_df['avg_volume'].iloc[i] = avg_volume
            self.history_df['high'].iloc[i] = High
            self.history_df['low'].iloc[i] = Low
            self.history_df['open'].iloc[i] = Open
            self.history_df['close'].iloc[i] = Close
            if Low is None:
                self.history_df['price_change'].iloc[i] = None
            else:
                self.history_df['price_change'].iloc[i] = (High - Low) / Low

        return self.history_df

    def kbar(self, symbol, start_date, end_date):
        kbars = self.api.kbars(
            contract=self.api.Contracts.Stocks[symbol],
            start=start_date,
            end=end_date,
        )

        df = pd.DataFrame({**kbars})
        df.ts = pd.to_datetime(df.ts)
        df['year'] = df['ts'].dt.year
        df['month'] = df['ts'].dt.month
        df['day'] = df['ts'].dt.day

        if len(df) == 0:
            return None, None, None, None, None
        else:
            High = df.groupby(['year', 'month', 'day']).max()['High'].iloc[-1]  # 最近一日最高價
            Low = df.groupby(['year', 'month', 'day']).min()['Low'].iloc[-1]    # 最近一日最低價
            df.sort_values(by=['year', 'month', 'day', 'ts'], ascending=[False, False, False, True], inplace=True)
            Open = df['Open'].iloc[0]
            df.sort_values(by=['year', 'month', 'day', 'ts'], ascending=[False, False, False, False], inplace=True)
            Close = df['Close'].iloc[0]
            df = df.groupby(['year', 'month', 'day'])[['Volume']].sum()
            return (sum(df['Volume']) / len(df)), High, Low, Open, Close

    def condition(self):
        # 篩選成交量大於 1000 和股價變動幅度大於 2% 的股票
        self.history_df = self.history_df.loc[np.logical_and(self.history_df.avg_volume >= 1000, self.history_df.price_change >= 0.02)]
        self.history_df = self.history_df[self.history_df.symbol.astype(str).str.len() == 4]  # 移除 ETF

        # 篩選股價在設定範圍內的股票
        price_series = self.history_df['close'].astype(float)
        price_range = np.logical_and(price_series >= self.low_price, price_series <= self.high_price)
        self.history_df = self.history_df[price_range]

        # 按照成交量排序
        self.history_df.sort_values(by="avg_volume", ascending=False, inplace=True)

    def return_df(self):
        return self.history_df

產生結果

觀察股票清單

你可以在每天 1:30 收盤後執行這段程式,來計算次日需要觀察的股票,篩選出的股票會保存在 stock.xlsx 中。

也可以根據自己的需求,調整股價範圍成交量股價變動幅度等條件。

後續分析

下篇文章我將示範如何基於這份觀察清單,透過永豐 API 取得即時的 tick 資料,找出盤中出現內外盤大量成交的股票,這是日內交易非常重要的指標。

#程式交易 #日內交易 #短線交易 #永豐證券 #Shioaji #股價波動 #成交量 #API交易 #股市策略 #股市分析 #量化交易 #台股

💬 留言區