Fix historical candle chart
This commit is contained in:
@@ -296,25 +296,39 @@ def _resolve_symbol(ticker: str, market_type: str) -> str:
|
|||||||
return ticker
|
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(
|
def _fetch_candles(
|
||||||
ticker: str,
|
ticker: str,
|
||||||
resolution: str = "D",
|
resolution: str = "D",
|
||||||
count: int = 30,
|
count: int = 30,
|
||||||
) -> list[dict[str, Any]]:
|
) -> list[dict[str, Any]]:
|
||||||
|
# Try TradingView chart API first
|
||||||
sym = _resolve_symbol(ticker, "stocks")
|
sym = _resolve_symbol(ticker, "stocks")
|
||||||
to_ts = int(time.time())
|
to_ts = int(time.time())
|
||||||
resolution_seconds = {"1": 60, "5": 300, "15": 900, "30": 1800, "60": 3600,
|
resolution_seconds = {"1": 60, "5": 300, "15": 900, "30": 1800, "60": 3600,
|
||||||
"240": 14400, "D": 86400, "W": 604800, "M": 2592000}
|
"240": 14400, "D": 86400, "W": 604800, "M": 2592000}
|
||||||
from_ts = to_ts - (count * resolution_seconds.get(resolution, 86400))
|
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}
|
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()
|
data = resp.json()
|
||||||
|
if data.get("s") == "ok" and len(data.get("t", [])) > 0:
|
||||||
if data.get("s") != "ok":
|
|
||||||
return []
|
|
||||||
|
|
||||||
candles = []
|
candles = []
|
||||||
for i in range(len(data["t"])):
|
for i in range(len(data["t"])):
|
||||||
candles.append({
|
candles.append({
|
||||||
@@ -326,6 +340,56 @@ def _fetch_candles(
|
|||||||
"volume": data["v"][i],
|
"volume": data["v"][i],
|
||||||
})
|
})
|
||||||
return candles
|
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]:
|
def _detect_candle_patterns(candles: list[dict[str, Any]]) -> list[str]:
|
||||||
|
|||||||
Reference in New Issue
Block a user