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:
91
scripts/yahoo-macd-signal.py
Normal file
91
scripts/yahoo-macd-signal.py
Normal file
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sys
|
||||
import urllib.parse
|
||||
import urllib.request
|
||||
|
||||
|
||||
def fetch_closes(symbol: str, range_: str = "6mo", interval: str = "1d") -> list[float]:
|
||||
base = f"https://query1.finance.yahoo.com/v8/finance/chart/{symbol}"
|
||||
params = {"range": range_, "interval": interval}
|
||||
url = f"{base}?{urllib.parse.urlencode(params)}"
|
||||
|
||||
req = urllib.request.Request(url, headers={"User-Agent": "Mozilla/5.0"})
|
||||
with urllib.request.urlopen(req, timeout=30) as resp:
|
||||
data = json.loads(resp.read().decode("utf-8", errors="replace"))
|
||||
|
||||
result = data.get("chart", {}).get("result", [])
|
||||
if not result:
|
||||
return []
|
||||
|
||||
quote = result[0].get("indicators", {}).get("quote", [])
|
||||
if not quote:
|
||||
return []
|
||||
|
||||
closes = quote[0].get("close", [])
|
||||
return [float(x) for x in closes if x is not None]
|
||||
|
||||
|
||||
def ema(values: list[float], period: int) -> list[float]:
|
||||
if not values:
|
||||
return []
|
||||
k = 2 / (period + 1)
|
||||
out = [values[0]]
|
||||
for v in values[1:]:
|
||||
out.append(v * k + out[-1] * (1 - k))
|
||||
return out
|
||||
|
||||
|
||||
def macd(closes: list[float]) -> tuple[list[float], list[float], list[float]]:
|
||||
ema12 = ema(closes, 12)
|
||||
ema26 = ema(closes, 26)
|
||||
dif = [a - b for a, b in zip(ema12, ema26)]
|
||||
dea = ema(dif, 9)
|
||||
hist = [d - s for d, s in zip(dif, dea)]
|
||||
return dif, dea, hist
|
||||
|
||||
|
||||
def main() -> None:
|
||||
symbol = sys.argv[1] if len(sys.argv) > 1 else "00922.TW"
|
||||
closes = fetch_closes(symbol)
|
||||
|
||||
if len(closes) < 35:
|
||||
print(f"{symbol} 資料不足,無法判斷 MACD(至少 35 筆,當前 {len(closes)})")
|
||||
return
|
||||
|
||||
dif, dea, hist = macd(closes)
|
||||
|
||||
d0, d1 = dif[-1], dif[-2]
|
||||
s0, s1 = dea[-1], dea[-2]
|
||||
h0, h1 = hist[-1], hist[-2]
|
||||
|
||||
golden_cross = d1 <= s1 and d0 > s0
|
||||
death_cross = d1 >= s1 and d0 < s0
|
||||
low_zone = d0 < 0 and s0 < 0
|
||||
|
||||
if golden_cross and low_zone:
|
||||
signal = "✅ 低位金叉:偏多訊號"
|
||||
elif golden_cross:
|
||||
signal = "✅ 金叉:短線轉強"
|
||||
elif death_cross:
|
||||
signal = "⚠️ 死叉:短線轉弱"
|
||||
elif h0 > h1 and h0 > 0:
|
||||
signal = "📈 多頭延續(柱體擴大)"
|
||||
elif h0 < h1 and h0 < 0:
|
||||
signal = "📉 空頭延續(柱體擴大)"
|
||||
else:
|
||||
signal = "👀 MACD 震盪中,先觀察"
|
||||
|
||||
print(f"{symbol} MACD 摘要")
|
||||
print(f"- DIF:{d0:.4f}")
|
||||
print(f"- DEA:{s0:.4f}")
|
||||
print(f"- HIST:{h0:.4f}")
|
||||
print(f"- 訊號:{signal}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user