Spaces:
Sleeping
Sleeping
File size: 4,277 Bytes
69f5fb0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | import os
import time
import requests
import pandas as pd
from datetime import datetime, date, timedelta
from zoneinfo import ZoneInfo
import pandas_market_calendars as mcal
IST = ZoneInfo("Asia/Kolkata")
DATA_FILE = os.path.join(os.path.dirname(__file__), "data", "nifty50_daily.parquet")
TICKERS = [
'ADANIENT', 'ADANIPORTS', 'APOLLOHOSP', 'ASIANPAINT', 'AXISBANK', 'BAJAJ-AUTO', 'BAJAJFINSV', 'BAJFINANCE',
'BHARTIARTL', 'BPCL', 'BRITANNIA', 'CIPLA', 'COALINDIA', 'DIVISLAB', 'DRREDDY', 'EICHERMOT', 'GRASIM',
'HCLTECH', 'HDFCBANK', 'HDFCLIFE', 'HEROMOTOCO', 'HINDALCO', 'HINDUNILVR', 'ICICIBANK', 'INDUSINDBK',
'INFY', 'ITC', 'JSWSTEEL', 'KOTAKBANK', 'LT', 'M&M', 'MARUTI', 'NESTLEIND', 'NTPC', 'ONGC', 'POWERGRID',
'RELIANCE', 'SBILIFE', 'SBIN', 'SUNPHARMA', 'TATACONSUM', 'TATAMOTORS', 'TATASTEEL', 'TCS', 'TECHM',
'TITAN', 'ULTRACEMCO', 'UPL', 'WIPRO'
]
def is_trading_day(target_date: date) -> bool:
try:
nse = mcal.get_calendar('NSE')
schedule = nse.schedule(start_date=target_date, end_date=target_date)
return not schedule.empty
except Exception as e:
print(f"Calendar check failed: {e}")
# Fallback: assume Monday-Friday is trading day
return target_date.weekday() < 5
def fetch_groww_data(ticker: str, start_ts: int, end_ts: int):
url = f"https://groww.in/v1/api/charting_service/v2/chart/exchange/NSE/segment/CASH/{ticker}?endTimeInMillis={end_ts}&intervalInMinutes=1&startTimeInMillis={start_ts}"
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64)",
"Accept": "application/json"
}
try:
response = requests.get(url, headers=headers, timeout=10)
if response.status_code == 200:
data = response.json()
if data and 'candles' in data and len(data['candles']) > 0:
# Candles format: [timestamp, open, high, low, close, volume]
last_candle = data['candles'][-1]
return last_candle[4] # Close price
return None
except Exception as e:
print(f"Error fetching {ticker}: {e}")
return None
def update_daily_data():
now = datetime.now(IST)
today = now.date()
if not is_trading_day(today):
print(f"{today} is not a trading day. Skipping update.")
return {"status": "skipped", "reason": "not a trading day"}
if not os.path.exists(DATA_FILE):
print(f"Data file {DATA_FILE} not found!")
return {"status": "error", "reason": "data file missing"}
# Read existing data
df = pd.read_parquet(DATA_FILE)
# Check if we already updated today
if not df.empty and pd.to_datetime(today) in df['date'].dt.date.values:
# We might have partial data or want to overwrite, but for safety:
# Let's delete today's entries if they exist so we can cleanly append
df = df[df['date'].dt.date != today]
print(f"Fetching data for {today}...")
# Market hours: 09:15 to 15:30 IST
start_dt = datetime.combine(today, datetime.strptime("09:15", "%H:%M").time()).replace(tzinfo=IST)
end_dt = datetime.combine(today, datetime.strptime("15:30", "%H:%M").time()).replace(tzinfo=IST)
start_ts = int(start_dt.timestamp() * 1000)
end_ts = int(end_dt.timestamp() * 1000)
new_rows = []
for ticker in TICKERS:
close_price = fetch_groww_data(ticker, start_ts, end_ts)
if close_price is not None:
new_rows.append({
'date': pd.to_datetime(today),
'close': float(close_price),
'ticker': ticker
})
time.sleep(0.5) # Rate limiting
if new_rows:
new_df = pd.DataFrame(new_rows)
updated_df = pd.concat([df, new_df], ignore_index=True)
updated_df.sort_values(by=['ticker', 'date'], inplace=True)
updated_df.to_parquet(DATA_FILE)
print(f"Successfully updated {len(new_rows)} tickers for {today}")
return {"status": "success", "updated_count": len(new_rows)}
else:
print("No new data fetched.")
return {"status": "error", "reason": "fetch failed for all tickers"}
if __name__ == "__main__":
update_daily_data()
|