-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.py
More file actions
166 lines (134 loc) · 6.66 KB
/
Copy pathutils.py
File metadata and controls
166 lines (134 loc) · 6.66 KB
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
#!/usr/bin/env python3
"""
utils.py
Utility functions for Upstox API integration
"""
import os
import time
import threading
import pandas as pd
import requests
import logging
logger = logging.getLogger(__name__)
# Global rate limiter for Upstox API
_upstox_last_request = 0.0
_upstox_lock = threading.Lock()
def fetch_from_upstox(symbol, start_date, end_date):
"""Fetch historical data from Upstox API with rate limiting"""
try:
# Load IPO mappings from MongoDB
try:
from db import get_instrument_key_mapping
symbol_mapping = get_instrument_key_mapping()
except Exception as e:
logger.error(f"Error getting Upstox mapping from DB: {e}")
return None
if not symbol_mapping or symbol not in symbol_mapping:
logger.warning(f"Symbol {symbol} not found in Upstox mapping (MongoDB)")
return None
instrument_key = symbol_mapping[symbol]
# Get Upstox credentials
access_token = os.getenv('UPSTOX_ACCESS_TOKEN')
if not access_token:
logger.warning("Upstox access token not found")
return None
# Prepare API request
headers = {
'Accept': 'application/json',
'Api-Version': '2.0',
'Authorization': f'Bearer {access_token}'
}
from_str = start_date.strftime('%Y-%m-%d')
to_str = end_date.strftime('%Y-%m-%d')
url = f"https://api.upstox.com/v2/historical-candle/{instrument_key}/day/{to_str}/{from_str}"
# Global rate limiting: Ensure minimum 100ms between Upstox API requests
global _upstox_last_request
with _upstox_lock:
current_time = time.time()
time_since_last = current_time - _upstox_last_request
if time_since_last < 0.1: # 100ms minimum delay
time.sleep(0.1 - time_since_last)
_upstox_last_request = time.time()
logger.info(f"🔄 Trying Upstox API for {symbol}")
response = requests.get(url, headers=headers)
# Handle rate limiting (429 Too Many Requests)
if response.status_code == 429:
logger.warning(f"⚠️ Rate limited for {symbol}, waiting 1 second...")
time.sleep(1)
response = requests.get(url, headers=headers)
if response.status_code == 200:
data = response.json()
if 'data' in data and 'candles' in data['data']:
candles = data['data']['candles']
if candles:
# Convert to DataFrame
df = pd.DataFrame(candles, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume', 'close'])
# Handle timestamp conversion - try different formats
try:
# Try Unix timestamp first
df['DATE'] = pd.to_datetime(df['timestamp'], unit='s')
except:
try:
# Try ISO format
df['DATE'] = pd.to_datetime(df['timestamp'])
except:
# Try string format
df['DATE'] = pd.to_datetime(df['timestamp'], format='%Y-%m-%d')
df.columns = ['timestamp', 'OPEN', 'HIGH', 'LOW', 'CLOSE', 'VOLUME', 'IGNORE', 'DATE']
# Select required columns and add LTP column (use CLOSE as LTP)
df = df[['DATE', 'OPEN', 'HIGH', 'LOW', 'CLOSE', 'VOLUME']]
df['LTP'] = df['CLOSE'] # Add LTP column using CLOSE price
# Ensure DATE is datetime (should already be, but verify for consistency)
if not pd.api.types.is_datetime64_any_dtype(df['DATE']):
df['DATE'] = pd.to_datetime(df['DATE'])
# Sort by date ascending (oldest to newest) to ensure consistent ordering
df = df.sort_values('DATE').reset_index(drop=True)
logger.info(f"✅ Upstox API: Got {len(df)} candles for {symbol}")
return df
logger.warning(f"⚠️ Upstox API: No data for {symbol}")
return None
except Exception as e:
logger.warning(f"⚠️ Upstox API error for {symbol}: {e}")
return None
def fetch_nifty_from_upstox(start_date, end_date):
"""Fetch Nifty 50 index data from Upstox API."""
import requests
access_token = os.getenv('UPSTOX_ACCESS_TOKEN')
if not access_token:
logger.warning("Upstox access token not found for Nifty fetching")
return None
headers = {
'Accept': 'application/json',
'Api-Version': '2.0',
'Authorization': f'Bearer {access_token}'
}
from_str = start_date.strftime('%Y-%m-%d')
to_str = end_date.strftime('%Y-%m-%d')
url = f"https://api.upstox.com/v2/historical-candle/NSE_INDEX|Nifty 50/day/{to_str}/{from_str}"
try:
logger.info("🔄 Trying Upstox API for Nifty 50 index")
response = requests.get(url, headers=headers)
if response.status_code == 200:
data = response.json()
if 'data' in data and 'candles' in data['data']:
candles = data['data']['candles']
if candles:
df = pd.DataFrame(candles, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume', 'close'])
try:
df['DATE'] = pd.to_datetime(df['timestamp'])
except Exception:
df['DATE'] = pd.to_datetime(df['timestamp'], format='%Y-%m-%d')
df.columns = ['timestamp', 'OPEN', 'HIGH', 'LOW', 'CLOSE', 'VOLUME', 'IGNORE', 'DATE']
df = df[['DATE', 'OPEN', 'HIGH', 'LOW', 'CLOSE', 'VOLUME']]
df['LTP'] = df['CLOSE']
# Ensure DATE is timezone naive to match yfinance output style
df['DATE'] = pd.to_datetime(df['DATE']).dt.tz_localize(None)
df = df.sort_values('DATE').reset_index(drop=True)
df.set_index('DATE', inplace=True)
logger.info(f"✅ Upstox API: Got {len(df)} Nifty 50 candles")
return df
else:
logger.warning(f"Upstox Nifty index query failed with status code {response.status_code}")
except Exception as e:
logger.warning(f"⚠️ Upstox API error for Nifty: {e}")
return None