53 lines
1.4 KiB
Python
53 lines
1.4 KiB
Python
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
|
|
import pandas as pd
|
|
import streamlit as st
|
|
import yfinance as yf
|
|
|
|
|
|
@st.cache_data(ttl=60, show_spinner=False)
|
|
def fetch_ohlc(symbol: str, interval: str, period: str) -> pd.DataFrame:
|
|
ticker = yf.Ticker(symbol)
|
|
df = ticker.history(period=period, interval=interval, auto_adjust=False, actions=False)
|
|
if df.empty:
|
|
raise ValueError("No data returned. Check symbol/interval/period compatibility.")
|
|
|
|
df = df.rename(columns=str.title)
|
|
required = ["Open", "High", "Low", "Close", "Volume"]
|
|
missing = [c for c in required if c not in df.columns]
|
|
if missing:
|
|
raise ValueError(f"Missing required columns: {missing}")
|
|
|
|
return df[required].dropna().copy()
|
|
|
|
|
|
def maybe_drop_live_bar(df: pd.DataFrame, interval: str, enabled: bool) -> pd.DataFrame:
|
|
if not enabled or len(df) < 2:
|
|
return df
|
|
|
|
last_ts = df.index[-1]
|
|
if last_ts.tzinfo is None:
|
|
now = datetime.utcnow()
|
|
else:
|
|
now = datetime.now(tz=last_ts.tzinfo)
|
|
|
|
delta = now - last_ts.to_pydatetime()
|
|
|
|
intraday_intervals = {
|
|
"1m": 1,
|
|
"2m": 2,
|
|
"5m": 5,
|
|
"15m": 15,
|
|
"30m": 30,
|
|
"60m": 60,
|
|
"90m": 90,
|
|
"1h": 60,
|
|
}
|
|
minutes = intraday_intervals.get(interval)
|
|
if minutes is not None and delta.total_seconds() < minutes * 60:
|
|
return df.iloc[:-1].copy()
|
|
|
|
return df
|