Jitendra12421 commited on
Commit
50e757b
·
verified ·
1 Parent(s): 2194ae4

fix-dashboard-ui-backend

Browse files
.hfignore ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ __pycache__/
2
+ *.pyc
3
+ .pytest_cache/
4
+ .mypy_cache/
5
+ .ruff_cache/
6
+ .venv/
7
+ venv/
8
+ .env
9
+ *.log
__pycache__/app.cpython-311.pyc CHANGED
Binary files a/__pycache__/app.cpython-311.pyc and b/__pycache__/app.cpython-311.pyc differ
 
__pycache__/kotak_neo.cpython-311.pyc CHANGED
Binary files a/__pycache__/kotak_neo.cpython-311.pyc and b/__pycache__/kotak_neo.cpython-311.pyc differ
 
data/nifty50_1d.parquet CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:4d0830f9d3cfa91f02ce717b556983beb12f897bc537a623c67e38f22ce05caf
3
- size 78366
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e9a3425f3bf8271fb9002f3f770dc8607e401e9e8e5b0066495fe73092210242
3
+ size 78452
data/nifty50_1m.parquet CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:b5d6022df273daa1f020676214ec35536426fd84f2d7efb669797287e27ffa2d
3
- size 18589635
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9df0c2b2820487db987459070243b498551961894fc49bb55f467d1b0466f2f2
3
+ size 18609051
data/opening_direction_training_dataset.parquet CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:722c8225451abcb49463d2a57354bc0c9b5eb519f31a25fa3c5242adc4dbbada
3
- size 4463631
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6fa5d8cf0e098429ce3b3c4739b498a5bed3884cd1dbe6c4fda97b4600a26474
3
+ size 4464130
kotak_neo.py CHANGED
@@ -439,7 +439,7 @@ class KotakNeoManager:
439
  "status": self.status(),
440
  "as_of": _utc_now_iso(),
441
  "neo_behavior": {
442
- "holdings_note": "Kotak Neo shows CNC delivery buys in Positions on trade day and in Holdings/T1 from the next trading day.",
443
  "trade_history_note": "Kotak Neo trade history availability is limited by Neo's own order and portfolio tracker behavior.",
444
  },
