Fix historical candle chart
This commit is contained in:
@@ -296,25 +296,39 @@ def _resolve_symbol(ticker: str, market_type: str) -> str:
|
||||
return ticker
|
||||
|
||||
|
||||
def _to_yahoo_ticker(ticker: str) -> str:
|
||||
"""Convert various ticker formats to Yahoo Finance format."""
|
||||
if ".JK" in ticker or ".JK" in ticker.upper():
|
||||
return ticker.replace(".jk", ".JK").replace(".Jk", ".JK")
|
||||
if ticker.startswith("IDX:"):
|
||||
return ticker.replace("IDX:", "") + ".JK"
|
||||
if ":" in ticker:
|
||||
return ticker.split(":", 1)[1]
|
||||
return ticker
|
||||
|
||||
|
||||
def _fetch_candles(
|
||||
ticker: str,
|
||||
resolution: str = "D",
|
||||
count: int = 30,
|
||||
) -> list[dict[str, Any]]:
|
||||
# Try TradingView chart API first
|
||||
sym = _resolve_symbol(ticker, "stocks")
|
||||
to_ts = int(time.time())
|
||||
resolution_seconds = {"1": 60, "5": 300, "15": 900, "30": 1800, "60": 3600,
|
||||
"240": 14400, "D": 86400, "W": 604800, "M": 2592000}
|
||||
from_ts = to_ts - (count * resolution_seconds.get(resolution, 86400))
|
||||
|
||||
url = "https://chart-data.tradingview.com/history"
|
||||
tv_urls = [
|
||||
"https://chart-data.tradingview.com/history",
|
||||
"https://scanner.tradingview.com/history",
|
||||
]
|
||||
for url in tv_urls:
|
||||
try:
|
||||
params = {"symbol": sym, "resolution": resolution, "from": from_ts, "to": to_ts}
|
||||
resp = requests.get(url, headers=TV_CHART_HEADERS, params=params, timeout=15)
|
||||
resp = requests.get(url, headers=TV_CHART_HEADERS, params=params, timeout=10)
|
||||
data = resp.json()
|
||||
|
||||
if data.get("s") != "ok":
|
||||
return []
|
||||
|
||||
if data.get("s") == "ok" and len(data.get("t", [])) > 0:
|
||||
candles = []
|
||||
for i in range(len(data["t"])):
|
||||
candles.append({
|
||||
@@ -326,6 +340,56 @@ def _fetch_candles(
|
||||
"volume": data["v"][i],
|
||||
})
|
||||
return candles
|
||||
except requests.RequestException:
|
||||
continue
|
||||
|
||||
# Fallback: Yahoo Finance API
|
||||
try:
|
||||
yahoo_sym = _to_yahoo_ticker(ticker)
|
||||
interval_map = {"1": "1m", "5": "5m", "15": "15m", "30": "30m",
|
||||
"60": "60m", "240": "4h", "D": "1d", "W": "1wk", "M": "1mo"}
|
||||
interval = interval_map.get(resolution, "1d")
|
||||
range_map = {30: "1mo", 60: "3mo", 120: "6mo", 250: "1y", 500: "2y"}
|
||||
y_range = "1mo"
|
||||
for cnt, r in sorted(range_map.items()):
|
||||
if count <= cnt:
|
||||
y_range = r
|
||||
break
|
||||
else:
|
||||
y_range = "5y"
|
||||
|
||||
url = f"https://query1.finance.yahoo.com/v8/finance/chart/{yahoo_sym}"
|
||||
params = {"interval": interval, "range": y_range}
|
||||
headers = {"User-Agent": TV_CHART_HEADERS["User-Agent"]}
|
||||
resp = requests.get(url, headers=headers, params=params, timeout=15)
|
||||
data = resp.json()
|
||||
|
||||
result = data.get("chart", {}).get("result", [None])[0]
|
||||
if not result:
|
||||
result = data.get("chart", {}).get("result", [None])[0]
|
||||
if result:
|
||||
timestamps = result.get("timestamp", [])
|
||||
quotes = result.get("indicators", {}).get("quote", [None])[0]
|
||||
if timestamps and quotes:
|
||||
opens = quotes.get("open", [])
|
||||
highs = quotes.get("high", [])
|
||||
lows = quotes.get("low", [])
|
||||
closes = quotes.get("close", [])
|
||||
volumes = quotes.get("volume", [])
|
||||
candles = []
|
||||
for i in range(len(timestamps)):
|
||||
o, h, l, c, v = opens[i], highs[i], lows[i], closes[i], volumes[i]
|
||||
if None in (o, h, l, c, v):
|
||||
continue
|
||||
candles.append({
|
||||
"time": timestamps[i],
|
||||
"open": o, "high": h, "low": l, "close": c, "volume": v,
|
||||
})
|
||||
return candles[-count:]
|
||||
except requests.RequestException:
|
||||
pass
|
||||
|
||||
return []
|
||||
|
||||
|
||||
def _detect_candle_patterns(candles: list[dict[str, Any]]) -> list[str]:
|
||||
|
||||
Reference in New Issue
Block a user