============================================================

Complete R script: TWSE ISIN + FinMind (clean version)

============================================================

—- 0. Packages —-

Run once if not installed:

install.packages(c(“rvest”,“httr”,“dplyr”,“stringr”,“jsonlite”))

library(rvest) library(httr) library(dplyr) library(stringr) library(jsonlite)

============================================================

PART 1: TWSE ISIN (strMode=2 = listed common stocks)

============================================================

twse_url <- “https://isin.twse.com.tw/isin/C_public.jsp?strMode=2” twse_page <- read_html(content(GET(twse_url), “text”, encoding = “Big5”))

twse_raw <- twse_page %>% html_table(fill = TRUE) %>% .[[1]]

— DIAGNOSTIC: run these 3 lines first and look at the output —

cat(“Rows:”, nrow(twse_raw), ” Cols:“, ncol(twse_raw),”“) print(colnames(twse_raw)) print(head(twse_raw, 3)) # ——————————————————————

Assign column names by position

if (ncol(twse_raw) == 6) { colnames(twse_raw) <- c(“stock_id_name”,“isin_code”,“listing_date”, “market”,“industry”,“cfi_code”) } else if (ncol(twse_raw) == 7) { colnames(twse_raw) <- c(“stock_id_name”,“isin_code”,“listing_date”, “market”,“industry”,“cfi_code”,“note”) } else { colnames(twse_raw) <- paste0(“V”, seq_len(ncol(twse_raw))) colnames(twse_raw)[1] <- “stock_id_name” colnames(twse_raw)[3] <- “listing_date” }

twse_clean <- twse_raw %>% mutate(across(everything(), as.character)) %>% filter( !is.na(stock_id_name), stock_id_name != ““, !str_detect(stock_id_name,”有價證券代號|股票代號|代號及名稱”) ) %>% mutate( stock_id = str_extract(stock_id_name, “1+”), stock_name = str_trim(str_remove(stock_id_name, “2+”)), listing_date = as.Date(listing_date, format = “%Y/%m/%d”) ) %>% filter( !is.na(stock_id), !str_detect(stock_id, “^00”), !str_detect(stock_id, “[A-Za-z]$”), !str_detect(stock_name, “ETF|基金|特別股|受益憑證|指數股票型|購|售|權證”) ) %>% select(stock_id, stock_name, listing_date, industry) %>% distinct(stock_id, .keep_all = TRUE)

cat(“TWSE listed common stocks count:”, nrow(twse_clean), “”) print(head(twse_clean, 10))

============================================================

PART 2: FinMind API

============================================================

finmind_url <- “https://api.finmindtrade.com/api/v4/data” finmind_resp <- GET(finmind_url, query = list(dataset = “TaiwanStockInfo”)) finmind_raw <- fromJSON(content(finmind_resp, “text”, encoding = “UTF-8”))$data

finmind_clean <- finmind_raw %>% filter(type == “stock”) %>% group_by(stock_id) %>% slice_max(date, n = 1, with_ties = FALSE) %>% ungroup() %>% transmute( stock_id = stock_id, stock_name = stock_name, listing_date = as.Date(date), industry = industry_category ) %>% filter(!str_detect(stock_name, “ETF|基金|特別股|受益憑證”)) %>% distinct(stock_id, .keep_all = TRUE)

cat(“FinMind listed common stocks count:”, nrow(finmind_clean), “”) print(head(finmind_clean, 10))

============================================================

PART 3: Compare

============================================================

twse_ids <- twse_clean\(stock_id finmind_ids <- finmind_clean\)stock_id

cat(“Only in TWSE :”, length(setdiff(twse_ids, finmind_ids)), “”) cat(“Only in FinMind:”, length(setdiff(finmind_ids, twse_ids)), “”) cat(“Common stocks :”, length(intersect(twse_ids, finmind_ids)), “”)

merged <- twse_clean %>% select(stock_id, stock_name, listing_date) %>% left_join(finmind_clean %>% select(stock_id, industry), by = “stock_id”)

print(head(merged, 10))

============================================================

PART 4 (optional): Save to CSV

============================================================

write.csv(twse_clean, “twse_stocks.csv”, row.names = FALSE, fileEncoding = “UTF-8”) write.csv(finmind_clean, “finmind_stocks.csv”, row.names = FALSE, fileEncoding = “UTF-8”) write.csv(merged, “merged_stocks.csv”, row.names = FALSE, fileEncoding = “UTF-8”)


  1. 0-9A-Za-z↩︎

  2. 0-9A-Za-z↩︎