445
  "summary": {
 
439
  "status": self.status(),
440
  "as_of": _utc_now_iso(),
441
  "neo_behavior": {
442
+ "holdings_note": "",
443
  "trade_history_note": "Kotak Neo trade history availability is limited by Neo's own order and portfolio tracker behavior.",
444
  },
445
  "summary": {
models/latest_prediction.csv CHANGED
@@ -1,2 +1,2 @@
1
  input_date,first5_start,first5_end,prediction,prob_up,confidence,threshold,model_name,is_overridden
2
- 2026-05-27,2026-05-27 09:15:00,2026-05-27 09:19:00,UP,0.6970470349448922,0.7720470349448922,0.425,blend_extra_trees_tight_logit_overlay,False
 
1
  input_date,first5_start,first5_end,prediction,prob_up,confidence,threshold,model_name,is_overridden
2
+ 2026-06-02,2026-06-02 09:15:00,2026-06-02 09:19:00,DOWN,0.6609583467127472,0.7359583467127473,0.425,blend_extra_trees_tight_logit_overlay,True
models/yahoo_history_cache.sqlite3 CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:534853b3b5984c2c4128ed073412f090ce96d6cb7a9da4aaa98a20482a2a4bff
3
- size 155648
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1dcb91ddef71b32d679585287872891cb4f4ddc992b8d3c3659989829323a454
3
+ size 225280
nifty_backend/__pycache__/runtime.cpython-311.pyc CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:758fbd828aed6b736b14e5a2a6834ef5559a3bf92b1f3e607f375249240ea6cb
3
- size 104535
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:89f2a00f920ffc636fbdd9b8b9b0fb6c6cbe955a5de208b7879183571d861e84
3
+ size 112925
nifty_backend/runtime.py CHANGED
@@ -64,6 +64,7 @@ REFRESH_REFRESHING = "refreshing"
64
  REFRESH_READY = "ready"
65
  REFRESH_FAILED = "failed"
66
  REFRESH_NORMAL = "normal"
 
67
 
68
  DECISION_OVERLAYS = [
69
  {
@@ -1094,6 +1095,7 @@ def dashboard_payload() -> dict[str, Any]:
1094
  _file_cache_key(OPENING_DATASET_PATH),
1095
  _file_cache_key(MODEL_DIR / "candidate_results.csv"),
1096
  _file_cache_key(NIFTY_1M_PATH),
 
1097
  )
1098
  with _dashboard_payload_lock:
1099
  return copy.deepcopy(_dashboard_payload_cached(key))
@@ -1197,6 +1199,7 @@ def _dashboard_payload_cached(key: tuple[tuple[str, int | None, int | None], ...
1197
  "latest": t5_latest,
1198
  "tomorrow_latest": tomorrow_latest,
1199
  "tplus1_latest": tplus1_latest,
 
1200
  "metrics": metrics,
1201
  "summary": summary,
1202
  "tomorrow_summary": tomorrow_summary,
@@ -1308,6 +1311,128 @@ def update_opening_outcomes_from_daily() -> dict[str, Any]:
1308
  }
1309
 
1310
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1311
  def refresh_market_close_data(session_date: date | None = None) -> dict[str, Any]:
1312
  now = datetime.now(IST)
1313
  session_date = session_date or now.date()
@@ -1319,6 +1444,11 @@ def refresh_market_close_data(session_date: date | None = None) -> dict[str, Any
1319
  minutes = fetch_yahoo_minutes(period="7d")
1320
  minute_frame = append_parquet_rows(NIFTY_1M_PATH, minutes, ["date"])
1321
  daily_info = refresh_daily_data()
 
 
 
 
 
1322
  t5_prediction = refresh_first5_prediction(session_date=session_date, minutes=minutes)
1323
  tplus1_prediction = refresh_tplus1_prediction(session_date=session_date)
1324
  outcomes = update_opening_outcomes_from_daily()
 
64
  REFRESH_READY = "ready"
65
  REFRESH_FAILED = "failed"
66
  REFRESH_NORMAL = "normal"
67
+ LIVE_ACCURACY_PATH = MODEL_DIR / "live_accuracy.json"
68
 
69
  DECISION_OVERLAYS = [
70
  {
 
1095
  _file_cache_key(OPENING_DATASET_PATH),
1096
  _file_cache_key(MODEL_DIR / "candidate_results.csv"),
1097
  _file_cache_key(NIFTY_1M_PATH),
1098
+ _file_cache_key(LIVE_ACCURACY_PATH),
1099
  )
1100
  with _dashboard_payload_lock:
1101
  return copy.deepcopy(_dashboard_payload_cached(key))
 
1199
  "latest": t5_latest,
1200
  "tomorrow_latest": tomorrow_latest,
1201
  "tplus1_latest": tplus1_latest,
1202
+ "live_accuracy": load_live_accuracy(),
1203
  "metrics": metrics,
1204
  "summary": summary,
1205
  "tomorrow_summary": tomorrow_summary,
 
1311
  }
1312
 
1313
 
1314
+ def load_live_accuracy() -> dict[str, Any]:
1315
+ """Load the live accuracy ledger from disk."""
1316
+ if LIVE_ACCURACY_PATH.exists():
1317
+ try:
1318
+ return json.loads(LIVE_ACCURACY_PATH.read_text(encoding="utf-8"))
1319
+ except Exception:
1320
+ pass
1321
+ return {
1322
+ "tomorrow": {"entries": [], "accuracy": None, "total": 0, "correct_count": 0},
1323
+ "t5": {"entries": [], "accuracy": None, "total": 0, "correct_count": 0},
1324
+ "tplus1": {"entries": [], "accuracy": None, "total": 0, "correct_count": 0},
1325
+ }
1326
+
1327
+
1328
+ def save_live_accuracy(data: dict[str, Any]) -> None:
1329
+ """Persist the live accuracy ledger to disk."""
1330
+ LIVE_ACCURACY_PATH.write_text(json.dumps(data, indent=2), encoding="utf-8")
1331
+
1332
+
1333
+ def update_live_accuracy(session_date: date) -> dict[str, Any]:
1334
+ """Score today's predictions against actual outcomes and update the ledger.
1335
+
1336
+ Must be called AFTER refresh_daily_data() (so today's close is available)
1337
+ but BEFORE refresh_first5_prediction / refresh_tplus1_prediction /
1338
+ refresh_tomorrow_prediction (so the CSV files still hold the predictions
1339
+ we want to score).
1340
+ """
1341
+ ledger = load_live_accuracy()
1342
+ daily = pd.read_parquet(NIFTY_1D_PATH)
1343
+ daily["_date"] = pd.to_datetime(daily["date"], errors="coerce").dt.normalize()
1344
+ today_rows = daily[daily["_date"].dt.date == session_date]
1345
+ if today_rows.empty:
1346
+ return ledger
1347
+
1348
+ day_open = float(today_rows.iloc[-1]["open"])
1349
+ day_close = float(today_rows.iloc[-1]["close"])
1350
+ if not (np.isfinite(day_open) and np.isfinite(day_close) and day_open != 0):
1351
+ return ledger
1352
+ actual_close_gt_open = "UP" if day_close > day_open else "DOWN"
1353
+ session_iso = session_date.isoformat()
1354
+
1355
+ # --- T+5: today's 9:20 AM prediction vs close > open ---
1356
+ logged_t5 = {e["date"] for e in ledger["t5"]["entries"]}
1357
+ if session_iso not in logged_t5 and LATEST_PATH.exists():
1358
+ try:
1359
+ t5_row = pd.read_csv(LATEST_PATH).iloc[-1].to_dict()
1360
+ if str(t5_row.get("input_date", ""))[:10] == session_iso:
1361
+ pred = str(t5_row.get("prediction", "")).upper()
1362
+ if pred in ("UP", "DOWN"):
1363
+ ledger["t5"]["entries"].append({
1364
+ "date": session_iso,
1365
+ "prediction": pred,
1366
+ "actual": actual_close_gt_open,
1367
+ "correct": pred == actual_close_gt_open,
1368
+ })
1369
+ except Exception:
1370
+ pass
1371
+
1372
+ # --- Tomorrow: yesterday's prediction targeting today vs close > open ---
1373
+ logged_tom = {e["date"] for e in ledger["tomorrow"]["entries"]}
1374
+ if session_iso not in logged_tom and TOMORROW_LATEST_PATH.exists():
1375
+ try:
1376
+ tom_row = pd.read_csv(TOMORROW_LATEST_PATH).iloc[-1].to_dict()
1377
+ if str(tom_row.get("target_date", ""))[:10] == session_iso:
1378
+ pred = str(tom_row.get("prediction", "")).upper()
1379
+ if pred in ("UP", "DOWN"):
1380
+ ledger["tomorrow"]["entries"].append({
1381
+ "date": session_iso,
1382
+ "prediction": pred,
1383
+ "actual": actual_close_gt_open,
1384
+ "correct": pred == actual_close_gt_open,
1385
+ })
1386
+ except Exception:
1387
+ pass
1388
+
1389
+ # --- T+1: yesterday's 14:20 prediction targeting today ---
1390
+ # T+1 target: today's close > yesterday's 14:20 close
1391
+ logged_t1 = {e["date"] for e in ledger["tplus1"]["entries"]}
1392
+ if session_iso not in logged_t1 and TPLUS1_LATEST_PATH.exists():
1393
+ try:
1394
+ t1_row = pd.read_csv(TPLUS1_LATEST_PATH).iloc[-1].to_dict()
1395
+ if str(t1_row.get("target_date", ""))[:10] == session_iso:
1396
+ pred = str(t1_row.get("prediction", "")).upper()
1397
+ input_date_str = str(t1_row.get("input_date", ""))[:10]
1398
+ input_day = date.fromisoformat(input_date_str)
1399
+ # Read the 14:20 close from minute data for the input session
1400
+ minute = pd.read_parquet(NIFTY_1M_PATH, columns=["date", "close"])
1401
+ minute["dt"] = pd.to_datetime(minute["date"], errors="coerce")
1402
+ minute = minute.dropna(subset=["dt"])
1403
+ minute["session_date"] = minute["dt"].dt.normalize()
1404
+ minute["time_str"] = minute["dt"].dt.strftime("%H:%M")
1405
+ window = minute[
1406
+ (minute["session_date"].dt.date == input_day)
1407
+ & (minute["time_str"] >= "14:00")
1408
+ & (minute["time_str"] <= "14:20")
1409
+ ].sort_values("dt")
1410
+ if not window.empty and pred in ("UP", "DOWN"):
1411
+ w_close = float(window.iloc[-1]["close"])
1412
+ t1_actual = "UP" if day_close > w_close else "DOWN"
1413
+ ledger["tplus1"]["entries"].append({
1414
+ "date": session_iso,
1415
+ "prediction": pred,
1416
+ "actual": t1_actual,
1417
+ "correct": pred == t1_actual,
1418
+ })
1419
+ except Exception:
1420
+ pass
1421
+
1422
+ # Recompute summary stats
1423
+ for model_id in ("t5", "tomorrow", "tplus1"):
1424
+ entries = ledger[model_id]["entries"]
1425
+ total = len(entries)
1426
+ correct = sum(1 for e in entries if e.get("correct"))
1427
+ ledger[model_id]["total"] = total
1428
+ ledger[model_id]["correct_count"] = correct
1429
+ ledger[model_id]["accuracy"] = correct / total if total > 0 else None
1430
+
1431
+ save_live_accuracy(ledger)
1432
+ clear_dashboard_payload_cache()
1433
+ return ledger
1434
+
1435
+
1436
  def refresh_market_close_data(session_date: date | None = None) -> dict[str, Any]:
1437
  now = datetime.now(IST)
1438
  session_date = session_date or now.date()
 
1444
  minutes = fetch_yahoo_minutes(period="7d")
1445
  minute_frame = append_parquet_rows(NIFTY_1M_PATH, minutes, ["date"])
1446
  daily_info = refresh_daily_data()
1447
+ # Score live predictions BEFORE they get overwritten by fresh ones
1448
+ try:
1449
+ update_live_accuracy(session_date)
1450
+ except Exception as exc:
1451
+ print(f"[close-refresh] live accuracy update failed: {exc}", flush=True)
1452
  t5_prediction = refresh_first5_prediction(session_date=session_date, minutes=minutes)
1453
  tplus1_prediction = refresh_tplus1_prediction(session_date=session_date)
1454
  outcomes = update_opening_outcomes_from_daily()