31 endpoints · Dados de mercado · Fundamentos · Fluxo institucional · Outros
https://api.blave.orgapi-key + secret-key em toda requisiçãoAPI plan or Blave Agent planstock_id — código da TWSE (上市) / TPEx (上櫃), p. ex. 2330, 0050, 00878, 006208. Letras e dígitos (pontos permitidos), ≤ 8 caracteres; caso contrário, 400 {"error": "Invalid stock_id"}.start / end — YYYY-MM-DD, inclusive. Salvo indicação em contrário no bloco, o formato não é validado (o filtro é uma comparação de strings); por isso, envie sempre YYYY-MM-DD.503 {"error": "Upstream rate limit. Please retry shortly."} — tente novamente mais tarde.batch/<data_type> (≤ 50 ids por chamada); nunca percorra um universo inteiro em loop com um endpoint de ação única./studio/market/twstock/list Nenhum.
data = requests.get(f"{BASE_URL}/studio/market/twstock/list" , headers=headers, timeout=60).json()["data"]# [{"stock_id": "00400A", "name": "主動國泰動能高息", "close": 14.72, "market": "TWSE",# "industry_code": None, "listing_date": None}, ...] # 2,392 rows in this response{"data": [...]}, ~2,400 linhas (上市 + 上櫃, incluindo ETFs; 興櫃 excluído).
| Campo | Tipo | Descrição |
|---|---|---|
stock_id | string | Código |
name | string | Nome |
close | float | null | Último fechamento diário (null quando o upstream não tinha valor, p. ex. negociação suspensa) |
market | string | TWSE (上市) ou TPEx (上櫃) |
industry_code | string | null | Código numérico bruto de 產業別 da TWSE/TPEx, repassado sem alteração (não decodificado). null para ETFs / títulos que não são de empresas. Códigos comuns: 15 航運業, 17 金融保險業, 22 生技醫療業, 24 半導體業, 25 電腦及週邊設備業, 26 光電業, 27 通信網路業, 28 電子零組件業, 29 電子通路業, 30 資訊服務業, 31 其他電子業 |
listing_date | string | null | YYYY-MM-DD; null para ETFs / títulos que não são de empresas |
Apenas os erros comuns (500 se os dois mercados falharem).
[:N] concentra a amostra em poucos setores./studio/market/twstock/info/<stock_id> | Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
stock_idstring · pathObrigatório | Código | Veja as convenções da categoria |
info = requests.get(f"{BASE_URL}/studio/market/twstock/info/2330" , headers=headers, timeout=30).json()["data"]# {"stock_id": "2330", "name": "台積電", "close": 2410.0, "industry_code": "24", "listing_date": "1994-09-05"}{"stock_id": "<stock_id>", "data": {...}}; data tem os mesmos campos de uma linha de /list.
| Status | Corpo | Quando |
|---|---|---|
| 400 | {"error": "Invalid stock_id"} | Falha na verificação de formato |
| 404 | {"error": "Stock not found"} | Não é um título listado atualmente |
/list./studio/market/twstock/price/<stock_id> | Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
stock_idstring · pathObrigatório | Código de ação / ETF listado (上市) ou OTC (上櫃) | Letras/dígitos (pontos permitidos), ≤ 8 caracteres — p. ex. 2330, 0050, 00878, 006208 | |
startstring · query | Primeira data, inclusive | YYYY-MM-DD | histórico completo |
endstring · query | Última data, inclusive | YYYY-MM-DD | mais recente disponível |
response = requests.get(f"{BASE_URL}/studio/market/twstock/price/2330" , headers=headers, timeout=60)data = response.json()["data"] # no start/end → full history, 8,069 rows# [{"date": "1994-10-01", "stock_id": "2330", "open": 171.0, "high": 172.0,# "low": 171.0, "close": 172.0, "spread": 1.0,# "volume": 1660506, "turnover_value": 284858008, "turnover_count": 684},# {"date": "1994-10-03", "stock_id": "2330", "open": 172.0, "high": 173.0,# "low": 171.0, "close": 172.0, "spread": 0.0,# "volume": 1560000, "turnover_value": 268084000, "turnover_count": 711}, ...]{"stock_id": "<stock_id>", "data": [ ... ]}, linhas em ordem crescente de date.
| Campo | Tipo | Unidade | Descrição |
|---|---|---|---|
date | string | YYYY-MM-DD | Dia de negociação |
stock_id | string | — | Código da ação |
open / high / low / close | float | TWD | Preços sem ajuste |
spread | float | TWD | Variação em relação ao fechamento anterior |
volume | int | ações (股) | Volume negociado |
turnover_value | int | TWD | Valor negociado |
turnover_count | int | negócios (筆) | Número de negócios |
| Status | Corpo | Quando |
|---|---|---|
| 400 | {"error": "Invalid stock_id"} | stock_id não passa na verificação de formato |
| 404 | {"error": "No data found for stock_id: <stock_id>"} | Código desconhecido / sem dados no upstream |
| 503 | {"error": "Upstream rate limit. Please retry shortly."} | Cota do upstream esgotada — tente novamente mais tarde |
start / end não é validado: um valor malformado filtra por comparação de strings em vez de retornar 400; por isso, envie sempre YYYY-MM-DD.price_adj para backtests de retorno total; este endpoint não tem ajuste.batch/price (≤ 50 ids por chamada) em vez de chamar este endpoint em loop./studio/market/twstock/price_adj/<stock_id> Iguais aos de /price/<stock_id>.
params = {"start": "2020-01-01", "end": "2024-12-31"}data = requests.get(f"{BASE_URL}/studio/market/twstock/price_adj/2330" , headers=headers, params=params, timeout=60).json()["data"]Mesma estrutura e mesmos campos de /price/<stock_id>; open / high / low / close são ajustados, volume / turnover_* são idênticos aos da série bruta.
Iguais aos de /price/<stock_id>.
/price avança./studio/market/twstock/quote/<stock_id> | Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
stock_idstring · pathObrigatório | Código | Veja as convenções da categoria |
data = requests.get(f"{BASE_URL}/studio/market/twstock/quote/2330" , headers=headers, timeout=30).json()["data"]# {"open": 2415.0, "high": 2465.0, "low": 2415.0, "close": 2445.0,# "change_price": -20.0, "change_rate": -0.81, "average_price": 2432.58,# "volume": 4245, "total_volume": 26403, "amount": 10379025000, "total_amount": 64227410000,# "yesterday_volume": 27390, "buy_price": 2445.0, "buy_volume": 17,# "sell_price": 2450.0, "sell_volume": 11, "volume_ratio": 0.96,# "quote_time": "2026-07-03 14:30:00", "stock_id": "2330", "tick_type": 2}{"stock_id": "<stock_id>", "data": {...}}; data é um objeto plano.
| Campo | Tipo | Descrição |
|---|---|---|
open / high / low / close | float | OHLC do dia até o momento |
change_price / change_rate | float | Variação em relação ao fechamento anterior (TWD / %) |
average_price | float | Preço médio negociado |
volume | int | Volume do último tick |
total_volume | int | Volume acumulado do dia |
amount / total_amount | float | Valor negociado do último tick / acumulado |
yesterday_volume | int | Volume do dia anterior |
buy_price / buy_volume | float / int | Melhor oferta de compra |
sell_price / sell_volume | float / int | Melhor oferta de venda |
volume_ratio | float | Razão de volume |
quote_time | string | YYYY-MM-DD HH:MM:SS — um timestamp completo, ao contrário do date simples dos outros endpoints |
stock_id | string | Código |
tick_type | int | 0 indeterminado, 1 iniciado pela venda (賣盤成交), 2 iniciado pela compra (買盤成交) |
| Status | Corpo | Quando |
|---|---|---|
| 400 | {"error": "Invalid stock_id"} | Falha na verificação de formato |
| 404 | {"error": "No data found for stock_id: <stock_id>"} | Sem cotação |
| 503 | {"error": "Upstream rate limit. Please retry shortly."} | Cota do upstream esgotada |
/studio/market/twstock/quote | Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
stock_idsstring · queryObrigatório | Códigos | Separados por vírgula, ≤ 50 ids |
data = requests.get(f"{BASE_URL}/studio/market/twstock/quote" , headers=headers, params={"stock_ids": "2330,2317"}, timeout=30).json()["data"]# {"2330": {...}, "2317": {...}}{"data": {"<stock_id>": {...quote fields...}, ...}}; campos iguais aos de /quote/<stock_id>. Ids sem cotação ficam ausentes.
| Status | Corpo | Quando |
|---|---|---|
| 400 | {"error": "stock_ids parameter required"} | Ausente |
| 400 | {"error": "stock_ids exceeds max 50 per request"} | Ids demais |
| 400 | {"error": "Invalid stock_id in list"} | Um código não passa na verificação de formato |
| 503 | {"error": "Upstream rate limit. Please retry shortly."} | Cota do upstream esgotada |
/studio/market/twstock/quote/all Nenhum.
rows = requests.get(f"{BASE_URL}/studio/market/twstock/quote/all" , headers=headers, timeout=30).json()["data"]{"data": [{...quote fields...}, ...]} (~2,800 linhas); campos iguais aos de /quote/<stock_id>.
| Status | Corpo | Quando |
|---|---|---|
| 503 | {"error": "Upstream rate limit. Please retry shortly."} | Cota do upstream esgotada |
/studio/market/twstock/minute/ohlcv/<stock_id>/<schema> | Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
stock_idstring · pathObrigatório | Código | Um código listado atualmente na TWSE/TPEx, ou TAIEX (加權指數) | |
schemastring · pathObrigatório | Tamanho da barra | 1m, 5m, 15m, 30m, 60m, 1d | |
startstring · query | Primeiro dia | YYYY-MM-DD | end − o intervalo máximo do schema |
endstring · query | Último dia, inclusive | YYYY-MM-DD | hoje (UTC) |
adjuststring · query | 1 = OHLC ajustado (後復權), com os mesmos fatores de /price_adj; volume nunca é ajustado | 0, 1, true, false | 0 |
Intervalo máximo por requisição (end − start): 1m 31 d · 5m 62 d · 15m 93 d · 30m 186 d · 60m 365 d · 1d 3650 d.
body = requests.get(f"{BASE_URL}/studio/market/twstock/minute/ohlcv/2330/1m" , headers=headers, params={"start": "2026-08-06", "end": "2026-08-06"}, timeout=60).json()# {"stock_id": "2330", "schema": "1m", "data": [# {"close": 2385.0, "high": 2395.0, "low": 2385.0, "open": 2395.0, "ts": "2026-08-06 01:00:00+00:00", "volume": 2540}, ...]}{"stock_id", "schema", "data": [...]}.
| Campo | Tipo | Unidade | Descrição |
|---|---|---|---|
ts | string | UTC ISO | Horário de abertura da barra (rótulo do início do minuto); a barra das 13:30 de Taipei é o leilão de fechamento |
open / high / low / close | float | TWD | Preços |
volume | int | lotes (張), não ações | Volume. As barras de TAIEX sempre trazem volume: 0 em todos os schemas — o índice não tem volume, então nenhum é fornecido; não leia esse valor como um número de volume negociado |
| Status | Corpo | Quando |
|---|---|---|
| 400 | {"error": "Invalid stock_id (must be a listed TWSE/TPEx security)"} | Não listado |
| 400 | {"error": "Invalid schema. Allowed: [...]"} | Schema inválido |
| 400 | {"error": "Invalid adjust (use 0 or 1)"} | adjust inválido |
| 400 | {"error": "Invalid date format. Use YYYY-MM-DD"} | Data malformada |
| 400 | {"error": "date_range_too_large", "message": "...", "max_days": <n>} | Intervalo acima do limite |
| 503 | {"error": "market data temporarily unavailable"} | Falha na leitura do armazenamento |
| 503 | {"error": "adjust factors temporarily unavailable"} | adjust=1 e fatores indisponíveis — nunca é servido sem ajuste de forma silenciosa |
minute/ohlcv/symbols antes de pedir anos de histórico.200 com []./quote/<stock_id> para o preço em tempo real./studio/market/twstock/minute/ohlcv/symbols Nenhum.
covered = requests.get(f"{BASE_URL}/studio/market/twstock/minute/ohlcv/symbols" , headers=headers, timeout=30).json()["data"]{"data": ["2330", "TAIEX", ...]} — ids que já têm dados por minuto em disco (ações listadas atualmente mais TAIEX), ordenados.
Apenas os erros comuns.
/studio/market/twstock/kbar/<stock_id> | Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
stock_idstring · pathObrigatório | Código | Um código listado atualmente na TWSE/TPEx, ou TAIEX | |
startstring · query | Primeiro dia | YYYY-MM-DD | hoje − 6 dias |
endstring · query | Último dia; end − start ≤ 31 dias | YYYY-MM-DD | hoje |
data = requests.get(f"{BASE_URL}/studio/market/twstock/kbar/2330" , headers=headers, params={"start": "2026-08-03", "end": "2026-08-07"}, timeout=60).json()["data"]{"stock_id", "data": [...]}, em ordem crescente.
| Campo | Tipo | Descrição |
|---|---|---|
date | string | YYYY-MM-DD (Taipei) |
minute | string | HH:MM:SS de Taipei, início da barra (09:00–13:30) |
stock_id | string | Código |
open / high / low / close | float | TWD |
volume | int | Lotes (張) |
| Status | Corpo | Quando |
|---|---|---|
| 400 | {"error": "Invalid stock_id (must be a listed TWSE/TPEx security)"} | Não listado |
| 400 | {"error": "Date range exceeds 31 days"} | Intervalo longo demais ou data malformada |
minute/ohlcv/<stock_id>/1m. Uma ação listada sem dados por minuto retorna [] (este endpoint não dispara a carga inicial).minute/ohlcv/symbols têm dados./studio/market/twstock/market_value/<stock_id> | Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
stock_idstring · pathObrigatório | Código | Veja as convenções da categoria | |
startstring · query | Primeira data | YYYY-MM-DD | histórico completo |
endstring · query | Última data | YYYY-MM-DD | mais recente |
data = requests.get(f"{BASE_URL}/studio/market/twstock/market_value/2330" , headers=headers, params={"start": "2026-01-01"}, timeout=60).json()["data"]{"stock_id", "data": [{"date", "stock_id", "market_value"}]}; market_value em TWD.
400 stock_id inválido, 404 sem dados, 503 cota do upstream.
/studio/market/twstock/market_value/all | Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
topint · query | Mantém apenas os N maiores por valor de mercado | 1–3000 | todos (~2,400) |
body = requests.get(f"{BASE_URL}/studio/market/twstock/market_value/all" , headers=headers, params={"top": 10}, timeout=60).json()# {"date": "2026-09-17", "twse_ex_etf_market_value": 150952470507848,# "data": [{"is_etf": false, "market": "TWSE", "market_value": 62885997412475,# "name": "台積電", "rank": 1, "stock_id": "2330"},# ...,# {"is_etf": true, "market": "TWSE", "market_value": 2383312875000,# "name": "元大台灣50", "rank": 6, "stock_id": "0050"}, ...]}# Index weight of a 上市 non-ETF stock (works with any `top`, the denominator is whole-market)row = body["data"][0] # 2330 — market "TWSE", is_etf falseshare = row["market_value"] / body["twse_ex_etf_market_value"]# ETFs rank alongside stocks (0050 is rank 6) — filter them with `is_etf`. Never by code prefix,# and never by re-fetching a classification: `is_etf` already IS that classification.rows = requests.get(f"{BASE_URL}/studio/market/twstock/market_value/all" , headers=headers, params={"top": 100}, timeout=60).json()["data"]top50 = [r["stock_id"] for r in rows if not r["is_etf"]][:50] # ETF-free market-cap top 50tpex_only = [r["stock_id"] for r in rows if r["market"] == "TPEx"] # board filter is exact{"date": "YYYY-MM-DD", "twse_ex_etf_market_value": int, "data": [...]}, em ordem decrescente de valor de mercado.
| Campo | Tipo | Descrição |
|---|---|---|
date | string | Dia de referência efetivamente usado (último publicado; pode estar um dia atrás de hoje) |
twse_ex_etf_market_value | int | TWD. Soma das linhas com market == "TWSE" que não são ETFs, no mesmo dia de referência. Denominador do mercado inteiro — não é reduzido por top |
data[].rank | int | Posição no ranking, começando em 1 |
data[].stock_id | string | Código |
data[].name | string | Nome |
data[].market | string | "TWSE" (上市) ou "TPEx" (上櫃), a partir das listas de títulos listados da TWSE / TPEx |
data[].market_value | int | TWD |
data[].is_etf | bool | true para os ETFs do ranking (359 de 2,370 linhas em 2026-09-17). false significa "fora do conjunto de ETFs", não "confirmado como não sendo ETF": um título sem categoria de setor — p. ex. o REIT 01010T — é false e continua dentro de twse_ex_etf_market_value |
| Status | Corpo | Quando |
|---|---|---|
| 400 | {"error": "top must be an integer between 1 and 3000"} | top inválido |
| 404 | {"error": "No recent market value data available"} (ou uma mensagem de listagem incompleta) | Sem dados recentes |
| 503 | {"error": "Upstream rate limit. Please retry shortly."} | Cota do upstream esgotada |
/market_value/<stock_id> em loop para perguntas do tipo "os N maiores por valor de mercado".rank e twse_ex_etf_market_value são universos diferentes. rank é do mercado inteiro — 上市 + 上櫃, ETFs incluídos — e não mudou quando o denominador foi adicionado. O denominador é só 上市 e exclui ETFs (industry_category em {ETF, 上櫃ETF, 上櫃指數股票型基金(ETF)}); REITs e ações preferenciais não são excluídos dele. Assim, market_value / twse_ex_etf_market_value só é um peso no índice para uma linha cujo market é "TWSE" e que não é ETF — uma linha de TPEx ou de ETF sobre esse denominador não é um peso —, enquanto rank continua sendo um ranking do mercado inteiro. Não leia os dois como um único ranking.market é uma etiqueta do segmento de listagem, não um indicador de ETF — is_etf é o indicador de ETF. Use-o para obter um universo sem ETFs. Não deduza ETFs pelo prefixo do stock_id (00 é uma convenção de mercado, não um contrato, e deixa de fora os REITs 01xxxT) nem busque de novo uma classificação em outro lugar. is_etf é exatamente o critério com que twse_ex_etf_market_value é calculado, então um filtro por is_etf e o denominador nunca divergem./studio/market/twstock/per/<stock_id> | Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
stock_idstring · pathObrigatório | Código | Veja as convenções da categoria | |
startstring · query | Primeira data | YYYY-MM-DD | histórico completo |
endstring · query | Última data | YYYY-MM-DD | mais recente |
data = requests.get(f"{BASE_URL}/studio/market/twstock/per/2330" , headers=headers, params={"start": "2026-01-01", "end": "2026-07-22"}, timeout=60).json()["data"]# [{"date": "2026-07-21", "stock_id": "2330", "dividend_yield": 0.95, "PER": 34.87, "PBR": 11.05}, ...]{"stock_id", "data": [...]}.
| Campo | Tipo | Descrição |
|---|---|---|
date | string | Dia de negociação |
stock_id | string | Código |
dividend_yield | float | Dividend yield (%) |
PER | float | Preço / lucro |
PBR | float | Preço / valor patrimonial |
400 stock_id inválido, 404 sem dados, 503 cota do upstream.
batch/per./studio/market/twstock/financials/<stock_id> | Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
stock_idstring · pathObrigatório | Código | Veja as convenções da categoria | |
startstring · query | Primeira data | YYYY-MM-DD | 2013-01-01 |
endstring · query | Última data | YYYY-MM-DD | hoje |
import pandas as pddata = requests.get(f"{BASE_URL}/studio/market/twstock/financials/2330" , headers=headers, params={"start": "2022-01-01", "end": "2024-12-31"}, timeout=30).json()["data"]# [{"date": "2022-03-31", "stock_id": "2330", "type": "Revenue", "value": 491075000000.0, "origin_name": "營業收入"}, ...]wide = pd.DataFrame(data).pivot_table(index="date", columns="type", values="value", aggfunc="first"){"stock_id", "data": [...]}, formato longo (uma linha por item por trimestre).
| Campo | Tipo | Descrição |
|---|---|---|
date | string | Fim do trimestre (03-31 / 06-30 / 09-30 / 12-31) |
stock_id | string | Código |
type | string | Código do item, p. ex. Revenue, GrossProfit, OperatingIncome, NetIncome, EPS, TAX, OtherComprehensiveIncome |
value | float | Valor (TWD; EPS em TWD por ação) |
origin_name | string | Rótulo em chinês — use-o para identificar códigos type desconhecidos |
400 stock_id inválido, 404 sem dados, 503 cota do upstream.
start é 2013-01-01; envie um start anterior e as linhas anteriores são retornadas (2330 recua até 2000-06-30)./studio/market/twstock/balance_sheet/<stock_id> Iguais aos de /financials/<stock_id>.
data = requests.get(f"{BASE_URL}/studio/market/twstock/balance_sheet/2330" , headers=headers, params={"start": "2022-01-01"}, timeout=30).json()["data"]Mesmo formato longo de /financials/<stock_id>. Principais códigos type: CashAndCashEquivalents, TotalAssets, TotalLiabilities, TotalEquity. Códigos terminados em _per são % do ativo total.
400 stock_id inválido, 404 sem dados, 503 cota do upstream.
start é 2013-01-01; envie um start anterior e as linhas anteriores são retornadas (2330 recua até 2012-12-31)./studio/market/twstock/cashflow/<stock_id> Iguais aos de /financials/<stock_id>.
import pandas as pddata = requests.get(f"{BASE_URL}/studio/market/twstock/cashflow/2330" , headers=headers, params={"start": "2022-01-01"}, timeout=30).json()["data"]cfo = (pd.DataFrame(data).query("type == 'CashFlowsFromOperatingActivities'") .assign(date=lambda d: pd.to_datetime(d["date"])).set_index("date")["value"].sort_index())cfo_q = cfo - cfo.groupby(cfo.index.year).shift(1).fillna(0) # YTD → single quarterMesmo formato longo de /financials/<stock_id>. Principais códigos type (os códigos do próprio conjunto de dados de origem; o conjunto completo varia por empresa e por ano, então trate a resposta como a lista de referência e use origin_name para o que não estiver abaixo). Filtre por type, não por origin_name — o rótulo de um mesmo código alterna entre parênteses de largura inteira e de meia largura ao longo dos anos:
type | origin_name |
|---|---|
CashFlowsFromOperatingActivities | 營業活動之淨現金流入(流出) |
CashProvidedByInvestingActivities | 投資活動之淨現金流入(流出) |
CashFlowsProvidedFromFinancingActivities | 籌資活動之淨現金流入(流出) |
PropertyAndPlantAndEquipment | 取得不動產、廠房及設備 (capex, negativo) |
Depreciation / AmortizationExpense | 折舊費用 / 攤銷費用 |
CashBalancesIncrease | 本期現金及約當現金增加(減少)數 |
CashBalancesBeginningOfPeriod / CashBalancesEndOfPeriod | 期初(年初)/ 期末現金及約當現金餘額 |
Os itens de fluxo são acumulados no ano (YTD), como são reportados em Taiwan: a linha 03-31 é só o Q1, 06-30 é Q1–Q2, 09-30 é Q1–Q3, 12-31 é o ano inteiro. Para um trimestre isolado, subtraia o trimestre anterior do mesmo ano (o Q1 não precisa de subtração) — portanto, busque a partir de um start em janeiro. CashBalancesEndOfPeriod é o saldo no fim do trimestre; CashBalancesBeginningOfPeriod é o saldo no início do ano. Este endpoint não tem o parâmetro period — sempre retorna YTD (a visão de trimestre isolado ?period=quarter existe apenas na rota do gráfico da web, não aqui).
400 stock_id inválido, 404 sem dados, 503 cota do upstream.
start é 2013-01-01; envie um start anterior e as linhas anteriores são retornadas (2330 recua até 2012-03-31)./studio/market/twstock/monthly_revenue/<stock_id> | Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
stock_idstring · pathObrigatório | Código | Veja as convenções da categoria | |
startstring · query | Primeira data | YYYY-MM-DD | 2000-01-01 |
endstring · query | Última data | YYYY-MM-DD | hoje |
import pandas as pddata = requests.get(f"{BASE_URL}/studio/market/twstock/monthly_revenue/2330" , headers=headers, params={"start": "2024-01-01", "end": "2024-12-31"}, timeout=30).json()["data"]df = pd.DataFrame(data).sort_values(["revenue_year", "revenue_month"])df["yoy_pct"] = df["revenue"].pct_change(periods=12) * 100# [{"date": "2024-01-01", "stock_id": "2330", "country": "Taiwan", "create_time": "",# "revenue": 176299866000, "revenue_year": 2023, "revenue_month": 12},# {"date": "2024-02-01", "stock_id": "2330", "country": "Taiwan", "create_time": "",# "revenue": 215785127000, "revenue_year": 2024, "revenue_month": 1}, ...]{"stock_id", "data": [...]}, uma linha por mês.
| Campo | Tipo | Descrição |
|---|---|---|
date | string | Primeiro dia do mês seguinte ao mês da receita — 2024-01-01 traz revenue_year: 2023, revenue_month: 12. Nunca use este campo como o período |
stock_id | string | Código |
country | string | Mercado — o valor observado é Taiwan |
create_time | string | Observado vazio ("") em todas as linhas |
revenue | int | Receita mensal em TWD (元), não em milhares — inferido pela magnitude, não declarado pelo upstream: 2330 para revenue_year 2024, revenue_month 1 retornou 215785127000, que só é um número plausível se lido em 元 (NT$ 215.8 bi) |
revenue_month | int | Mês da receita (1–12) — use este campo, não date, para o período |
revenue_year | int | Ano da receita |
400 stock_id inválido, 404 sem dados, 503 cota do upstream.
/studio/market/twstock/ratios/<stock_id> | Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
stock_idstring · pathObrigatório | Código | Veja as convenções da categoria | |
startstring · query | Primeira data de fim de trimestre | YYYY-MM-DD | 2013-01-01 |
endstring · query | Última data de fim de trimestre | YYYY-MM-DD | hoje |
import pandas as pddata = requests.get(f"{BASE_URL}/studio/market/twstock/ratios/2330" , headers=headers, params={"start": "2024-01-01"}, timeout=30).json()["data"]# [..., {"date": "2026-06-30", "stock_id": "2330",# "gross_margin_q": 67.7207, "gross_margin_ttm": 64.2302, "operating_margin_q": 60.3443, "operating_margin_ttm": 56.1009,# "net_margin_q": 55.6354, "net_margin_ttm": 50.3717, "roe_q": 11.3934, "roe_ttm": 40.3342, "roa_q": 7.8372, "roa_ttm": 27.3074,# "eps_q": 27.25, "eps_ttm": 86.28, "eps_yoy_q": 77.4089, "eps_yoy_ttm": 53.2232,# "revenue_yoy_q": 36.0453, "revenue_yoy_ttm": 30.5567, "revenue_qoq_q": 12.0163, "revenue_qoq_ttm": 8.2017,# "debt_ratio": 30.9438, "current_ratio": 245.7635, "quick_ratio": 225.0114, "equity_multiplier": 1.4481,# "interest_coverage_q": 280.5515, "interest_coverage_ttm": 227.0232,# "inventory_turnover_q": 1.1767, "inventory_turnover_ttm": 4.6058, "cfo_to_net_income_q": 1.1084, "cfo_to_net_income_ttm": 1.1779,# "fcf_q": 287363030000.0, "fcf_ttm": 1143556366000.0, "fcf_per_share_q": 11.0827, "fcf_per_share_ttm": 44.1036, ...}]df = pd.DataFrame(data).assign(date=lambda d: pd.to_datetime(d["date"])).set_index("date"){"stock_id", "data": [...]}, formato largo: uma linha por trimestre, da mais antiga para a mais recente, uma coluna por indicador. Cada indicador é um float arredondado para 4 casas decimais, ou null.
| Campo | Tipo | Descrição |
|---|---|---|
date | string | Fim do trimestre (03-31 / 06-30 / 09-30 / 12-31) — não o dia em que o relatório se tornou público |
stock_id | string | Código |
<ratio>_q | float | null | Apenas o trimestre |
<ratio>_ttm | float | null | Últimos quatro trimestres (soma dos quatro trimestres isolados); null se faltar algum dos quatro |
debt_ratio, current_ratio, quick_ratio, equity_multiplier | float | null | Indicadores de balanço no fim do período — sem sufixo |
<ratio> (cada um tem _q e _ttm):
| Grupo | Indicadores | Unidade |
|---|---|---|
| Rentabilidade | gross_margin, operating_margin, pretax_margin, net_margin, opex_ratio, roe, roa | % (já ×100) |
| Por ação | eps, revenue_per_share, fcf_per_share | TWD por ação |
| Crescimento | revenue_yoy, revenue_qoq, operating_income_yoy, net_income_yoy, eps_yoy | % (já ×100) |
| Estrutura | interest_coverage | vezes |
| Eficiência | receivable_turnover, inventory_turnover, asset_turnover, cfo_to_net_income | vezes |
| Fluxo de caixa | fcf | TWD, valor bruto (não em milhares) |
Colunas sem sufixo: debt_ratio, current_ratio, quick_ratio são % (já ×100 — uma liquidez corrente de 2.46× é retornada como 245.7635); equity_multiplier é em vezes.
| Status | Corpo | Quando |
|---|---|---|
| 400 | {"error": "Invalid stock_id"} | O código não passa na verificação de formato |
| 404 | {"error": "No data found for stock_id: <id>"} | Sem demonstrações financeiras para o código (ETFs como 0050 / 00878), ou nenhuma linha dentro de start–end |
| 503 | {"error": "Data temporarily unavailable. Please retry shortly."} | Armazenamento de indicadores não está pronto — tente novamente mais tarde, nunca leia isso como "sem dados" |
null (sem margem bruta, liquidez corrente etc.).date é lookahead.null, nunca em 0.per/<stock_id>) e os indicadores de receita mensal (calcule YoY / MoM a partir de monthly_revenue/<stock_id>).GET /studio/market/twstock/batch/ratios?stock_ids=... (≤ 50 ids por chamada).start anterior não retorna nada mais antigo./studio/market/twstock/dividend/<stock_id> | Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
stock_idstring · pathObrigatório | Código | Código listado atualmente (4–6 dígitos, letra final opcional) | |
startstring · query | Primeira data efetiva | YYYY-MM-DD estrito | histórico completo |
endstring · query | Última data efetiva | YYYY-MM-DD estrito | histórico completo |
O filtro por intervalo usa uma data efetiva em três níveis: cash_ex_date se definida, senão stock_ex_date, senão record_date — eventos recém-anunciados ainda sem data ex também aparecem.
data = requests.get(f"{BASE_URL}/studio/market/twstock/dividend/2330" , headers=headers, params={"start": "2025-01-01", "end": "2025-12-31"}, timeout=30).json()["data"]# [{"record_date": "2025-03-24", "period": "113年第3季", "announce_date": "2025-03-03",# "cash_ex_date": "2025-03-18", "stock_ex_date": "", "pay_date": "2025-04-10",# "cash": 4.50002042, "stock": 0.0, "stock_ratio": 0.0}, ...]{"stock_id", "data": [...]}, uma linha por linha de anúncio.
| Campo | Tipo | Descrição |
|---|---|---|
record_date | string | 權利分派基準日 YYYY-MM-DD |
period | string | 股利所屬期間 — um rótulo opaco (114年第3季, 113, 不適用, …); compare como string, não converta em ano |
announce_date | string | 公告日; "" quando desconhecida |
cash_ex_date | string | 除息交易日; "" quando não há / não definida |
stock_ex_date | string | 除權交易日; "" quando não há |
pay_date | string | 現金股利發放日; "" quando desconhecida |
cash | float | Dividendo em dinheiro por ação (TWD, 盈餘 + 公積) |
stock | float | Dividendo em ações por ação (元面額, 盈餘 + 公積) |
stock_ratio | float | stock / 10 — proporção de ajuste no estilo de desdobramento |
| Status | Corpo | Quando |
|---|---|---|
| 400 | {"error": "Invalid stock_id"} | Falha na verificação de formato |
| 400 | {"error": "Invalid start date, expected YYYY-MM-DD"} (ou end) | Data malformada |
| 404 | {"error": "No data found for stock_id: <id>"} / {"error": "No dividend records for stock_id: <id>"} | Não listado, ou sem nenhum histórico de dividendos |
| 503 | {"error": "Upstream rate limit. Please retry shortly."} | Cota do upstream esgotada |
cash == 0 e stock == 0) são mantidas — uma decisão anunciada de não distribuir.2330 chegou a uma data uma semana à frente da requisição. Filtre você mesmo por data se precisar apenas de eventos passados.200 + [] (diferente de 404).404./studio/market/twstock/news/<stock_id> | Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
stock_idstring · pathObrigatório | Código | Veja as convenções da categoria | |
startstring · query | Primeiro dia | YYYY-MM-DD | hoje − 6 dias |
endstring · query | Último dia; end − start ≤ 31 dias | YYYY-MM-DD | hoje |
data = requests.get(f"{BASE_URL}/studio/market/twstock/news/2330" , headers=headers, params={"start": "2026-08-01", "end": "2026-08-07"}, timeout=60).json()["data"]{"stock_id", "data": [...]}, vários artigos por dia (fins de semana incluídos).
| Campo | Tipo | Descrição |
|---|---|---|
date | string | Data e hora de publicação |
stock_id | string | Código |
title | string | Título |
source | string | Veículo |
link | string | URL |
| Status | Corpo | Quando |
|---|---|---|
| 400 | {"error": "Date range exceeds 31 days"} ou uma mensagem de erro de análise de data | Intervalo longo demais / data malformada |
| 503 | {"error": "Upstream rate limit. Please retry shortly."} | Cota do upstream esgotada |
[]./studio/market/twstock/institutional/<stock_id> | Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
stock_idstring · pathObrigatório | Código | Veja as convenções da categoria | |
startstring · query | Primeira data | YYYY-MM-DD | histórico completo |
endstring · query | Última data | YYYY-MM-DD | mais recente |
data = requests.get(f"{BASE_URL}/studio/market/twstock/institutional/2330" , headers=headers, params={"start": "2024-01-01", "end": "2024-12-31"}, timeout=60).json()["data"]# [{"date": "2024-01-02", "stock_id": "2330", "foreign_buy": 28464159, "foreign_sell": 47404324,# "trust_buy": 5553520, "trust_sell": 269712, "dealer_self_buy": 452000, "dealer_self_sell": 366190,# "dealer_hedge_buy": 942546, "dealer_hedge_sell": 780090,# "foreign_dealer_self_buy": 0, "foreign_dealer_self_sell": 0}, ...]{"stock_id", "data": [...]}, formato largo, uma linha por dia. Todos os valores em ações (股).
| Campo | Descrição |
|---|---|
date, stock_id | Dia, código |
foreign_buy / foreign_sell | 外資 (sem os dealers estrangeiros) |
trust_buy / trust_sell | 投信 |
dealer_self_buy / dealer_self_sell | 自營商自行買賣 |
dealer_hedge_buy / dealer_hedge_sell | 自營商避險 |
foreign_dealer_self_buy / foreign_dealer_self_sell | 外資自營商 (quase sempre 0) |
400 stock_id inválido, 404 sem dados, 503 cota do upstream.
*_buy − *_sell.GET /studio/market/twmarket/institutional) agrupa de outra forma — veja aquela seção./studio/market/twstock/margin/<stock_id> | Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
stock_idstring · pathObrigatório | Código | Veja as convenções da categoria | |
startstring · query | Primeira data | YYYY-MM-DD | histórico completo |
endstring · query | Última data | YYYY-MM-DD | mais recente |
import pandas as pddata = requests.get(f"{BASE_URL}/studio/market/twstock/margin/2330" , headers=headers, params={"start": "2024-01-01"}, timeout=60).json()["data"]df = pd.DataFrame(data)df["margin_util"] = df["margin_balance"] / df["margin_limit"] # 融資使用率{"stock_id", "data": [...]}, uma linha por dia. Os valores são em lotes (張), não em ações — verificado com o MI_MARGN da TWSE: para 2026-09-15, 2330 retornou margin_balance: 29282 e margin_limit: 6483092, exatamente iguais aos 今日餘額 29,282 e 次一營業日限額 6,483,092 da própria TWSE para essa data. Cada linha traz seu próprio date e stock_id; ao ler o histórico completo (sem start / end), tire todos os números da mesma linha — margin_limit é republicado a cada dia e muda ao longo do tempo.
| Campo | Descrição |
|---|---|
margin_buy / margin_sell | 融資買進 / 賣出 |
margin_cash_repay | 融資現金償還 |
margin_balance / margin_prev_balance | 融資今日 / 前日餘額 |
margin_limit | 融資限額 — o 次一營業日限額 da TWSE conforme publicado na data daquela linha, ou seja, o limite que vale para o PRÓXIMO dia útil (2330 em 2026-09-15: 6,483,092 lotes) |
short_buy / short_sell | 融券買進 / 賣出 |
short_cash_repay | 融券現金償還 |
short_balance / short_prev_balance | 融券今日 / 前日餘額 |
short_limit | 融券限額 |
offset_loan_short | 資券相抵 |
400 stock_id inválido, 404 sem dados, 503 cota do upstream.
/studio/market/twstock/gov_bank/<stock_id> | Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
stock_idstring · pathObrigatório | Código | Veja as convenções da categoria | |
startstring · query | Primeiro dia | YYYY-MM-DD | hoje − 6 dias |
endstring · query | Último dia; end − start ≤ 31 dias | YYYY-MM-DD | hoje |
data = requests.get(f"{BASE_URL}/studio/market/twstock/gov_bank/2330" , headers=headers, params={"start": "2026-08-01", "end": "2026-08-07"}, timeout=60).json()["data"]{"stock_id", "data": [...]}, até 8 linhas por dia (uma por banco), ordenadas por data e banco.
| Campo | Descrição |
|---|---|
date, stock_id | Dia, código |
bank_name | Banco |
buy / sell | Ações compradas / vendidas |
buy_amount / sell_amount | TWD comprados / vendidos |
| Status | Corpo | Quando |
|---|---|---|
| 400 | {"error": "Date range exceeds 31 days"} ou uma mensagem de erro de análise de data | Intervalo longo demais / data malformada |
| 503 | {"error": "Upstream rate limit. Please retry shortly."} | Cota do upstream esgotada |
/studio/market/twstock/lending/<stock_id> | Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
stock_idstring · pathObrigatório | Código | Veja as convenções da categoria | |
startstring · query | Primeira data | YYYY-MM-DD | histórico completo |
endstring · query | Última data | YYYY-MM-DD | mais recente |
data = requests.get(f"{BASE_URL}/studio/market/twstock/lending/2330" , headers=headers, params={"start": "2026-08-01"}, timeout=60).json()["data"]{"stock_id", "data": [...]}, várias linhas por dia.
| Campo | Descrição |
|---|---|
date, stock_id | Dia, código |
transaction_type | 競價 / 議借 |
volume | Volume |
fee_rate | Taxa de empréstimo |
close | Preço de fechamento |
original_return_date | Data de devolução original |
original_lending_period | Prazo de empréstimo original |
400 stock_id inválido, 404 sem dados, 503 cota do upstream.
/studio/market/twstock/broker/search | Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
namestring · queryObrigatório | Nome da filial a buscar | Qualquer substring, sem diferenciar maiúsculas de minúsculas |
rows = requests.get(f"{BASE_URL}/studio/market/twstock/broker/search" , headers=headers, params={"name": "松山"}, timeout=30).json()["data"]# [{"broker_id": "9217", "broker_name": "凱基-松山"}, ...]{"query": "<name>", "data": [{"broker_id", "broker_name"}]}.
| Status | Corpo | Quando |
|---|---|---|
| 400 | {"error": "name parameter required"} | Ausente |
| 503 | {"error": "Upstream rate limit. Please retry shortly."} | Cota do upstream esgotada |
/studio/market/twstock/broker/stock/<stock_id> Envie date para um único dia, ou start (+ end) para um intervalo; start prevalece se os dois forem enviados.
| Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
stock_idstring · pathObrigatório | Código | Veja as convenções da categoria | |
datestring · query | Dia único | YYYY-MM-DD | hoje |
startstring · query | Início do intervalo | YYYY-MM-DD | |
endstring · query | Fim do intervalo; intervalo ≤ 366 dias, inclusive | YYYY-MM-DD | start |
rows = requests.get(f"{BASE_URL}/studio/market/twstock/broker/stock/2330" , headers=headers, params={"start": "2026-08-03", "end": "2026-08-07"}, timeout=60).json()["data"]{"stock_id", "data": [...]}, uma linha por filial por dia.
| Campo | Tipo | Descrição |
|---|---|---|
date | string | Dia de negociação |
stock_id | string | Código |
broker_id | string | Código da filial (pode ser alfanumérico, p. ex. 920A) |
broker_name | string | Nome da filial |
price | float | Preço médio negociado ponderado por volume |
buy / sell | int | Ações compradas / vendidas |
| Status | Corpo | Quando |
|---|---|---|
| 400 | {"error": "Invalid stock_id"} | Falha na verificação de formato |
| 400 | {"error": "Invalid date (YYYY-MM-DD)"} | Data malformada |
| 400 | {"error": "start/end range is <n> days; max 366 (inclusive) — split into smaller ranges"} | Intervalo longo demais |
| 503 | {"error": "Upstream rate limit. Please retry shortly."} | Dados temporariamente indisponíveis — tente novamente; não leia isso como "sem negócios" |
200 + [].start / end em 2026-09-06 → 2026-09-13 retornaram linhas de cinco dias de negociação distintos, tanto em broker/stock/<stock_id> quanto em broker/trader/<trader_id>./studio/market/twstock/broker/trader/<trader_id> Mesmas regras de date / start / end de /broker/stock/<stock_id>.
| Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
trader_idstring · pathObrigatório | Código da filial obtido em /broker/search | Letras, dígitos, - (p. ex. 9217, 920A) | |
datestring · query | Dia único | YYYY-MM-DD | hoje |
startstring · query | Início do intervalo | YYYY-MM-DD | |
endstring · query | Fim do intervalo; intervalo ≤ 366 dias, inclusive | YYYY-MM-DD | start |
rows = requests.get(f"{BASE_URL}/studio/market/twstock/broker/trader/9217" , headers=headers, params={"date": "2026-08-07"}, timeout=60).json()["data"]{"trader_id", "data": [...]}, uma linha por ação por dia; campos date, broker_id, broker_name, stock_id, price, buy, sell (como em /broker/stock).
Como em /broker/stock/<stock_id>, com 400 {"error": "Invalid trader_id"} para um código inválido.
/studio/market/twstock/alerts Informe date, ou start / end, ou nenhum deles (= hoje, Taipei).
| Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
datestring · query | Um dia: disposições em vigor nesse dia, avisos de atenção anunciados nesse dia | YYYY-MM-DD estrito; não pode ser usado com start / end | |
startstring · query | Primeiro dia do intervalo | YYYY-MM-DD estrito | 2001-01-01 com stock_id; caso contrário, end − 365 dias |
endstring · query | Último dia do intervalo (inclusive) | YYYY-MM-DD estrito | hoje (ou start, se posterior) |
kindstring · query | Tipo de anúncio | disposal (處置), notice (注意) | ambos |
marketstring · query | Exchange | twse, tpex | ambos |
stock_idstring · query | Um código; remove o limite de 366 dias | Veja as convenções da categoria | todos |
Semântica do intervalo: uma disposição é retornada quando seu período (start–end) se sobrepõe ao intervalo; um aviso de atenção, quando sua date de anúncio está dentro dele. Sem stock_id, o intervalo é de no máximo 366 dias, inclusive — divida intervalos mais longos do mercado inteiro (um ano civil por chamada cabe). Ao contrário do padrão da categoria, start / end / date são validados estritamente.
# disposals in force on one daydata = requests.get(f"{BASE_URL}/studio/market/twstock/alerts" , headers=headers, params={"date": "2026-10-13", "kind": "disposal"}, timeout=30).json()["data"]# [..., {"date": "2026-10-12", "stock_id": "5228", "stock_name": "鈺鎧", "market": "tpex",# "kind": "disposal", "count": 2, "start": "2026-10-13", "end": "2026-10-19",# "condition": "連續3個營業日", "measure": "第一次處置", "match_minutes": 2,# "reason": "* 公布日期:115/10/12\n* 證券代號:5228\n…", "close": 59.6, "pe": 29.22},# {"date": "2026-10-12", "stock_id": "2492", "stock_name": "華新科", "market": "twse",# "kind": "disposal", "count": 8, "start": "2026-10-13", "end": "2026-10-19",# "condition": "連續三次", "measure": "第一次處置", "match_minutes": 2,# "reason": "1處置原因:該有價證券之交易,連續三個營業日達本公司「公布注意交易資訊」標準。\n2處置期間:…", "close": None, "pe": None}, ...] # 36 rows# notices announced on one daynotes = requests.get(f"{BASE_URL}/studio/market/twstock/alerts" , headers=headers, params={"date": "2026-10-12", "kind": "notice"}, timeout=30).json()["data"]# [..., {"date": "2026-10-12", "stock_id": "5228", "stock_name": "鈺鎧", "market": "tpex",# "kind": "notice", "count": 15, "start": None, "end": None, "condition": "第一款、第三款、第四款",# "measure": None, "match_minutes": None,# "reason": "最近六個營業日(含當日)累積之最後成交價漲幅達32.63%(第一款)\n…", "close": 59.6, "pe": 29.22}, ...]# one stock's disposal history (no range cap with stock_id)hist = requests.get(f"{BASE_URL}/studio/market/twstock/alerts" , headers=headers, params={"stock_id": "2492", "kind": "disposal", "start": "2001-01-01"}, timeout=30).json()["data"]# 10 rows: 2001-11-23~2001-11-29 收足五成款券 (match_minutes None), 2018-05-08~2018-05-21 第一次處置 (5), …,# 2026-10-13~2026-10-19 第一次處置 (2){"start", "end", "data": [...]}; start / end repetem o intervalo resolvido (ambos iguais a date quando date foi enviado). Linhas ordenadas por date, market, kind, stock_id. Uma linha por anúncio.
| Campo | Tipo | Descrição |
|---|---|---|
date | string | Dia do anúncio YYYY-MM-DD (uma disposição entra em vigor no dia de negociação seguinte) |
stock_id | string | Código — inclui warrants, ETFs e títulos conversíveis (p. ex. 037060, 45402) |
stock_name | string | null | Nome conforme publicado |
market | string | twse (上市) ou tpex (上櫃) |
kind | string | disposal ou notice |
count | int | Contagem acumulada da bolsa (累計 / 累計次數) |
start, end | string | null | Período da disposição, com os dois dias incluídos; null em avisos de atenção |
condition | string | null | Disposição: o gatilho conforme publicado (連續三次, 連續3個營業日, 最近十個營業日已有六次 …). Aviso de atenção: as cláusulas citadas (第一款、第五款); null se não houver |
measure | string | null | Tipo de disposição: 第一次處置, 第二次處置, 再次處置, 人工管制撮合, 收足五成款券 …; null em avisos de atenção e nas linhas antigas da TPEx |
match_minutes | int | null | Disposição: o N de 「約每N分鐘撮合一次」 lido do texto; null quando o texto não indica nenhum (todas as disposições da TWSE antes de ~2011 — o texto delas está em branco — e as medidas que não são de casamento de ordens) e em avisos de atenção |
reason | string | null | Texto completo do anúncio; null onde a bolsa não publicou nenhum (todas as disposições da TWSE antes de 2011-03) (disposição 處置內容, aviso de atenção 注意交易資訊) |
close, pe | float | null | Fechamento e P/L no anúncio; sempre null nas disposições da TWSE |
| Status | Corpo | Quando |
|---|---|---|
| 400 | {"error": "Invalid start date, expected YYYY-MM-DD"} (ou end) | start / end malformados |
| 400 | {"error": "start must not be after end"} | Intervalo invertido |
| 400 | {"error": "Invalid date, expected YYYY-MM-DD"} | date malformada |
| 400 | {"error": "use either date or start/end"} | date enviado junto com start ou end |
| 400 | {"error": "Invalid stock_id"} | Falha na verificação de formato |
| 400 | {"error": "kind must be one of ['disposal', 'notice']"} / {"error": "market must be one of ['twse', 'tpex']"} | Valor desconhecido |
| 400 | {"error": "start/end range is <n> days; max 366 (inclusive) without stock_id — split into smaller ranges"} | Intervalo acima de 366 dias sem stock_id |
| 503 | {"error": "Data temporarily unavailable. Please retry shortly."} | Uma tabela solicitada não pode ser servida (não atualizada há 48 h, ou ilegível) — tente novamente mais tarde, nunca leia isso como "sem anúncios". Apenas as tabelas de kind / market solicitadas são verificadas |
date é o dia do anúncio, start é o primeiro dia em vigor. Para perguntar "em disposição no dia D", use date=D (ou start=end=D), não a data do anúncio.start / end são o período anunciado; um feriado de mercado ou uma suspensão de negociação dentro dele estende o fim real, o que os dados não registram.match_minutes segue as regras vigentes no dia (TPEx 5 / 20 minutos → 2 a partir de 2026-08-10) — leia o valor linha a linha, nunca presuma um valor./studio/market/twstock/batch/<data_type> | Nome | Descrição | Valores permitidos | Padrão |
|---|---|---|---|
data_typestring · pathObrigatório | Conjunto de dados | price, price_adj, per, institutional, shareholding, foreign_shareholding, financials, balance_sheet, monthly_revenue, ratios, dividend | |
stock_idsstring · queryObrigatório | Códigos | Separados por vírgula, ≤ 50 | |
startstring · query | Primeira data | YYYY-MM-DD (validado estritamente apenas para dividend) | conforme o data_type |
endstring · query | Última data | YYYY-MM-DD | conforme o data_type |
payload = requests.get(f"{BASE_URL}/studio/market/twstock/batch/per" , headers=headers, params={"stock_ids": "2330,6182", "start": "2026-08-04", "end": "2026-08-08"}, timeout=120).json()# {"data_type": "per",# "data": {"2330": [{"date": "2026-08-04", "dividend_yield": 0.95, "PER": 31.19, "PBR": 10.21, "stock_id": "2330"}, ...],# "6182": [...]},# "failed": []}{"data_type", "data": {"<stock_id>": [...rows...]}, "failed": [...]}. As linhas são idênticas às do endpoint de ação única correspondente.
failed — ids cuja busca no servidor falhou (limite de requisições ou erro do upstream); tente esses novamente.data quanto de failed realmente não tem dados.| Status | Corpo | Quando |
|---|---|---|
| 400 | {"error": "Unsupported data_type '<x>'. Supported: [...]"} | data_type inválido |
| 400 | {"error": "stock_ids parameter required"} | Ausente |
| 400 | {"error": "stock_ids exceeds max 50 per request"} | Ids demais |
| 400 | {"error": "Invalid stock_id in list"} | Um código não passa na verificação de formato |
| 400 | {"error": "Invalid start date, expected YYYY-MM-DD"} | Apenas dividend |
ratios (財務比率): as linhas de cada id são as linhas largas por trimestre de /ratios/<stock_id> ("data": {"2330": [{"date": "2026-06-30", "stock_id": "2330", "roe_q": 11.3934, ...}], "2317": [...]}). Um código sem demonstrações financeiras (ETFs) fica ausente tanto de data quanto de failed (sem 404); um armazenamento de indicadores que não está pronto coloca todos os ids em failed (sem 503).dividend difere de /dividend/<stock_id>: lê apenas os dados armazenados (sem atualização), um id desconhecido ou uma ação sem histórico de dividendos fica ausente silenciosamente (sem 404), e um problema de cota do upstream aparece em failed, não como um 503.