Added DateTime to WebService
This commit is contained in:
parent
79029bdcd9
commit
a442b2caca
1 changed files with 88 additions and 12 deletions
|
|
@ -29,7 +29,7 @@ def get_db():
|
|||
""")
|
||||
return conn
|
||||
|
||||
_current_cache = {} # ticker -> (price, resolved_date, fetched_at)
|
||||
_current_cache = {} # ticker -> (price, resolved_date, date, time, fetched_at)
|
||||
_current_cache_lock = threading.Lock()
|
||||
|
||||
|
||||
|
|
@ -45,24 +45,45 @@ def fetch_yahoo_price(ticker, target_date):
|
|||
|
||||
url = f"https://query1.finance.yahoo.com/v8/finance/chart/{ticker}"
|
||||
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}
|
||||
r = requests.get(url, params={"period1": period1, "period2": period2, "interval": "1d"}, headers=headers, timeout=10)
|
||||
r = requests.get(
|
||||
url,
|
||||
params={"period1": period1, "period2": period2, "interval": "1d"},
|
||||
headers=headers,
|
||||
timeout=10
|
||||
)
|
||||
|
||||
if r.status_code != 200:
|
||||
return None, f"yahoo http {r.status_code}"
|
||||
|
||||
data = r.json()
|
||||
|
||||
try:
|
||||
result = data["chart"]["result"][0]
|
||||
timestamps = result["timestamp"]
|
||||
closes = result["indicators"]["quote"][0]["close"]
|
||||
meta = result.get("meta", {})
|
||||
except (KeyError, IndexError, TypeError):
|
||||
return None, "no historical data"
|
||||
|
||||
# Yahoo's timestamp for the latest regular-market update
|
||||
market_timestamp = meta.get("regularMarketTime")
|
||||
|
||||
if market_timestamp:
|
||||
market_datetime = datetime.utcfromtimestamp(market_timestamp)
|
||||
market_date = market_datetime.strftime("%Y-%m-%d")
|
||||
market_time = market_datetime.strftime("%H:%M:%S")
|
||||
else:
|
||||
market_date = None
|
||||
market_time = None
|
||||
|
||||
best = None
|
||||
|
||||
for ts, close in zip(timestamps, closes):
|
||||
if close is None:
|
||||
continue
|
||||
|
||||
day = datetime.utcfromtimestamp(ts)
|
||||
|
||||
if day.date() <= target_date.date():
|
||||
if best is None or day > best[0]:
|
||||
best = (day, close)
|
||||
|
|
@ -70,7 +91,12 @@ def fetch_yahoo_price(ticker, target_date):
|
|||
if best is None:
|
||||
return None, "no trading day found in window"
|
||||
|
||||
return {"resolved_date": best[0].strftime("%Y-%m-%d"), "price": round(best[1], 4)}, None
|
||||
return {
|
||||
"resolved_date": best[0].strftime("%Y-%m-%d"),
|
||||
"price": round(best[1], 4),
|
||||
"date": market_date,
|
||||
"time": market_time
|
||||
}, None
|
||||
|
||||
|
||||
@app.route("/current")
|
||||
|
|
@ -79,23 +105,47 @@ def current_price():
|
|||
return jsonify({"error": "unauthorized"}), 401
|
||||
|
||||
ticker = request.args.get("ticker", "").upper().strip()
|
||||
|
||||
if not ticker:
|
||||
return jsonify({"error": "missing ticker"}), 400
|
||||
|
||||
now = time.time()
|
||||
|
||||
with _current_cache_lock:
|
||||
cached = _current_cache.get(ticker)
|
||||
if cached and (now - cached[2]) < CURRENT_TTL_SECONDS:
|
||||
return jsonify({"ticker": ticker, "price": cached[0], "resolved_date": cached[1], "cached": True})
|
||||
|
||||
if cached and (now - cached[4]) < CURRENT_TTL_SECONDS:
|
||||
return jsonify({
|
||||
"ticker": ticker,
|
||||
"price": cached[0],
|
||||
"resolved_date": cached[1],
|
||||
"cached": True,
|
||||
"date": cached[2],
|
||||
"time": cached[3]
|
||||
})
|
||||
|
||||
result, err = fetch_yahoo_price(ticker, datetime.utcnow())
|
||||
|
||||
if err:
|
||||
return jsonify({"ticker": ticker, "error": err}), 502
|
||||
|
||||
with _current_cache_lock:
|
||||
_current_cache[ticker] = (result["price"], result["resolved_date"], now)
|
||||
_current_cache[ticker] = (
|
||||
result["price"],
|
||||
result["resolved_date"],
|
||||
result["date"],
|
||||
result["time"],
|
||||
now
|
||||
)
|
||||
|
||||
return jsonify({"ticker": ticker, "price": result["price"], "resolved_date": result["resolved_date"], "cached": False})
|
||||
return jsonify({
|
||||
"ticker": ticker,
|
||||
"price": result["price"],
|
||||
"resolved_date": result["resolved_date"],
|
||||
"cached": False,
|
||||
"date": result["date"],
|
||||
"time": result["time"]
|
||||
})
|
||||
|
||||
|
||||
@app.route("/historical")
|
||||
|
|
@ -105,6 +155,7 @@ def historical_price():
|
|||
|
||||
ticker = request.args.get("ticker", "").upper().strip()
|
||||
date_str = request.args.get("date", "").strip()
|
||||
|
||||
if not ticker or not date_str:
|
||||
return jsonify({"error": "missing ticker or date"}), 400
|
||||
|
||||
|
|
@ -113,35 +164,60 @@ def historical_price():
|
|||
except ValueError:
|
||||
return jsonify({"error": "date must be YYYY-MM-DD"}), 400
|
||||
|
||||
# If someone asks "historical" for today/future, treat it like /current instead
|
||||
# If someone asks "historical" for today/future,
|
||||
# treat it like /current instead
|
||||
if target_date.date() >= datetime.utcnow().date():
|
||||
return current_price()
|
||||
|
||||
with _db_lock:
|
||||
conn = get_db()
|
||||
|
||||
row = conn.execute(
|
||||
"SELECT resolved_date, price FROM historical_cache WHERE ticker=? AND requested_date=?",
|
||||
(ticker, date_str),
|
||||
).fetchone()
|
||||
|
||||
conn.close()
|
||||
|
||||
if row:
|
||||
return jsonify({"ticker": ticker, "requested_date": date_str, "resolved_date": row[0], "price": row[1], "cached": True})
|
||||
return jsonify({
|
||||
"ticker": ticker,
|
||||
"requested_date": date_str,
|
||||
"resolved_date": row[0],
|
||||
"price": row[1],
|
||||
"cached": True
|
||||
})
|
||||
|
||||
result, err = fetch_yahoo_price(ticker, target_date)
|
||||
|
||||
if err:
|
||||
return jsonify({"ticker": ticker, "error": err}), 502
|
||||
|
||||
with _db_lock:
|
||||
conn = get_db()
|
||||
|
||||
conn.execute(
|
||||
"INSERT OR REPLACE INTO historical_cache (ticker, requested_date, resolved_date, price) VALUES (?, ?, ?, ?)",
|
||||
(ticker, date_str, result["resolved_date"], result["price"]),
|
||||
"INSERT OR REPLACE INTO historical_cache "
|
||||
"(ticker, requested_date, resolved_date, price) "
|
||||
"VALUES (?, ?, ?, ?)",
|
||||
(
|
||||
ticker,
|
||||
date_str,
|
||||
result["resolved_date"],
|
||||
result["price"]
|
||||
),
|
||||
)
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
return jsonify({"ticker": ticker, "requested_date": date_str, "resolved_date": result["resolved_date"], "price": result["price"], "cached": False})
|
||||
return jsonify({
|
||||
"ticker": ticker,
|
||||
"requested_date": date_str,
|
||||
"resolved_date": result["resolved_date"],
|
||||
"price": result["price"],
|
||||
"cached": False
|
||||
})
|
||||
|
||||
|
||||
@app.route("/health")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue