Technical
In Taiwan stock technical data, we have 20 datasets, as follows:
- Taiwan Stock Overview TaiwanStockInfo
- Taiwan Stock Overview (with Warrants) TaiwanStockInfoWithWarrant
- Taiwan Warrant Underlying Reference Table TaiwanStockInfoWithWarrantSummary
- Taiwan Stock Trading Date TaiwanStockTradingDate
- Taiwan Stock Price Table TaiwanStockPrice
- Taiwan Stock Weekly K Table TaiwanStockWeekPrice
- Taiwan Stock Monthly K Table TaiwanStockMonthPrice
- Taiwan Adjusted Stock Price Table TaiwanStockPriceAdj
- Taiwan Stock Historical Tick Data Table TaiwanStockPriceTick
- Taiwan Individual Stock PER, PBR Table TaiwanStockPER
- Order and Trade Statistics Every 5 Seconds TaiwanStockStatisticsOfOrderBookAndTrade
- Taiwan Weighted Index TaiwanVariousIndicators5Seconds
- Day Trading Targets and Volume/Value TaiwanStockDayTrading
- Weighted/OTC Total Return Index TaiwanStockTotalReturnIndex
- Taiwan Individual Stock 10-Year Line Table TaiwanStock10Year
- Taiwan Stock Minute K Table TaiwanStockKBar
- Index Statistics Every 5 Seconds TaiwanStockEvery5SecondsIndex
- Taiwan Stock Suspension Announcement TaiwanStockSuspended
- Day Trading Sell-First-Then-Buy Suspension Notice TaiwanStockDayTradingSuspension
- Daily Price Limit TaiwanStockPriceLimit
Taiwan Stock Overview TaiwanStockInfo¶
- This table mainly lists all Taiwan listed (TWSE), OTC (TPEx), and Emerging stocks, including stock names, codes, and industry categories!
- Data update time: 1:30 daily. The actual update time is based on the API data.
Transferred stocks keep multiple rows: take the row with the latest date as the current market
If a stock moved from the Emerging board to TWSE / TPEx, this table keeps both an emerging row and a twse / tpex row. The date of the emerging row is frozen at the day the stock left the Emerging board, while the twse / tpex row carries the current date. Filtering with type == "emerging" alone therefore also picks up stocks that have already transferred; take the row with the latest date for each stock_id instead. This matters especially for TaiwanStockPriceTick and TaiwanStockKBar, whose volume unit differs by market (lots for TWSE / TPEx, shares for Emerging).
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockInfo",
}
resp = requests.get(url, headers=headers, params=parameter)
data = resp.json()
data = pd.DataFrame(data["data"])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset = "TaiwanStockInfo"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
Output
| industry_category | stock_id | stock_name | type | date | |
|---|---|---|---|---|---|
| 0 | ETF | 0050 | 元大台灣50 | twse | 2021-10-05 |
| 1 | ETF | 0051 | 元大中型100 | twse | 2021-10-05 |
| 2 | ETF | 0052 | 富邦科技 | twse | 2021-10-05 |
| 3 | ETF | 0053 | 元大電子 | twse | 2021-10-05 |
| 4 | ETF | 0054 | 元大台商50 | twse | 2021-10-05 |
Taiwan Stock Overview (with Warrants) TaiwanStockInfoWithWarrant¶
- This table mainly lists all Taiwan listed (TWSE), OTC (TPEx), and Emerging stocks and warrants, including names, codes, and industry categories!
- Total record count exceeds 50,000.
- Data update time: 1:30 daily. The actual update time is based on the API data.
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockInfoWithWarrant",
}
resp = requests.get(url, headers=headers, params=parameter)
data = resp.json()
data = pd.DataFrame(data["data"])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset = "TaiwanStockInfoWithWarrant"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
Output
| industry_category | stock_id | stock_name | type | date | |
|---|---|---|---|---|---|
| 0 | ETF | 0050 | 元大台灣50 | twse | 2021-10-05 |
| 1 | ETF | 0051 | 元大中型100 | twse | 2021-10-05 |
| 2 | ETF | 0052 | 富邦科技 | twse | 2021-10-05 |
| 3 | ETF | 0053 | 元大電子 | twse | 2021-10-05 |
| 4 | ETF | 0054 | 元大台商50 | twse | 2021-10-05 |
Taiwan Warrant Underlying Reference Table TaiwanStockInfoWithWarrantSummary (available only to sponsor members)¶
- Provides the warrant underlying reference table. (Since it includes warrant data, the data volume is large and takes about a minute.)
- Covers both listed (TWSE) and OTC (TPEX) warrants' underlying (
target_stock_id) reference; OTC warrant underlying history goes back to 2011-01-03, so you can look up the warrants of a given underlying (including expired and code-reused historical warrants). - Data update time: 1:30 daily. The actual update time is based on the API data.
A single warrant code may map to different underlying stocks
Warrants have an expiration date. Once a warrant code (stock_id) expires and is delisted, that code is recycled and reissued to a new warrant on a (possibly different) underlying stock. As a result, the same stock_id may appear in multiple rows in this table, each mapping to a different underlying (target_stock_id) and each with its own date (listing date) and end_date (last trading date).
To determine which underlying a warrant code maps to on a given day, match by "the query date falls within that row's date ~ end_date interval"; reused codes from different periods are naturally distinguished by their non-overlapping intervals.
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockInfoWithWarrantSummary",
"data_id": "2330",# optional parameter
"start_date": "2020-04-06",# optional parameter
}
resp = requests.get(url, headers=headers, params=parameter)
data = resp.json()
data = pd.DataFrame(data["data"])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset = "TaiwanStockInfoWithWarrantSummary",
data_id = "2330",# optional parameter
start_date = "2020-04-06"# optional parameter
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
Output
| stock_id | date | close | target_stock_id | target_close | type | fulfillment_method | end_date | fulfillment_start_date | fulfillment_end_date | exercise_ratio | fulfillment_price | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 052018 | 2023-07-18 | 0 | 2330 | 0 | 認購 | 美式 | 2025-07-15 | 2023-07-18 | 2025-07-17 | 0.1 | 0 |
| 1 | 052405 | 2023-07-21 | 0 | 2330 | 0 | 認購 | 美式 | 2025-07-17 | 2023-07-21 | 2025-07-21 | 0.01 | 0 |
| 2 | 057397 | 2023-09-04 | 0 | 2330 | 0 | 認購 | 美式 | 2025-09-01 | 2023-09-04 | 2025-09-03 | 0.03 | 0 |
| 3 | 057607 | 2023-09-06 | 0 | 2330 | 0 | 認購 | 美式 | 2025-09-03 | 2023-09-06 | 2025-09-05 | 0.06 | 0 |
| 4 | 060985 | 2023-10-03 | 0 | 2330 | 0 | 認購 | 美式 | 2025-09-30 | 2023-10-03 | 2025-10-02 | 0.03 | 0 |
{
stock_id: str, # stock code
date: str, # listing date
close: float, # closing price
target_stock_id: str, # underlying stock code
target_close: float, # underlying closing price
type: str, # warrant type
fulfillment_method: str, # exercise method
end_date: str, # last trading date
fulfillment_start_date: str, # exercise start date
fulfillment_end_date: str, # exercise end date
exercise_ratio: float, # exercise ratio
fulfillment_price: float # exercise price
}
Taiwan Stock Trading Date TaiwanStockTradingDate¶
- Provides Taiwan stock trading dates.
- Data update time: Monday to Friday 18:00. The actual update time is based on the API data.
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockTradingDate",
}
resp = requests.get(url, headers=headers, params=parameter)
data = resp.json()
data = pd.DataFrame(data["data"])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset = "TaiwanStockTradingDate"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
Output
Daily Stock Price Information TaiwanStockPrice¶
- Provides daily trading information for Taiwan listed (TWSE), OTC (TPEx), and Emerging stocks!
- Data range: 1994-10-01 ~ now
- Data update time: Monday to Friday 17:30. The actual update time is based on the API data.
Emerging stocks: open is the previous-day average price, and may fall outside the day's high/low (not a data error)
Emerging-board stocks trade by negotiation and have no opening price. For emerging stocks this table therefore fills open with the previous-day average price, not an opening price; max / min / close are still the day's high / low / last traded price and are correct.
As a result, an emerging stock's open can sit above max or below min on volatile days. This is a field-definition difference, not corrupt data. For candlestick charts, use max / min / close, or treat open as the previous-day average.
Example: 6515 穎崴 on 2020-03-19 (emerging at the time) → open=218.06, max=200, min=170, close=174.9; 218.06 is exactly the previous-day average that day. The stock later moved to TWSE, after which its data is normal.
A related case: open=0 on an emerging stock's first trading day. Since an emerging stock's open is the previous-day average, on a stock's very first trading day there is no previous day to average, so open shows as 0; max / min / close are still the day's correct values, and from the next day onward open carries a normal previous-day average. This too is a field-definition difference, not corrupt data.
Example: 8272 全景 on 2023-10-17 (its first day on the emerging board) → open=0, max=136, min=112.5, close=130; the next day, 2023-10-18, open=129.39, which is 2023-10-17's average price. The same rule holds for TaiwanStockPriceAdj (adjusted price): the adjusted price is the raw price times an adjustment factor, so 0 carries through unchanged.
When no traded price is published for a stock on a given day, open / max / min / close are all 0 (not a data error)
In the daily quote published by TWSE / TPEx, a stock with no published traded price for that day has its open/high/low/close shown as --. This table follows the original publication and converts that to the numeric value 0, so open / max / min / close / spread are all 0 for that stock on that day. The source publication itself carries no price — this is not a crawling gap.
This can happen in any market (TWSE, TPEx, and Emerging alike) and is unrelated to the emerging-board open definition described above. A halted stock, a day with no trades at all, or a day with only sporadic trades that produce no published price all fall into this category.
Example 1 (no trades at all): 2317 鴻海 on 2025-07-30 → Trading_Volume=0, and open/max/min/close are all 0; the TWSE publication for that day literally reads "volume 0, open/high/low/close --". The previous trading day 2025-07-29 (close=171.5) and the next one 2025-07-31 (close=178) are both normal.
Example 2 (volume present but no published price): 9929 秋雨 on 2025-07-31 → Trading_Volume=451, yet open/max/min/close are still 0; the TWSE publication reads "volume 451, open/high/low/close --".
How to detect it: because of Example 2, do not filter on Trading_Volume > 0 alone — that condition misses rows that have volume but no price. Filter on the price columns instead:
df = df[df["close"] > 0] # keep only days with a published traded price
# or forward-fill from the previous trading day's close
df["close"] = df["close"].replace(0, method="ffill")
Difference from TaiwanStockPriceAdj: the adjusted-price table is not 0 on these days — it carries forward the previous trading day's adjusted price (while Trading_Volume keeps the day's actual value). For instance, 2317 鴻海 on 2025-07-30 in TaiwanStockPriceAdj is open=169.94, max=170.43, min=166.06, close=166.54, i.e. 2025-07-29's adjusted price. Use TaiwanStockPriceAdj if you want a series with no 0 gaps; use TaiwanStockPrice's 0 if you need to identify which days had no published price.
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockPrice",
"data_id": "2330",
"start_date": "2020-04-02",
"end_date": "2020-04-12",
}
resp = requests.get(url, headers=headers, params=parameter)
data = resp.json()
data = pd.DataFrame(data["data"])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockPrice",
data_id= "2330",
start_date= "2020-04-02",
end_date= "2020-04-08"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
from FinMind.data import DataLoader
from loguru import logger
import datetime
api = DataLoader()
api.login_by_token(api_token='token')
start = datetime.datetime.now()
df = api.taiwan_stock_daily(
stock_id_list=['2330', '2317', '2454', '3008'],
start_date='2024-01-01',
end_date='2024-12-31',
use_async=True,
)
cost = datetime.datetime.now() - start
logger.info(cost)
Output
| date | stock_id | Trading_Volume | Trading_money | open | max | min | close | spread | Trading_turnover | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2020-04-06 | 2330 | 59712754 | 16324198154 | 273 | 275.5 | 270 | 275.5 | 4 | 19971 |
| 1 | 2020-04-07 | 2330 | 48887346 | 13817936851 | 283.5 | 284 | 280.5 | 283 | 7.5 | 24281 |
| 2 | 2020-04-08 | 2330 | 38698826 | 11016972354 | 285 | 285.5 | 283 | 285 | 2 | 19126 |
| 3 | 2020-04-09 | 2330 | 29276430 | 8346209654 | 287.5 | 288 | 282.5 | 283 | -2 | 15271 |
| 4 | 2020-04-10 | 2330 | 28206858 | 7894277586 | 280 | 282 | 279 | 279.5 | -3.5 | 15833 |
{
date: str, # date
stock_id: str, # stock code
Trading_Volume: int64, # trading volume
Trading_money: int64, # trading amount
open: float64, # open price
max: float64, # max price
min: float64, # min price
close: float64, # close price
spread: float64, # price change
Trading_turnover: float32 # number of trades
}
Fetch all data for a specific date at once (available only to backer, sponsor members)¶
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockPrice",
"start_date": "2020-04-06",
}
resp = requests.get(url, headers=headers, params=parameter)
data = resp.json()
data = pd.DataFrame(data["data"])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockPrice",
start_date= "2020-04-06"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
Output
| date | stock_id | Trading_Volume | Trading_money | open | max | min | close | spread | Trading_turnover | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2020-04-06 | 0050 | 12207626 | 935731083 | 76.95 | 77.1 | 75.75 | 77.05 | 1.15 | 5824 |
| 1 | 2020-04-06 | 0051 | 33000 | 953030 | 29.05 | 29.05 | 28.74 | 29.05 | 0.38 | 21 |
| 2 | 2020-04-06 | 0052 | 178700 | 10660088 | 59.4 | 60.05 | 58.75 | 60 | 1.25 | 56 |
| 3 | 2020-04-06 | 0053 | 17000 | 589750 | 34.66 | 35 | 34.48 | 34.84 | 0.18 | 17 |
| 4 | 2020-04-06 | 0054 | 10000 | 200040 | 19.87 | 20.03 | 19.87 | 20.03 | 0 | 4 |
{
date: str, # date
stock_id: str, # stock code
Trading_Volume: int64, # trading volume
Trading_money: int64, # trading amount
open: float64, # open price
max: float64, # max price
min: float64, # min price
close: float64, # close price
spread: float64, # price change
Trading_turnover: int64 # number of trades
}
Taiwan Stock Weekly K Table TaiwanStockWeekPrice (available only to backer, sponsor members)¶
- Provides daily trading information for Taiwan listed (TWSE), OTC (TPEx), and Emerging stocks!
- Data range: 2000-01-01 ~ now
- Data update time: Monday to Friday 17:30. The actual update time is based on the API data.
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockWeekPrice",
"data_id": "2330",
"start_date": "2020-04-02",
"end_date": "2020-04-12",
}
resp = requests.get(url, headers=headers, params=parameter)
data = resp.json()
data = pd.DataFrame(data["data"])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockWeekPrice",
data_id= "2330",
start_date= "2020-04-02",
end_date= "2020-04-08"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
from FinMind.data import DataLoader
from loguru import logger
import datetime
api = DataLoader()
api.login_by_token(api_token='token')
start = datetime.datetime.now()
df = api.taiwan_stock_weekly(
stock_id_list=['2330', '2317', '2454', '3008'],
start_date='2024-01-01',
end_date='2024-12-31',
use_async=True,
)
cost = datetime.datetime.now() - start
logger.info(cost)
Output
| stock_id | yweek | max | min | trading_volume | trading_money | trading_turnover | date | close | open | spread | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2330 | 2020W15 | 288 | 270 | 409564428 | 114799189198 | 188964 | 2020-04-06 | 279.5 | 273 | 8 |
{
stock_id: str, # stock code
yweek: str, # weekly date
max: float64, # max price
min: float64, # min price
trading_volume: int64, # trading volume
trading_money: int64, # trading amount
trading_turnover: float32, # number of trades
date: str, # date
close: float64, # close price
open: float64, # open price
spread: float64 # price change
}
Fetch all data for a specific date at once (available only to backer, sponsor members)¶
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockWeekPrice",
"start_date": "2020-04-06",
}
resp = requests.get(url, headers=headers, params=parameter)
data = resp.json()
data = pd.DataFrame(data["data"])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockWeekPrice",
start_date= "2020-04-06"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
Output
| stock_id | yweek | max | min | trading_volume | trading_money | trading_turnover | date | close | open | spread | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2330 | 2020W15 | 288 | 270 | 409564428 | 114799189198 | 188964 | 2020-04-06 | 279.5 | 273 | 8 |
{
stock_id: str, # stock code
yweek: str, # weekly date
max: float64, # max price
min: float64, # min price
trading_volume: int64, # trading volume
trading_money: int64, # trading amount
trading_turnover: float32, # number of trades
date: str, # date
close: float64, # close price
open: float64, # open price
spread: float64 # price change
}
Taiwan Stock Monthly K Table TaiwanStockMonthPrice (available only to backer, sponsor members)¶
- Provides daily trading information for Taiwan listed (TWSE), OTC (TPEx), and Emerging stocks!
- Data range: 2000-01-01 ~ now
- Data update time: Monday to Friday 17:30. The actual update time is based on the API data.
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockMonthPrice",
"data_id": "2330",
"start_date": "2020-04-02",
"end_date": "2020-04-12",
}
resp = requests.get(url, headers=headers, params=parameter)
data = resp.json()
data = pd.DataFrame(data["data"])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockMonthPrice",
data_id= "2330",
start_date= "2020-04-02",
end_date= "2020-05-08"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
from FinMind.data import DataLoader
from loguru import logger
import datetime
api = DataLoader()
api.login_by_token(api_token='token')
start = datetime.datetime.now()
df = api.taiwan_stock_monthly(
stock_id_list=['2330', '2317', '2454', '3008'],
start_date='2024-01-01',
end_date='2024-12-31',
use_async=True,
)
cost = datetime.datetime.now() - start
logger.info(cost)
Output
| stock_id | ymonth | max | min | trading_volume | trading_money | trading_turnover | date | close | open | spread | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2330 | 2020M05 | 301.5 | 288.5 | 1744651784 | 513799591970 | 788158 | 2020-05-01 | 292 | 294.5 | -12.5 |
{
stock_id: str, # stock code
ymonth: str, # monthly date
max: float64, # max price
min: float64, # min price
trading_volume: int64, # trading volume
trading_money: int64, # trading amount
trading_turnover: float32, # number of trades
date: str, # date
close: float64, # close price
open: float64, # open price
spread: float64 # price change
}
Fetch all data for a specific date at once (available only to backer, sponsor members)¶
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockMonthPrice",
"start_date": "2020-04-06",
}
resp = requests.get(url, headers=headers, params=parameter)
data = resp.json()
data = pd.DataFrame(data["data"])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockMonthPrice",
start_date= "2020-04-06"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
Output
| stock_id | ymonth | max | min | trading_volume | trading_money | trading_turnover | date | close | open | spread | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2330 | 2020M05 | 301.5 | 288.5 | 1744651784 | 513799591970 | 788158 | 2020-05-01 | 292 | 294.5 | -12.5 |
{
stock_id: str, # stock code
ymonth: str, # monthly date
max: float64, # max price
min: float64, # min price
trading_volume: int64, # trading volume
trading_money: int64, # trading amount
trading_turnover: float32, # number of trades
date: str, # date
close: float64, # close price
open: float64, # open price
spread: float64 # price change
}
Taiwan Adjusted Stock Price Table TaiwanStockPriceAdj (available only to backer, sponsor members)¶
- Data range: 1994-10-01 ~ now
- Data update time: Monday to Friday 17:30. The actual update time is based on the API data.
When the adjustment factor updates, and which day is the baseline
Adjusted prices are computed backwards: the most recent trading day in the data is the baseline, and adjustment factors are applied cumulatively to earlier days. As a result, the adjusted price on the event day itself always equals that day's raw price — the adjustment shows up in the history before that day.
For ex-dividend / ex-rights, capital reduction, stock split and par value change events, the adjustment factor is applied in the post-close update on the event day itself; it is not deferred to the next trading day.
If a scheduled event date falls on a market-wide closure (a typhoon suspension, for example) and is postponed, the adjustment follows the day trading actually took place, not the originally scheduled date.
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockPriceAdj",
"data_id": "2330",
"start_date": "2020-04-02",
"end_date": "2020-04-12",
}
resp = requests.get(url, headers=headers, params=parameter)
data = resp.json()
data = pd.DataFrame(data["data"])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockPriceAdj",
data_id= "2330",
start_date= "2020-04-02",
end_date= "2020-04-08"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
from FinMind.data import DataLoader
from loguru import logger
import datetime
api = DataLoader()
api.login_by_token(api_token='token')
start = datetime.datetime.now()
df = api.taiwan_stock_daily_adj(
stock_id_list=['2330', '2317', '2454', '3008'],
start_date='2024-01-01',
end_date='2024-12-31',
use_async=True,
)
cost = datetime.datetime.now() - start
logger.info(cost)
Output
| date | stock_id | Trading_Volume | Trading_money | open | max | min | close | spread | Trading_turnover | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2020-04-06 | 2330 | 59712754 | 16324198154 | 273 | 275.5 | 270 | 275.5 | 4 | 19971 |
| 1 | 2020-04-07 | 2330 | 48887346 | 13817936851 | 283.5 | 284 | 280.5 | 283 | 7.5 | 24281 |
| 2 | 2020-04-08 | 2330 | 38698826 | 11016972354 | 285 | 285.5 | 283 | 285 | 2 | 19126 |
| 3 | 2020-04-09 | 2330 | 29276430 | 8346209654 | 287.5 | 288 | 282.5 | 283 | -2 | 15271 |
| 4 | 2020-04-10 | 2330 | 28206858 | 7894277586 | 280 | 282 | 279 | 279.5 | -3.5 | 15833 |
{
date: str, # date
stock_id: str, # stock code
Trading_Volume: int64, # trading volume
Trading_money: int64, # trading amount
open: float64, # open price
max: float64, # max price
min: float64, # min price
close: float64, # close price
spread: float64, # price change
Trading_turnover: float32 # number of trades
}
Fetch all data for a specific date at once (available only to backer, sponsor members)¶
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockPriceAdj",
"start_date": "2020-04-06",
}
resp = requests.get(url, headers=headers, params=parameter)
data = resp.json()
data = pd.DataFrame(data["data"])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockPriceAdj",
start_date= "2020-04-06"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
Output
| date | stock_id | Trading_Volume | Trading_money | open | max | min | close | spread | Trading_turnover | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2020-04-06 | 0050 | 12207626 | 935731083 | 76.95 | 77.1 | 75.75 | 77.05 | 1.15 | 5824 |
| 1 | 2020-04-06 | 0051 | 33000 | 953030 | 29.05 | 29.05 | 28.74 | 29.05 | 0.38 | 21 |
| 2 | 2020-04-06 | 0052 | 178700 | 10660088 | 59.4 | 60.05 | 58.75 | 60 | 1.25 | 56 |
| 3 | 2020-04-06 | 0053 | 17000 | 589750 | 34.66 | 35 | 34.48 | 34.84 | 0.18 | 17 |
| 4 | 2020-04-06 | 0054 | 10000 | 200040 | 19.87 | 20.03 | 19.87 | 20.03 | 0 | 4 |
{
date: str, # date
stock_id: str, # stock code
Trading_Volume: int64, # trading volume
Trading_money: int64, # trading amount
open: float64, # open price
max: float64, # max price
min: float64, # min price
close: float64, # close price
spread: float64, # price change
Trading_turnover: float32 # number of trades
}
Taiwan Stock Historical Tick Data Table TaiwanStockPriceTick (available only to backer, sponsor members)¶
(Due to the large data volume, each request only provides one stock's data for one day.)
- Data range: 2018-12-07 ~ now.
- Providing the dataset, stock_id, and start_date parameters returns data for that day.
- Data update time: Monday to Friday 15:30. The actual update time is based on the API data.
- Some data is missing on these dates: 2018-12-22, 2019-02-20, 2019-02-21, 2019-02-22. In addition, 2019-05-16 only has data for a small number of ETFs.
- Enabling Async significantly reduces the data update time. In a Colab test, downloading 2,236 stocks took only 3 minutes 40 seconds.
TickType has been corrected across the full history (2018-12-07 ~ 2023-03-10)
Before 2023-03-13, trades whose side could not be determined were all labelled 1 (buyer-initiated), which made the buyer-initiated share noticeably too high. Every trading day in this range has been regenerated using the same rule applied from 2023-03-13 onward. If you downloaded any of these dates before, please fetch the data again.
For dates before 2021-06-22, about 8% ~ 10% of trades have TickType 0 (undetermined), because the source data itself carries no side information for those trades, while the old version labelled them all as buyer-initiated. If you group statistics by TickType, treat 0 separately rather than merging it into either side.
The unit of volume differs by market: lots for TWSE / TPEx, shares for Emerging
The volume column keeps each market's native trading unit: TWSE and TPEx stocks are in lots (1 lot = 1,000 shares); Emerging stocks are in shares. Both units therefore appear in the same day of data. This is a difference between markets, not a data error. The same rule applies to volume in TaiwanStockKBar (minute K).
To tell which market a stock currently belongs to, use the type column of TaiwanStockInfo (twse / tpex / emerging). Note: a stock that moved from Emerging to TWSE / TPEx keeps both rows in TaiwanStockInfo — an emerging row and a twse / tpex row — and the date of the emerging row is frozen at the day the stock left the Emerging board. Filtering with type == "emerging" alone therefore also picks up stocks that have already moved, which makes the Emerging volume unit look inconsistent. Take the row with the latest date for each stock_id as the current market.
Example: for 1294, the emerging row has date 2024-09-25 while the tpex row carries the current date, so it is a TPEx stock today and its volume is in lots; 1260 has only an emerging row carrying the current date, so it is still an Emerging stock and its volume is in shares.
Also note, when reconciling tick data against the daily volume in TaiwanStockPrice: for TWSE / TPEx stocks the daily volume includes block trades (see TaiwanStockBlockTrade), while tick data does not, so the two will not match exactly.
Example
import io
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockPriceTick",
"data_id": "2330",
"start_date": "2020-01-02",
}
resp = requests.get(url, headers=headers, params=parameter)
data = resp.json()
data = pd.DataFrame(data["data"])
print(data.head())
from FinMind.data import DataLoader
from loguru import logger
import datetime
token = ""
data_loader = DataLoader()
data_loader.login_by_token(token)
date = '2025-12-08'
start = datetime.datetime.now()
df = data_loader.taiwan_stock_tick(
date=date,
use_async=True,
)
cost = datetime.datetime.now() - start
logger.info(cost)
# 00:03:41
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockPriceTick",
data_id= "2330",
start_date= "2020-01-02"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = do.call('cbind',data$data) %>%
data.table
head(df)
Output
| date | stock_id | deal_price | volume | Time | TickType | |
|---|---|---|---|---|---|---|
| 0 | 2020-01-02 | 2330 | 332.5 | 520 | 09:00:00.000 | 0 |
| 1 | 2020-01-02 | 2330 | 332.5 | 520 | 09:00:00.646 | 0 |
| 2 | 2020-01-02 | 2330 | 333 | 45 | 09:00:05.000 | 0 |
| 3 | 2020-01-02 | 2330 | 333 | 45 | 09:00:05.660 | 0 |
| 4 | 2020-01-02 | 2330 | 333 | 22 | 09:00:10.000 | 0 |
Fetch all data for a specific date at once (available only to sponsorpro members)¶
(Due to the large data volume, each request only provides one day's data.)
- Data range: 2018-12-07 ~ now.
- Providing the dataset and date parameters returns data for that day.
- Data update time: Monday to Friday 15:30. The actual update time is based on the API data.
- Some data is missing on these dates: 2018-12-22, 2019-02-20, 2019-02-21, 2019-02-22. In addition, 2019-05-16 only has data for a small number of ETFs.
TickType has been corrected across the full history (2018-12-07 ~ 2023-03-10)
Before 2023-03-13, trades whose side could not be determined were all labelled 1 (buyer-initiated), which made the buyer-initiated share noticeably too high. Every trading day in this range has been regenerated using the same rule applied from 2023-03-13 onward. If you downloaded any of these dates before, please fetch the data again.
For dates before 2021-06-22, about 8% ~ 10% of trades have TickType 0 (undetermined), because the source data itself carries no side information for those trades, while the old version labelled them all as buyer-initiated. If you group statistics by TickType, treat 0 separately rather than merging it into either side.
The unit of volume differs by market: lots for TWSE / TPEx, shares for Emerging
The volume column keeps each market's native trading unit: TWSE and TPEx stocks are in lots (1 lot = 1,000 shares); Emerging stocks are in shares. Both units therefore appear in the same day of data. This is a difference between markets, not a data error. The same rule applies to volume in TaiwanStockKBar (minute K).
To tell which market a stock currently belongs to, use the type column of TaiwanStockInfo (twse / tpex / emerging). Note: a stock that moved from Emerging to TWSE / TPEx keeps both rows in TaiwanStockInfo — an emerging row and a twse / tpex row — and the date of the emerging row is frozen at the day the stock left the Emerging board. Filtering with type == "emerging" alone therefore also picks up stocks that have already moved, which makes the Emerging volume unit look inconsistent. Take the row with the latest date for each stock_id as the current market.
Example: for 1294, the emerging row has date 2024-09-25 while the tpex row carries the current date, so it is a TPEx stock today and its volume is in lots; 1260 has only an emerging row carrying the current date, so it is still an Emerging stock and its volume is in shares.
Also note, when reconciling tick data against the daily volume in TaiwanStockPrice: for TWSE / TPEx stocks the daily volume includes block trades (see TaiwanStockBlockTrade), while tick data does not, so the two will not match exactly.
Row order of the whole-day files
The whole-day files are sorted by stock_id and Time; when several trades share the same time, they are ordered by actual execution sequence. You can take each stock's first row (the open) or its last trade before a given time directly in file order.
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/storage_objects"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockPriceTick",
"date": '2019-01-02',
}
resp = requests.get(url, headers=headers, params=parameter)
data = pd.read_parquet(io.BytesIO(resp.content))
print(data.head())
library(httr)
library(data.table)
library(dplyr)
library(arrow)
url = 'https://api.finmindtrade.com/api/v4/storage_objects'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockPriceTick",
date= "2019-01-02"
),
add_headers(Authorization = paste("Bearer", token))
)
con = content(response, "raw")
data <- read_parquet(con)
close(con)
head(data)
Output
| date | stock_id | deal_price | volume | Time | TickType | |
|---|---|---|---|---|---|---|
| 0 | 2019-01-02 | 0050 | 75.85 | 167 | 09:00:03.794 | 0 |
| 1 | 2019-01-02 | 0050 | 75.90 | 11 | 09:00:08.813 | 1 |
| 2 | 2019-01-02 | 0050 | 75.85 | 2 | 09:00:18.852 | 2 |
| 3 | 2019-01-02 | 0050 | 75.85 | 31 | 09:00:23.871 | 2 |
| 4 | 2019-01-02 | 0050 | 75.85 | 19 | 09:00:28.890 | 2 |
Individual Stock PER, PBR Table TaiwanStockPER¶
- Data range: 2005-10-01 ~ now
- Data update time: Monday to Friday 18:00. The actual update time is based on the API data.
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockPER",
"data_id": "2330",
"start_date": "2020-04-01",
"end_date": "2020-04-12",
}
data = requests.get(url, headers=headers, params=parameter)
data = data.json()
data = pd.DataFrame(data['data'])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockPER",
data_id= "2330",
start_date= "2020-01-02",
end_date= "2020-04-12"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
from FinMind.data import DataLoader
from loguru import logger
import datetime
api = DataLoader()
api.login_by_token(api_token='token')
start = datetime.datetime.now()
df = api.taiwan_stock_per_pbr(
stock_id_list=['2330', '2317', '2454', '3008'],
start_date='2024-01-01',
end_date='2024-12-31',
use_async=True,
)
cost = datetime.datetime.now() - start
logger.info(cost)
Output
| date | stock_id | dividend_yield | PER | PBR | |
|---|---|---|---|---|---|
| 0 | 2020-01-02 | 2330 | 2.36 | 26.69 | 5.54 |
| 1 | 2020-01-03 | 2330 | 2.36 | 26.73 | 5.55 |
| 2 | 2020-01-06 | 2330 | 2.41 | 26.14 | 5.42 |
| 3 | 2020-01-07 | 2330 | 2.43 | 25.94 | 5.38 |
| 4 | 2020-01-08 | 2330 | 2.43 | 25.94 | 5.38 |
Fetch all data for a specific date at once (available only to backer, sponsor members)¶
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockPER",
"start_date": "2020-04-06",
}
data = requests.get(url, headers=headers, params=parameter)
data = data.json()
data = pd.DataFrame(data['data'])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockPER",
start_date= "2020-04-06"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
Output
| date | stock_id | dividend_yield | PER | PBR | |
|---|---|---|---|---|---|
| 0 | 2020-04-06 | 1101 | 7.68 | 9.12 | 1.14 |
| 1 | 2020-04-06 | 1102 | 7.68 | 7.52 | 0.90 |
| 2 | 2020-04-06 | 1103 | 6.60 | 7.54 | 0.43 |
| 3 | 2020-04-06 | 1104 | 6.33 | 9.08 | 0.57 |
| 4 | 2020-04-06 | 1108 | 2.18 | 62.64 | 0.65 |
Order and Trade Statistics Every 5 Seconds TaiwanStockStatisticsOfOrderBookAndTrade¶
(Due to the large data volume, each request only provides one day's data.)
- Data range: 2005-01-01 ~ now
Scope of cumulative trades
Cumulative trades (TotalDealOrder, TotalDealVolume, TotalDealMoney) only count regular trades on the centralized market and exclude odd-lot, block, after-hours fixed-price, auction and tender trades, so the closing total is slightly lower than the daily market volume, and the gap widens on days with large block trades. Volume is in lots (1,000 shares) and value in millions of NTD.
Interval: one row per minute until 2011-01-14, every 15 seconds from 2011-01-17, every 10 seconds from 2014-02-24, and every 5 seconds from 2014-12-29.
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockStatisticsOfOrderBookAndTrade",
"start_date": "2021-01-07",
}
data = requests.get(url, headers=headers, params=parameter)
data = data.json()
data = pd.DataFrame(data['data'])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockStatisticsOfOrderBookAndTrade",
start_date= "2021-01-07"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
Output
| Time | TotalBuyOrder | TotalBuyVolume | TotalSellOrder | TotalSellVolume | TotalDealOrder | TotalDealVolume | TotalDealMoney | date | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 09:00:00 | 298618 | 3229222 | 365465 | 1730137 | 0 | 0 | 0 | 2021-01-07 |
| 1 | 09:00:05 | 301246 | 3254929 | 367886 | 1751034 | 17535 | 97251 | 4515 | 2021-01-07 |
| 2 | 09:00:10 | 304171 | 3283698 | 370338 | 1770414 | 31370 | 150557 | 7041 | 2021-01-07 |
| 3 | 09:00:15 | 307686 | 3325195 | 372828 | 1782960 | 40083 | 177080 | 8088 | 2021-01-07 |
| 4 | 09:00:20 | 310927 | 3345735 | 375220 | 1792055 | 47250 | 198536 | 9137 | 2021-01-07 |
{
Time: str, # time
TotalBuyOrder: str, # cumulative number of buy orders
TotalBuyVolume: int64, # cumulative buy order volume
TotalSellOrder: int64, # cumulative number of sell orders
TotalSellVolume: int64, # cumulative sell order volume
TotalDealOrder: int64, # cumulative number of trades
TotalDealVolume: int64, # cumulative trade volume
TotalDealMoney: int64, # cumulative trade amount
date: str # date
}
Weighted Index TaiwanVariousIndicators5Seconds¶
(Due to the large data volume, each request only provides one day's data.)
- Data range: 2005-01-01 ~ now
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanVariousIndicators5Seconds",
"start_date": "2020-07-01",
}
data = requests.get(url, headers=headers, params=parameter)
data = data.json()
data = pd.DataFrame(data['data'])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanVariousIndicators5Seconds",
start_date="2020-07-01"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
from FinMind.data import DataLoader
from loguru import logger
import datetime
api = DataLoader()
api.login_by_token(api_token='token')
date = '2025-12-08'
start = datetime.datetime.now()
df = api.taiwan_stock_various_indicators_5_seconds(
data_id_list=['發行量加權股價指數', '未含金融保險股指數'],
date=date,
use_async=True,
)
cost = datetime.datetime.now() - start
logger.info(cost)
Output
Day Trading Targets and Volume/Value TaiwanStockDayTrading¶
- Data range: 2014-01-01 ~ now
- Data update time: the day-trading target list and the sell-first-then-buy marker (BuyAfterSale) are available before market open on the same day; the same-day day-trading volume/value (Volume, BuyAmount, SellAmount) is updated after market close at 21:30. The actual update time is based on the API data.
- Sell-first-then-buy marker BuyAfterSale: * = sell-first-then-buy suspended (intraday only buy-first-then-sell is allowed; day trading is still permitted); Y / blank = both buy-first-then-sell and sell-first-then-buy are allowed
- Note: BuyAfterSale reflects the exchange-level eligibility for an individual security (i.e. whether the stock is on the suspended-sell-first list). Whether you can actually sell first still depends on your own account eligibility (completion of the required sell-first agreements and your trading quota) and your broker's current securities-lending availability. Therefore it is normal for a broker's software to show "buy-first-then-sell only" while this field shows both directions; the actual permission follows your individual broker's account eligibility and inventory
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockDayTrading",
"data_id": "2330",
"start_date": "2020-04-02",
"end_date": "2020-04-12",
}
resp = requests.get(url, headers=headers, params=parameter)
data = resp.json()
data = pd.DataFrame(data["data"])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockDayTrading",
data_id= "2330",
start_date= "2020-04-02",
end_date= "2020-04-08"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
from FinMind.data import DataLoader
from loguru import logger
import datetime
api = DataLoader()
api.login_by_token(api_token='token')
start = datetime.datetime.now()
df = api.taiwan_stock_day_trading(
stock_id_list=['2330', '2317', '2454', '3008'],
start_date='2024-01-01',
end_date='2024-12-31',
use_async=True,
)
cost = datetime.datetime.now() - start
logger.info(cost)
Output
| stock_id | date | BuyAfterSale | Volume | BuyAmount | SellAmount | |
|---|---|---|---|---|---|---|
| 0 | 2330 | 2020-04-06 | Y | 8122000 | 2215280000 | 2218094500 |
| 1 | 2330 | 2020-04-07 | Y | 5128000 | 1450483500 | 1447872000 |
| 2 | 2330 | 2020-04-08 | Y | 2467000 | 702411500 | 702367000 |
| 3 | 2330 | 2020-04-09 | Y | 2583000 | 736745500 | 734035500 |
| 4 | 2330 | 2020-04-10 | Y | 1590000 | 445516000 | 444576000 |
Fetch all data for a specific date at once (available only to backer, sponsor members)¶
Example
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockDayTrading",
"start_date": "2020-04-06",
}
res = requests.get(url, headers=headers, params=parameter)
temp = res.json()
data = pd.DataFrame(temp["data"])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockDayTrading",
start_date= "2020-04-06"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
Output
| stock_id | date | BuyAfterSale | Volume | BuyAmount | SellAmount | |
|---|---|---|---|---|---|---|
| 0 | 0050 | 2020-04-06 | 1296000 | 99116100 | 99343200 | |
| 1 | 0051 | 2020-04-06 | 2000 | 57680 | 57560 | |
| 2 | 0052 | 2020-04-06 | 9000 | 536200 | 537700 | |
| 3 | 0053 | 2020-04-06 | 0 | 0 | 0 | |
| 4 | 0054 | 2020-04-06 | 0 | 0 | 0 |
Weighted/OTC Total Return Index TaiwanStockTotalReturnIndex¶
- Data range: 2003-01-01 ~ now
- Data update time: Monday to Friday 16:50. The actual update time is based on the API data.
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockTotalReturnIndex",
"data_id": "TAIEX", # TAIEX total return index
# "data_id": "TPEx", # TPEx index and total return index
"start_date": "2020-04-02",
"end_date": "2020-04-12",
}
resp = requests.get(url, headers=headers, params=parameter)
data = resp.json()
data = pd.DataFrame(data["data"])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockTotalReturnIndex",
data_id= "TAIEX", # TAIEX total return index
# data_id= "TPEx", # TPEx index and total return index
start_date= "2020-04-02",
end_date= "2020-04-08"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
Output
Taiwan Individual Stock 10-Year Line Table TaiwanStock10Year (available only to backer, sponsor members)¶
- Data range: 2011-01-24 ~ now
- The average price is calculated over 2,500 trading days.
- Data update time: Monday to Friday 20:00. The actual update time is based on the API data.
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStock10Year",
"data_id": "2330",
"start_date": "2020-04-02",
"end_date": "2020-04-12",
}
resp = requests.get(url, headers=headers, params=parameter)
data = resp.json()
data = pd.DataFrame(data["data"])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStock10Year",
data_id= "2330",
start_date= "2020-04-02",
end_date= "2020-04-12"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
from FinMind.data import DataLoader
from loguru import logger
import datetime
api = DataLoader()
api.login_by_token(api_token='token')
start = datetime.datetime.now()
df = api.taiwan_stock_10year(
stock_id_list=['2330', '2317', '2454', '3008'],
start_date='2024-01-01',
end_date='2024-12-31',
use_async=True,
)
cost = datetime.datetime.now() - start
logger.info(cost)
Output
Fetch all data for a specific date at once (available only to backer, sponsor members)¶
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStock10Year",
"start_date": "2020-04-06",
}
resp = requests.get(url, headers=headers, params=parameter)
data = resp.json()
data = pd.DataFrame(data["data"])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStock10Year",
start_date= "2020-04-06"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
Output
Taiwan Stock Minute K Table TaiwanStockKBar (available only to sponsor members)¶
(Due to the large data volume, each request only provides one day's data.)
- Data range: individual stocks 2019-01-01 ~ now; TAIEX index (
data_id="TAIEX") 2005-01-03 ~ now - Data update time: Monday to Friday 15:50. The actual update time is based on the API data.
- Some data is missing on these dates: 2019-02-20, 2019-02-21, 2019-02-22 (only the TAIEX index minute K is available on these three days; there is no individual-stock data). In addition, on 2019-05-16 only a small number of ETFs have individual-stock data.
- Enabling Async significantly reduces the data update time. In a Colab test, downloading 2,175 stocks took only 2 minutes 31 seconds.
This table also provides the TAIEX index minute K
Besides individual stocks, passing TAIEX as data_id returns the minute K of the Taiwan Capitalization Weighted Stock Index:
- Data range 2005-01-03 ~ now, longer than the individual-stock minute K (which starts 2019-01-01)
- 271 rows per trading day, covering
09:00:00~13:30:00, one row per minute - An index has no trading volume, so
volumeis always 0;open/high/low/closeare index values within that minute - Make-up trading Saturdays are covered as well
The unit of volume differs by market: lots for TWSE / TPEx, shares for Emerging
The volume column keeps each market's native trading unit: TWSE and TPEx stocks are in lots (1 lot = 1,000 shares); Emerging stocks are in shares — the same rule as TaiwanStockPriceTick. For how to determine a stock's market (and the caveat that transferred stocks keep two rows in TaiwanStockInfo), see the note of the same name in the TaiwanStockPriceTick section.
A 13:33 minute K for TWSE / TPEx stocks is the delayed closing auction
When the closing call auction of a TWSE or TPEx stock triggers the price stabilization measure, the closing match is delayed and executes at 13:33, so that day has an extra 13:33 minute K. This bar is the official closing match of the day — a valid trade that should be kept. Its close equals the official closing price of the day (close in TaiwanStockPrice), which you can use to identify delayed-close days.
Emerging stocks trade continuously until 15:00, so 13:33 is just an ordinary intraday minute for them and has nothing to do with a delayed close. Because a stock may move from the Emerging board to TWSE / TPEx, decide the market by its status on that day.
Example
from FinMind.data import DataLoader
from loguru import logger
import datetime
token = ""
data_loader = DataLoader()
data_loader.login_by_token(token)
date = '2024-12-20'
taiwan_stock_price_df = data_loader.taiwan_stock_daily(start_date=date)
# Only fetch stocks with trading volume greater than 0 on the day
taiwan_stock_price_df = taiwan_stock_price_df[
["stock_id", "Trading_Volume"]
]
taiwan_stock_price_df = taiwan_stock_price_df[
taiwan_stock_price_df["Trading_Volume"] > 0
]
# Fetch IDs of all listed/OTC stocks whose industry_category is not market index, Index, or all securities,
# because these instruments do not have broker breakdown data
stock_info_df = data_loader.taiwan_stock_info()
stock_info = stock_info_df[stock_info_df["type"].isin(["twse", "tpex"])]
cate_mask = stock_info["industry_category"].isin(
["大盤", "Index", "所有證券"]
)
id_mask = stock_info["stock_id"].isin(["TAIEX", "TPEx"])
stock_info = stock_info[~(cate_mask | id_mask)]
stock_info = stock_info.merge(
taiwan_stock_price_df, how="inner", on=["stock_id"]
)
stock_info = stock_info[~stock_info["stock_id"].isin(taiwan_stock_price_df)]
stock_id_list = list(set(stock_info["stock_id"].values))
logger.info(f"len: {len(stock_id_list)}") # 2175
start = datetime.datetime.now()
df = data_loader.taiwan_stock_kbar(
stock_id_list=stock_id_list,
date=date,
use_async=True,
)
cost = datetime.datetime.now() - start
logger.info(cost)
# 0:02:31.357733
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockKBar",
"data_id": "2330",
"start_date": "2023-09-22",
}
resp = requests.get(url, headers=headers, params=parameter)
data = resp.json()
data = pd.DataFrame(data["data"])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockKBar",
data_id= "2330",
start_date= "2023-09-22"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
Output
| date | minute | stock_id | open | high | low | close | volume | |
|---|---|---|---|---|---|---|---|---|
| 0 | 2023-09-22 | 09:00:00 | 2330 | 523 | 524 | 522 | 524 | 3893 |
| 1 | 2023-09-22 | 09:01:00 | 2330 | 524 | 524 | 523 | 524 | 159 |
| 2 | 2023-09-22 | 09:02:00 | 2330 | 523 | 524 | 522 | 523 | 548 |
| 3 | 2023-09-22 | 09:03:00 | 2330 | 522 | 523 | 522 | 522 | 208 |
| 4 | 2023-09-22 | 09:04:00 | 2330 | 522 | 523 | 522 | 522 | 179 |
Fetch all data for a specific date at once (available only to sponsorpro members)¶
(Due to the large data volume, each request only provides one day's data.)
- Data range: 2019-01-02 ~ now, one trading day at a time.
- Providing the dataset and date parameters returns all market data for that day.
- Downloads the whole-day parquet via a signed URL — no need to query stock by stock.
Example
import io
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/storage_objects"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockKBar",
"date": '2026-01-02',
}
resp = requests.get(url, headers=headers, params=parameter)
data = pd.read_parquet(io.BytesIO(resp.content))
print(data.head())
library(httr)
library(data.table)
library(dplyr)
library(arrow)
url = 'https://api.finmindtrade.com/api/v4/storage_objects'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockKBar",
date= "2026-01-02"
),
add_headers(Authorization = paste("Bearer", token))
)
con = content(response, "raw")
data <- read_parquet(con)
close(con)
head(data)
Output
| date | minute | stock_id | open | high | low | close | volume | |
|---|---|---|---|---|---|---|---|---|
| 0 | 2026-01-02 | 09:00:00 | 2330 | 990 | 995 | 988 | 992 | 4100 |
| 1 | 2026-01-02 | 09:01:00 | 2330 | 992 | 993 | 990 | 991 | 210 |
| 2 | 2026-01-02 | 09:02:00 | 2330 | 991 | 992 | 990 | 990 | 310 |
| 3 | 2026-01-02 | 09:03:00 | 2330 | 990 | 991 | 989 | 990 | 190 |
| 4 | 2026-01-02 | 09:04:00 | 2330 | 990 | 991 | 989 | 991 | 170 |
Index Statistics Every 5 Seconds TaiwanStockEvery5SecondsIndex (available only to backer, sponsor members)¶
(Due to the large data volume, each request only provides one day's data.)
- Data range: 2005-01-03 ~ now
13:30:00 closing value, index name history and known gaps
- 13:30:00 is the official closing index: for both TWSE and TPEx indices, the 13:30:00 value is the day's closing index. After TPEx indices enter the closing auction at 13:25, the published intraday value stops changing, so 13:25 ~ 13:29:55 stay at the same value and 13:30:00 is the closing index.
- TPEx chemical index name:
Chemicalfor the full history (the former nameChemicalEngineering, used from 2007-07-02 to 2025-09-12, has been merged intoChemical). - Known gap: on 2017-05-08 the raw TPEx index data starts at 09:00:05, with no 09:00:00 point.
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockEvery5SecondsIndex",
"start_date": "2025-05-09",
}
data = requests.get(url, headers=headers, params=parameter)
data = data.json()
data = pd.DataFrame(data['data'])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockEvery5SecondsIndex",
start_date="2025-05-09"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
from FinMind.data import DataLoader
from loguru import logger
import datetime
api = DataLoader()
api.login_by_token(api_token='token')
date = '2025-12-08'
start = datetime.datetime.now()
df = api.taiwan_stock_every5seconds_index(
data_id_list=['發行量加權股價指數', '未含金融保險股指數'],
date=date,
use_async=True,
)
cost = datetime.datetime.now() - start
logger.info(cost)
Output
| date | time | stock_id | price | kind | |
|---|---|---|---|---|---|
| 0 | 2025-05-09 | 09:00:00 | Automobile | 358.19 | twse |
| 1 | 2025-05-09 | 09:00:05 | Automobile | 358.45 | twse |
| 2 | 2025-05-09 | 09:00:10 | Automobile | 358.19 | twse |
| 3 | 2025-05-09 | 09:00:15 | Automobile | 357.63 | twse |
| 4 | 2025-05-09 | 09:00:20 | Automobile | 357.65 | twse |
Taiwan Stock Suspension Announcement TaiwanStockSuspended (available only to backer, sponsor members)¶
- Data range: 2011-10-06 ~ now
- Records announcements of trading suspension on individual stocks due to material information, shareholder meetings, disposition, etc., including suspension start date/time and expected resumption date/time.
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockSuspended",
"start_date": "2017-04-01",
"end_date": "2025-01-01",
}
data = requests.get(url, headers=headers, params=parameter)
data = data.json()
data = pd.DataFrame(data['data'])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
token = "" # Refer to login to obtain the token
url = 'https://api.finmindtrade.com/api/v4/data'
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockSuspended",
start_date= "2017-04-01",
end_date= "2025-01-01"
),
add_headers(Authorization = paste("Bearer", token))
)
data = response %>% content
df = do.call('cbind',data$data) %>%data.table
head(df)
Output
Day Trading Sell-First-Then-Buy Suspension Notice TaiwanStockDayTradingSuspension (available only to backer, sponsor members)¶
- Data range: 2014-06-01 ~ now
- Records advance notices of suspension of "sell-first-then-buy" day trading on individual stocks, with common reasons including ex-rights and ex-dividend events, and includes the suspension start and end dates.
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockDayTradingSuspension",
"start_date": "2024-12-01",
"end_date": "2025-01-01",
}
data = requests.get(url, headers=headers, params=parameter)
data = data.json()
data = pd.DataFrame(data['data'])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
token = "" # Refer to login to obtain the token
url = 'https://api.finmindtrade.com/api/v4/data'
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockDayTradingSuspension",
start_date= "2024-12-01",
end_date= "2025-01-01"
),
add_headers(Authorization = paste("Bearer", token))
)
data = response %>% content
df = do.call('cbind',data$data) %>%data.table
head(df)
Output
Daily Price Limit TaiwanStockPriceLimit (available only to backer, sponsor members)¶
- Data range: 2000-01-01 ~ now
- Data update time: Monday to Friday 18:00
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockPriceLimit",
"data_id": "2330",
"start_date": "2023-01-01",
}
data = requests.get(url, headers=headers, params=parameter)
data = data.json()
data = pd.DataFrame(data['data'])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockPriceLimit",
data_id="2330",
start_date= "2023-01-01"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)
from FinMind.data import DataLoader
from loguru import logger
import datetime
api = DataLoader()
api.login_by_token(api_token='token')
start = datetime.datetime.now()
df = api.taiwan_stock_price_limit(
stock_id_list=['2330', '2317', '2454', '3008'],
start_date='2024-01-01',
end_date='2024-12-31',
use_async=True,
)
cost = datetime.datetime.now() - start
logger.info(cost)
Output
| date | stock_id | reference_price | limit_up | limit_down | |
|---|---|---|---|---|---|
| 0 | 2023-01-03 | 2330 | 450.00 | 495.00 | 405.00 |
| 1 | 2023-01-04 | 2330 | 452.00 | 497.00 | 407.00 |
| 2 | 2023-01-05 | 2330 | 452.50 | 497.50 | 407.50 |
| 3 | 2023-01-06 | 2330 | 454.50 | 500.00 | 409.00 |
| 4 | 2023-01-09 | 2330 | 458.00 | 503.50 | 412.50 |
Note
When limit_up and limit_down are 0, this means the instrument has no price-limit, including:
- Leveraged ETFs (e.g., 00631L)
- Inverse ETFs (e.g., 00632R)
- Emerging stocks
Fetch all data for a specific date at once (available only to backer, sponsor members)¶
Example
import requests
import pandas as pd
url = "https://api.finmindtrade.com/api/v4/data"
token = "" # Refer to login to obtain the token
headers = {"Authorization": f"Bearer {token}"}
parameter = {
"dataset": "TaiwanStockPriceLimit",
"start_date": "2023-01-03",
}
data = requests.get(url, headers=headers, params=parameter)
data = data.json()
data = pd.DataFrame(data['data'])
print(data.head())
library(httr)
library(data.table)
library(dplyr)
url = 'https://api.finmindtrade.com/api/v4/data'
token = "" # Refer to login to obtain the token
response = httr::GET(
url = url,
query = list(
dataset="TaiwanStockPriceLimit",
start_date= "2023-01-03"
),
add_headers(Authorization = paste("Bearer", token))
)
data = content(response)
df = data$data %>%
do.call('rbind',.) %>%
data.table
head(df)