CoolFace
Apppublic

thinkingEverytime/QuantOracle

sourceHugging Faceupdated 6mo agoView on Hugging Face
1likes
groww_api.py90 linesDownload Raw Back to scripts
1#!/usr/bin/env python32"""Tiny Groww Trade API helpers (token + historical candles).3 4This is intentionally small and only supports what QuantOracle needs:5  - exchange: NSE6  - segment: CASH7  - candles: daily (interval_in_minutes=1440)8 9Docs reference: https://groww.in/trade-api/docs10"""11 12from __future__ import annotations13 14import hashlib15import time16from dataclasses import dataclass17from typing import Any18 19import requests20 21_TOKEN_URL = "https://api.groww.in/v1/token/api/access"22_CANDLE_RANGE_URL = "https://api.groww.in/v1/historical/candle/range"23 24 25@dataclass(frozen=True)26class GrowwAuth:27    api_key: str28    api_secret: str29 30 31def get_access_token(auth: GrowwAuth, *, key_type: str = "approval", timeout: int = 30) -> str:32    ts = str(int(time.time()))33    checksum = hashlib.sha256((auth.api_secret + ts).encode("utf-8")).hexdigest()34    r = requests.post(35        _TOKEN_URL,36        headers={"Authorization": f"Bearer {auth.api_key}"},37        json={"key_type": key_type, "checksum": checksum, "timestamp": ts},38        timeout=timeout,39    )40    if r.status_code != 200:41        raise RuntimeError(f"Groww token HTTP {r.status_code}: {(r.text or '')[:200]}")42    data = r.json() or {}43    token = data.get("token")44    if not token:45        raise RuntimeError(f"Groww token response missing 'token': {str(data)[:200]}")46    return str(token)47 48 49def get_candles_range(50    access_token: str,51    *,52    trading_symbol: str,53    start_time: str,54    end_time: str,55    interval_in_minutes: int = 1440,56    exchange: str = "NSE",57    segment: str = "CASH",58    timeout: int = 30,59) -> list[list[Any]]:60    r = requests.get(61        _CANDLE_RANGE_URL,62        headers={63            "Authorization": f"Bearer {access_token}",64            "Accept": "application/json",65            "X-API-VERSION": "1.0",66        },67        params={68            "exchange": exchange,69            "segment": segment,70            "trading_symbol": trading_symbol,71            "start_time": start_time,72            "end_time": end_time,73            "interval_in_minutes": int(interval_in_minutes),74        },75        timeout=timeout,76    )77    if r.status_code != 200:78        raise RuntimeError(f"Groww candles HTTP {r.status_code}: {(r.text or '')[:200]}")79    data = r.json() or {}80    # The API returns a top-level payload in some responses; be tolerant.81    payload = data.get("payload") if isinstance(data, dict) else None82    if isinstance(payload, dict) and "candles" in payload:83        candles = payload.get("candles") or []84    else:85        candles = data.get("candles") or []86    if not isinstance(candles, list):87        raise RuntimeError(f"Groww candles unexpected shape: {str(data)[:200]}")88    return candles89 90