restore and rebuild all stock query scripts
Recover 7 existing scripts from remote repo and rebuild 5 missing ones: - twse-margin-trading.py (融資融券) - twse-day-trading.py (當沖交易) - twse-foreign-holdings.py (外資持股) - yahoo-dividend-browserless.py (股利資訊) - yahoo-broker-trading-browserless.py (主力券商進出) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
120
scripts/twse-margin-trading.py
Normal file
120
scripts/twse-margin-trading.py
Normal file
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
查詢 TWSE 個股融資融券餘額(信用交易統計)
|
||||
|
||||
用法:
|
||||
python3 skills/stocks-query/scripts/twse-margin-trading.py 2330
|
||||
python3 skills/stocks-query/scripts/twse-margin-trading.py 3481
|
||||
|
||||
資料來源:證交所 TWSE 公開 API
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sys
|
||||
import urllib.request
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
|
||||
def fetch_margin(stock_no: str, date_str: str | None = None) -> dict:
|
||||
"""從 TWSE 抓融資融券資料,自動往前回溯最多 10 天找到有資料的日期。"""
|
||||
if date_str:
|
||||
dates_to_try = [date_str]
|
||||
else:
|
||||
today = datetime.now()
|
||||
dates_to_try = [(today - timedelta(days=i)).strftime("%Y%m%d") for i in range(10)]
|
||||
|
||||
for d in dates_to_try:
|
||||
url = (
|
||||
f"https://www.twse.com.tw/rwd/zh/marginTrading/MI_MARGN"
|
||||
f"?date={d}&selectType=ALL&response=json"
|
||||
)
|
||||
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=30) as resp:
|
||||
data = json.loads(resp.read().decode("utf-8", errors="replace"))
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
if data.get("stat") != "OK":
|
||||
continue
|
||||
|
||||
tables = data.get("tables", [])
|
||||
if not tables:
|
||||
continue
|
||||
|
||||
# 找到個股那張表(title 含「融資融券」或欄位含「股票代號」)
|
||||
target_table = None
|
||||
for tbl in tables:
|
||||
fields = tbl.get("fields", [])
|
||||
if "股票代號" in fields:
|
||||
target_table = tbl
|
||||
break
|
||||
|
||||
if not target_table:
|
||||
continue
|
||||
|
||||
fields = target_table["fields"]
|
||||
for row in target_table.get("data", []):
|
||||
code = row[fields.index("股票代號")].strip()
|
||||
if code == stock_no:
|
||||
result = {"date": d}
|
||||
for i, field in enumerate(fields):
|
||||
result[field.strip()] = row[i].strip().replace(",", "")
|
||||
return result
|
||||
|
||||
raise RuntimeError(f"找不到 {stock_no} 的融資融券資料(已回溯 10 天)")
|
||||
|
||||
|
||||
def print_summary(stock_no: str, d: dict) -> None:
|
||||
date_fmt = f"{d['date'][:4]}/{d['date'][4:6]}/{d['date'][6:]}"
|
||||
name = d.get("股票名稱", stock_no)
|
||||
print(f"{name}({stock_no})|融資融券摘要")
|
||||
print(f"• 日期:{date_fmt}")
|
||||
|
||||
# 融資
|
||||
margin_buy = d.get("融資買進", "-")
|
||||
margin_sell = d.get("融資賣出", "-")
|
||||
margin_cash = d.get("融資現償", "-")
|
||||
margin_balance = d.get("融資餘額", d.get("融資今日餘額", "-"))
|
||||
margin_limit = d.get("融資限額", "-")
|
||||
print(f"• 融資買進:{margin_buy}")
|
||||
print(f"• 融資賣出:{margin_sell}")
|
||||
print(f"• 融資現償:{margin_cash}")
|
||||
print(f"• 融資餘額:{margin_balance}")
|
||||
if margin_limit != "-":
|
||||
print(f"• 融資限額:{margin_limit}")
|
||||
|
||||
# 融券
|
||||
short_sell = d.get("融券賣出", "-")
|
||||
short_buy = d.get("融券買進", "-")
|
||||
short_cash = d.get("融券現償", "-")
|
||||
short_balance = d.get("融券餘額", d.get("融券今日餘額", "-"))
|
||||
short_limit = d.get("融券限額", "-")
|
||||
print(f"• 融券賣出:{short_sell}")
|
||||
print(f"• 融券買進:{short_buy}")
|
||||
print(f"• 融券現償:{short_cash}")
|
||||
print(f"• 融券餘額:{short_balance}")
|
||||
if short_limit != "-":
|
||||
print(f"• 融券限額:{short_limit}")
|
||||
|
||||
# 券資比
|
||||
try:
|
||||
mb = float(margin_balance) if margin_balance != "-" else 0
|
||||
sb = float(short_balance) if short_balance != "-" else 0
|
||||
if mb > 0:
|
||||
ratio = (sb / mb) * 100
|
||||
print(f"• 券資比:{ratio:.2f}%")
|
||||
except (ValueError, ZeroDivisionError):
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
stock_no = sys.argv[1] if len(sys.argv) > 1 else "2330"
|
||||
try:
|
||||
data = fetch_margin(stock_no)
|
||||
print_summary(stock_no, data)
|
||||
except Exception as e:
|
||||
print(f"取得失敗:{e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
Reference in New Issue
Block a user