topsecrettraders commited on
Commit
7e82e76
·
verified ·
1 Parent(s): 6d17eec

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +30 -39
app.py CHANGED
@@ -143,46 +143,32 @@ def fetch_series(
143
  t_end = f"{date} {end_time}:59"
144
 
145
  if mode == "advanced":
146
- # 1. Fetch available instruments
147
  inst_data = sb_rpc("get_instruments_for_expiry", {"p_date": date, "p_root": root, "p_expiry": expiry})
148
  instruments = [r['instrument_name'] for r in inst_data]
149
 
150
  if not instruments:
151
  return JSONResponse({"error": f"No data found for expiry {expiry}", "labels":[], "P":[]})
152
 
153
- # 2. Intelligent Default Selection (Spot/Equity > Future > First Available)
154
  ref_instrument = instrument
 
 
155
  if not ref_instrument:
156
- spot_keys =[k for k in instruments if k.endswith('-INDEX') or k.endswith('-EQ')]
157
  fut_keys = [k for k in instruments if 'FUT' in k]
 
158
  if spot_keys:
159
  ref_instrument = spot_keys[0]
160
  elif fut_keys:
161
  ref_instrument = fut_keys[0]
162
  else:
163
- ref_instrument = instruments[0]
164
-
165
- if ref_instrument not in instruments:
166
- return JSONResponse({"error": f"Ref Instrument '{ref_instrument}' not found in DB for this expiry. Please re-select from dropdown.", "labels": [], "P":[]})
167
-
168
- # 3. Build Strike Map correctly handling Fyers date strings (e.g. NIFTY2630224000CE -> 24000)
169
- strike_map = {}
170
- for k in instruments:
171
- if k.endswith('CE') or k.endswith('PE'):
172
- # Fyers string: 2 digits(YY) + 3 Alphanumeric(M DD/MMM) + Strike + CE/PE
173
- match = re.search(r'\d{2}[A-Z0-9]{3}(\d+(\.\d+)?)(?:CE|PE)$', k)
174
- if match:
175
- strike_map[k] = float(match.group(1))
176
- else:
177
- # Fallback
178
- match2 = re.search(r'(\d+(\.\d+)?)(?:CE|PE)$', k)
179
- if match2:
180
- strike_map[k] = float(match2.group(1))
181
-
182
- if not strike_map:
183
- return JSONResponse({"error": "No options available to build ATM map.", "labels":[], "P":[]})
184
 
185
- # 4. Call Postgres with parsed Strike Map
 
186
  params = {
187
  "p_root": root,
188
  "p_expiry": expiry,
@@ -190,7 +176,7 @@ def fetch_series(
190
  "p_end_time": t_end,
191
  "p_ref_instrument": ref_instrument,
192
  "p_atm_range": atm_range,
193
- "p_strike_map": strike_map
194
  }
195
  records = sb_rpc("get_advanced_chart_data", params)
196
 
@@ -209,13 +195,14 @@ def fetch_series(
209
  records = sb_rpc("get_normal_chart_data", params)
210
 
211
  if not records or (isinstance(records, dict) and records.get("error")):
212
- return JSONResponse({"error": "No DB records found. Time range might be empty.", "labels":[], "P":[]})
 
213
 
214
  df = pd.DataFrame(records)
215
  if df.empty:
216
  return JSONResponse({"error": "Dataframe Empty", "labels": [], "P":[]})
217
 
218
- # Rename RPC column outputs to match Standard UI format
219
  df.rename(columns={
220
  "tick_ts": "ts",
221
  "b_qty": "buy_qty",
@@ -226,6 +213,7 @@ def fetch_series(
226
  df['ts'] = pd.to_datetime(df['ts'])
227
  df.set_index('ts', inplace=True)
228
 
 
229
  tf_map = {
230
  "1min": "1min", "3min": "3min", "5min": "5min",
231
  "15min": "15min", "30min": "30min", "1hour": "1h"
@@ -233,24 +221,27 @@ def fetch_series(
233
  panda_tf = tf_map.get(timeframe, "1min")
234
 
235
  agg_dict = {
236
- "price": "last", "volume": "last", "oi": "last",
237
  "buy_qty": "mean", "sell_qty": "mean",
238
  "cb": "mean", "cs": "mean", "pb": "mean", "ps": "mean"
239
  }
240
 
241
- resampled = df.resample(panda_tf).agg(agg_dict).ffill().fillna(0)
 
 
 
242
 
243
  response_data = {
244
  "labels": resampled.index.strftime('%H:%M').tolist(),
245
- "P": resampled['price'].tolist(),
246
- "B": resampled['buy_qty'].tolist(),
247
- "S": resampled['sell_qty'].tolist(),
248
- "V": resampled['volume'].tolist(),
249
- "OI": resampled['oi'].tolist(),
250
- "CB": resampled['cb'].tolist(),
251
- "CS": resampled['cs'].tolist(),
252
- "PB": resampled['pb'].tolist(),
253
- "PS": resampled['ps'].tolist()
254
  }
255
 
256
  return JSONResponse(response_data)
 
143
  t_end = f"{date} {end_time}:59"
144
 
145
  if mode == "advanced":
146
+ # 1. Fetch available instruments (Lightweight metadata fetch)
147
  inst_data = sb_rpc("get_instruments_for_expiry", {"p_date": date, "p_root": root, "p_expiry": expiry})
148
  instruments = [r['instrument_name'] for r in inst_data]
149
 
150
  if not instruments:
151
  return JSONResponse({"error": f"No data found for expiry {expiry}", "labels":[], "P":[]})
152
 
153
+ # 2. Intelligent Default Selection (Spot > Future > First Available)
154
  ref_instrument = instrument
155
+
156
+ # If user left instrument blank, find the best reference (Index or Future)
157
  if not ref_instrument:
158
+ spot_keys = [k for k in instruments if k.endswith('-INDEX') or k.endswith('-EQ')]
159
  fut_keys = [k for k in instruments if 'FUT' in k]
160
+
161
  if spot_keys:
162
  ref_instrument = spot_keys[0]
163
  elif fut_keys:
164
  ref_instrument = fut_keys[0]
165
  else:
166
+ # Fallback: Find first key that is NOT an option
167
+ others = [k for k in instruments if not k.endswith('CE') and not k.endswith('PE')]
168
+ ref_instrument = others[0] if others else instruments[0]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
 
170
+ # 3. Call Postgres (Logic is now 100% inside DB)
171
+ # We pass empty dict for p_strike_map as it is handled in SQL now
172
  params = {
173
  "p_root": root,
174
  "p_expiry": expiry,
 
176
  "p_end_time": t_end,
177
  "p_ref_instrument": ref_instrument,
178
  "p_atm_range": atm_range,
179
+ "p_strike_map": {}
180
  }
181
  records = sb_rpc("get_advanced_chart_data", params)
182
 
 
195
  records = sb_rpc("get_normal_chart_data", params)
196
 
197
  if not records or (isinstance(records, dict) and records.get("error")):
198
+ # Handle case where Time range exists but maybe reference instrument had no ticks
199
+ return JSONResponse({"error": "No valid data found in range.", "labels":[], "P":[]})
200
 
201
  df = pd.DataFrame(records)
202
  if df.empty:
203
  return JSONResponse({"error": "Dataframe Empty", "labels": [], "P":[]})
204
 
205
+ # Rename columns to match standard
206
  df.rename(columns={
207
  "tick_ts": "ts",
208
  "b_qty": "buy_qty",
 
213
  df['ts'] = pd.to_datetime(df['ts'])
214
  df.set_index('ts', inplace=True)
215
 
216
+ # Resample Logic
217
  tf_map = {
218
  "1min": "1min", "3min": "3min", "5min": "5min",
219
  "15min": "15min", "30min": "30min", "1hour": "1h"
 
221
  panda_tf = tf_map.get(timeframe, "1min")
222
 
223
  agg_dict = {
224
+ "price": "last", "volume": "sum", "oi": "last", # Vol should be sum for aggregations usually
225
  "buy_qty": "mean", "sell_qty": "mean",
226
  "cb": "mean", "cs": "mean", "pb": "mean", "ps": "mean"
227
  }
228
 
229
+ # Only aggregate columns that actually exist
230
+ existing_cols = {k: v for k, v in agg_dict.items() if k in df.columns}
231
+
232
+ resampled = df.resample(panda_tf).agg(existing_cols).ffill().fillna(0)
233
 
234
  response_data = {
235
  "labels": resampled.index.strftime('%H:%M').tolist(),
236
+ "P": resampled['price'].tolist() if 'price' in resampled else [],
237
+ "B": resampled['buy_qty'].tolist() if 'buy_qty' in resampled else [],
238
+ "S": resampled['sell_qty'].tolist() if 'sell_qty' in resampled else [],
239
+ "V": resampled['volume'].tolist() if 'volume' in resampled else [],
240
+ "OI": resampled['oi'].tolist() if 'oi' in resampled else [],
241
+ "CB": resampled['cb'].tolist() if 'cb' in resampled else [],
242
+ "CS": resampled['cs'].tolist() if 'cs' in resampled else [],
243
+ "PB": resampled['pb'].tolist() if 'pb' in resampled else [],
244
+ "PS": resampled['ps'].tolist() if 'ps' in resampled else []
245
  }
246
 
247
  return JSONResponse(response_data)