Jitendra12421 commited on
Commit
f7eba48
·
verified ·
1 Parent(s): a6f6432

Upload 42 files

Browse files
.gitattributes CHANGED
@@ -34,3 +34,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  models/yahoo_history_cache.sqlite3 filter=lfs diff=lfs merge=lfs -text
 
 
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  models/yahoo_history_cache.sqlite3 filter=lfs diff=lfs merge=lfs -text
37
+ nifty_backend/__pycache__/runtime.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
data/tomorrow_test_predictions.parquet CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:10065b1a9ef8b127e324103911731856946700e857f932ff8f54adb93c63c143
3
- size 9555
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a0f2de230f3ae32dd009829efe7b90333dfa7f07bdb9a627d96f6173c30c77bb
3
+ size 10739
models/nifty_tomorrow_direction_model.joblib CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:486ac9963b76c67863e49b75422ff6d299bbf85cd8bd9932291016c832794c82
3
- size 328
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fffacba0382c720974d006020e083b14fe13510c5347b8e2778bc514bb965e34
3
+ size 443
models/tomorrow_latest_prediction.csv CHANGED
@@ -1,2 +1,2 @@
1
- input_date,target_date,prediction,prob_up,confidence,threshold,model_name,source_model,validation_accuracy,test_accuracy
2
- 2026-05-27,2026-05-29,DOWN,0.503279589082978,0.503279589082978,0.543,nifty_tomorrow_direction_model,tuned_daily_forest_single,0.5780141843971631,0.6182795698924731
 
1
+ input_date,target_date,prediction,prob_up,confidence,threshold,model_name,source_model,validation_accuracy,test_accuracy,artifact_source
2
+ 2026-05-27,2026-05-29,DOWN,0.4807130191016562,0.5192869808983438,0.54,nifty_tomorrow_direction_model,locked_multiwindow_nifty50_ensemble,0.5673758865248227,0.6368421052631579,C:\Users\jhaji\Downloads\forecasting project\Code\models\nifty_forecaster\outputs
models/tomorrow_summary.json CHANGED
@@ -3,35 +3,40 @@
3
  "horizon": "daily",
4
  "horizon_bars": 1,
5
  "config": {
6
- "name": "tuned_daily_forest_single",
7
- "use_intraday": false,
8
  "use_external": true,
9
  "use_institutional": false,
10
  "use_options": true,
11
  "use_engineered_macro_flow": false,
12
- "blend_mode": "single_model",
13
  "decision_overlay": "bank_body_near_threshold"
14
  },
15
- "threshold": 0.543,
16
- "validation_accuracy": 0.5780141843971631,
17
- "test_accuracy": 0.6182795698924731,
18
- "baseline_accuracy": 0.5053763440860215,
19
  "n_train": 2221,
20
  "n_valid": 282,
21
- "n_test": 186,
22
  "train_start": "2015-01-09",
23
  "train_end": "2023-12-31",
24
  "valid_start": "2024-07-01",
25
  "valid_end": "2025-08-17",
26
  "test_start": "2025-08-18",
27
- "test_end": "2026-05-20",
28
  "latest_forecast_date": "2026-05-27",
29
- "latest_forecast_for": "next trading session 2026-05-29",
30
- "latest_forecast_prob_up": 0.503279589082978,
31
  "latest_forecast_signal": "DOWN",
32
- "feature_count": 301,
 
 
 
 
33
  "model_name": "nifty_tomorrow_direction_model",
34
- "source_model": "tuned_daily_forest_single",
35
  "target": "next trading session NIFTY 50 direction",
36
- "latest_target_date": "2026-05-29"
 
37
  }
 
3
  "horizon": "daily",
4
  "horizon_bars": 1,
5
  "config": {
6
+ "name": "locked_multiwindow_nifty50_ensemble",
7
+ "use_intraday": true,
8
  "use_external": true,
9
  "use_institutional": false,
10
  "use_options": true,
11
  "use_engineered_macro_flow": false,
12
+ "blend_mode": "locked_nifty50_multiwindow",
13
  "decision_overlay": "bank_body_near_threshold"
14
  },
15
+ "threshold": 0.54,
16
+ "validation_accuracy": 0.5673758865248227,
17
+ "test_accuracy": 0.6368421052631579,
18
+ "baseline_accuracy": 0.5052631578947369,
19
  "n_train": 2221,
20
  "n_valid": 282,
21
+ "n_test": 190,
22
  "train_start": "2015-01-09",
23
  "train_end": "2023-12-31",
24
  "valid_start": "2024-07-01",
25
  "valid_end": "2025-08-17",
26
  "test_start": "2025-08-18",
27
+ "test_end": "2026-05-26",
28
  "latest_forecast_date": "2026-05-27",
29
+ "latest_forecast_for": "next trading bar after 2026-05-27",
30
+ "latest_forecast_prob_up": 0.48071301910165626,
31
  "latest_forecast_signal": "DOWN",
32
+ "feature_count": 204,
33
+ "validation_prob_std": 0.07748322465953016,
34
+ "test_prob_std": 0.07363146825392504,
35
+ "test_prob_min": 0.37108281367720986,
36
+ "test_prob_max": 0.6611571963678617,
37
  "model_name": "nifty_tomorrow_direction_model",
38
+ "source_model": "locked_multiwindow_nifty50_ensemble",
39
  "target": "next trading session NIFTY 50 direction",
40
+ "artifact_type": "daily_forecaster_outputs",
41
+ "artifact_source": "C:\\Users\\jhaji\\Downloads\\forecasting project\\Code\\models\\nifty_forecaster\\outputs"
42
  }
nifty_backend/__pycache__/runtime.cpython-311.pyc CHANGED
Binary files a/nifty_backend/__pycache__/runtime.cpython-311.pyc and b/nifty_backend/__pycache__/runtime.cpython-311.pyc differ
 
nifty_backend/runtime.py CHANGED
@@ -1,9 +1,10 @@
1
  from __future__ import annotations
2
 
3
- import json
4
- import copy
5
- import sys
6
- import threading
 
7
  from dataclasses import dataclass
8
  from datetime import date, datetime, time, timedelta
9
  from functools import lru_cache
@@ -42,8 +43,18 @@ TEST_PREDICTIONS_PATH = DATA_DIR / "test_predictions.parquet"
42
  TOMORROW_MODEL_PATH = MODEL_DIR / "nifty_tomorrow_direction_model.joblib"
43
  TOMORROW_LATEST_PATH = MODEL_DIR / "tomorrow_latest_prediction.csv"
44
  TOMORROW_SUMMARY_PATH = MODEL_DIR / "tomorrow_summary.json"
45
- TOMORROW_TEST_PREDICTIONS_PATH = DATA_DIR / "tomorrow_test_predictions.parquet"
46
- TPLUS1_MODEL_PATH = MODEL_DIR / "nifty_1420_tplus1_logistic_model.joblib"
 
 
 
 
 
 
 
 
 
 
47
  TPLUS1_LATEST_PATH = MODEL_DIR / "tplus1_latest_prediction.csv"
48
  TPLUS1_SUMMARY_PATH = MODEL_DIR / "tplus1_summary.json"
49
  TPLUS1_TEST_PREDICTIONS_PATH = DATA_DIR / "tplus1_test_predictions.parquet"
@@ -541,19 +552,125 @@ def latest_saved_prediction() -> dict[str, Any]:
541
  return dict(_latest_saved_prediction_cached(_file_cache_key(LATEST_PATH), _file_cache_key(MODEL_DIR / "summary.json")))
542
 
543
 
544
- def _latest_saved_prediction_uncached() -> dict[str, Any]:
545
  if LATEST_PATH.exists():
546
  return pd.read_csv(LATEST_PATH).iloc[-1].to_dict()
547
  summary_path = MODEL_DIR / "summary.json"
548
  if summary_path.exists():
549
  return json.loads(summary_path.read_text(encoding="utf-8"))
550
- raise FileNotFoundError("No latest prediction is available yet.")
551
-
552
-
553
- def load_tomorrow_model_artifact() -> dict[str, Any]:
554
- if TOMORROW_MODEL_PATH.exists():
555
- return joblib.load(TOMORROW_MODEL_PATH)
556
- summary = load_tomorrow_summary()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
557
  return {
558
  "artifact_type": "daily_forecaster_snapshot",
559
  "model_name": summary.get("model_name", "nifty_tomorrow_direction_model"),
@@ -562,23 +679,27 @@ def load_tomorrow_model_artifact() -> dict[str, Any]:
562
  }
563
 
564
 
565
- def load_tomorrow_summary() -> dict[str, Any]:
566
- if TOMORROW_SUMMARY_PATH.exists():
567
- return json.loads(TOMORROW_SUMMARY_PATH.read_text(encoding="utf-8"))
568
- return {
569
- "model_name": "nifty_tomorrow_direction_model",
570
- "source_model": "tuned_daily_forest_single",
571
- "target": "next trading session NIFTY 50 direction",
572
- "threshold": 0.543,
573
- "validation_accuracy": 0.5780141843971631,
574
- "test_accuracy": 0.6182795698924731,
575
- "baseline_accuracy": 0.5053763440860215,
576
- "n_test": 186,
577
- "feature_count": 301,
578
- }
 
 
 
579
 
580
 
581
  def latest_tomorrow_prediction() -> dict[str, Any]:
 
582
  latest_daily = latest_parquet_date(NIFTY_1D_PATH)
583
  if TOMORROW_LATEST_PATH.exists():
584
  row = pd.read_csv(TOMORROW_LATEST_PATH).iloc[-1].to_dict()
@@ -589,9 +710,15 @@ def latest_tomorrow_prediction() -> dict[str, Any]:
589
  input_day = None
590
  if latest_daily is not None and (input_day is None or input_day < latest_daily):
591
  try:
592
- return refresh_tomorrow_prediction(session_date=latest_daily)
 
 
 
 
 
 
593
  except Exception:
594
- return cleaned
595
  return cleaned
596
  summary = load_tomorrow_summary()
597
  try:
@@ -835,9 +962,23 @@ def _tomorrow_probability_from_daily(daily: pd.DataFrame, fallback_prob: float)
835
  return float(np.clip(score, 0.35, 0.65))
836
 
837
 
838
- def refresh_tomorrow_prediction(session_date: date | None = None) -> dict[str, Any]:
839
- summary = load_tomorrow_summary()
840
- artifact = load_tomorrow_model_artifact()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
841
  daily = pd.read_parquet(NIFTY_1D_PATH)
842
  daily["date"] = pd.to_datetime(daily["date"], errors="coerce").dt.normalize()
843
  daily = daily.dropna(subset=["date"]).sort_values("date")
 
1
  from __future__ import annotations
2
 
3
+ import json
4
+ import copy
5
+ import os
6
+ import sys
7
+ import threading
8
  from dataclasses import dataclass
9
  from datetime import date, datetime, time, timedelta
10
  from functools import lru_cache
 
43
  TOMORROW_MODEL_PATH = MODEL_DIR / "nifty_tomorrow_direction_model.joblib"
44
  TOMORROW_LATEST_PATH = MODEL_DIR / "tomorrow_latest_prediction.csv"
45
  TOMORROW_SUMMARY_PATH = MODEL_DIR / "tomorrow_summary.json"
46
+ TOMORROW_TEST_PREDICTIONS_PATH = DATA_DIR / "tomorrow_test_predictions.parquet"
47
+ FORECASTING_PROJECT_ROOT = Path(
48
+ os.environ.get(
49
+ "FORECASTING_PROJECT_ROOT",
50
+ str(BACKEND_ROOT.parent.parent / "forecasting project"),
51
+ )
52
+ )
53
+ DAILY_FORECASTER_OUTPUT_DIR = FORECASTING_PROJECT_ROOT / "Code" / "models" / "nifty_forecaster" / "outputs"
54
+ DAILY_FORECASTER_SUMMARY_PATH = DAILY_FORECASTER_OUTPUT_DIR / "forecaster_summary.json"
55
+ DAILY_FORECASTER_LATEST_PATH = DAILY_FORECASTER_OUTPUT_DIR / "forecaster_latest.csv"
56
+ DAILY_FORECASTER_PREDICTIONS_PATH = DAILY_FORECASTER_OUTPUT_DIR / "forecaster_test_predictions.csv"
57
+ TPLUS1_MODEL_PATH = MODEL_DIR / "nifty_1420_tplus1_logistic_model.joblib"
58
  TPLUS1_LATEST_PATH = MODEL_DIR / "tplus1_latest_prediction.csv"
59
  TPLUS1_SUMMARY_PATH = MODEL_DIR / "tplus1_summary.json"
60
  TPLUS1_TEST_PREDICTIONS_PATH = DATA_DIR / "tplus1_test_predictions.parquet"
 
552
  return dict(_latest_saved_prediction_cached(_file_cache_key(LATEST_PATH), _file_cache_key(MODEL_DIR / "summary.json")))
553
 
554
 
555
+ def _latest_saved_prediction_uncached() -> dict[str, Any]:
556
  if LATEST_PATH.exists():
557
  return pd.read_csv(LATEST_PATH).iloc[-1].to_dict()
558
  summary_path = MODEL_DIR / "summary.json"
559
  if summary_path.exists():
560
  return json.loads(summary_path.read_text(encoding="utf-8"))
561
+ raise FileNotFoundError("No latest prediction is available yet.")
562
+
563
+
564
+ def _read_daily_forecaster_summary() -> dict[str, Any] | None:
565
+ if not DAILY_FORECASTER_SUMMARY_PATH.exists():
566
+ return None
567
+ raw = json.loads(DAILY_FORECASTER_SUMMARY_PATH.read_text(encoding="utf-8"))
568
+ if isinstance(raw, list):
569
+ matches = [row for row in raw if row.get("symbol") == "NIFTY 50"]
570
+ summary = dict(matches[0] if matches else raw[0])
571
+ elif isinstance(raw, dict):
572
+ summary = dict(raw)
573
+ else:
574
+ return None
575
+ config = summary.get("config") if isinstance(summary.get("config"), dict) else {}
576
+ summary.setdefault("symbol", "NIFTY 50")
577
+ summary.setdefault("horizon", "daily")
578
+ summary.setdefault("horizon_bars", 1)
579
+ summary["model_name"] = "nifty_tomorrow_direction_model"
580
+ summary["source_model"] = str(config.get("name") or summary.get("source_model") or "locked_multiwindow_nifty50_ensemble")
581
+ summary["target"] = "next trading session NIFTY 50 direction"
582
+ summary["artifact_type"] = "daily_forecaster_outputs"
583
+ summary["artifact_source"] = str(DAILY_FORECASTER_OUTPUT_DIR)
584
+ return summary
585
+
586
+
587
+ def _read_daily_forecaster_latest(summary: dict[str, Any]) -> dict[str, Any] | None:
588
+ if not DAILY_FORECASTER_LATEST_PATH.exists():
589
+ return None
590
+ latest = pd.read_csv(DAILY_FORECASTER_LATEST_PATH)
591
+ if latest.empty:
592
+ return None
593
+ if "symbol" in latest.columns:
594
+ filtered = latest[latest["symbol"].astype(str) == "NIFTY 50"]
595
+ if not filtered.empty:
596
+ latest = filtered
597
+ row = {k: (None if pd.isna(v) else v) for k, v in latest.iloc[-1].to_dict().items()}
598
+ input_date = row.get("latest_forecast_date") or row.get("input_date")
599
+ target_date = row.get("target_date")
600
+ if not target_date and input_date:
601
+ try:
602
+ target_date = next_trading_day(date.fromisoformat(str(input_date)[:10]) + timedelta(days=1)).isoformat()
603
+ except Exception:
604
+ target_date = None
605
+ prob_up = row.get("latest_forecast_prob_up", row.get("prob_up"))
606
+ prediction = row.get("latest_forecast_signal", row.get("prediction"))
607
+ threshold = row.get("threshold", summary.get("threshold"))
608
+ confidence = row.get("confidence")
609
+ if confidence is None and prob_up is not None:
610
+ try:
611
+ confidence = float(max(float(prob_up), 1.0 - float(prob_up)))
612
+ except Exception:
613
+ confidence = None
614
+ return {
615
+ "input_date": input_date,
616
+ "target_date": target_date,
617
+ "prediction": prediction,
618
+ "prob_up": prob_up,
619
+ "confidence": confidence,
620
+ "threshold": threshold,
621
+ "model_name": "nifty_tomorrow_direction_model",
622
+ "source_model": summary.get("source_model", "locked_multiwindow_nifty50_ensemble"),
623
+ "validation_accuracy": summary.get("validation_accuracy"),
624
+ "test_accuracy": summary.get("test_accuracy"),
625
+ "artifact_source": str(DAILY_FORECASTER_OUTPUT_DIR),
626
+ }
627
+
628
+
629
+ def sync_daily_forecaster_outputs() -> dict[str, Any] | None:
630
+ summary = _read_daily_forecaster_summary()
631
+ if summary is None:
632
+ return None
633
+ latest = _read_daily_forecaster_latest(summary)
634
+ TOMORROW_SUMMARY_PATH.write_text(json.dumps(summary, indent=2), encoding="utf-8")
635
+ if latest is not None:
636
+ pd.DataFrame([latest]).to_csv(TOMORROW_LATEST_PATH, index=False)
637
+ if DAILY_FORECASTER_PREDICTIONS_PATH.exists():
638
+ predictions = pd.read_csv(DAILY_FORECASTER_PREDICTIONS_PATH)
639
+ if "symbol" in predictions.columns:
640
+ predictions = predictions[predictions["symbol"].astype(str) == "NIFTY 50"].copy()
641
+ if not predictions.empty:
642
+ if "pred" in predictions.columns and "prediction" not in predictions.columns:
643
+ predictions["prediction"] = np.where(pd.to_numeric(predictions["pred"], errors="coerce") == 1, "UP", "DOWN")
644
+ if "correct" not in predictions.columns and {"target", "pred"}.issubset(predictions.columns):
645
+ predictions["correct"] = (
646
+ pd.to_numeric(predictions["target"], errors="coerce")
647
+ == pd.to_numeric(predictions["pred"], errors="coerce")
648
+ )
649
+ predictions.to_parquet(TOMORROW_TEST_PREDICTIONS_PATH, index=False)
650
+ artifact = {
651
+ "artifact_type": "daily_forecaster_outputs",
652
+ "model_name": "nifty_tomorrow_direction_model",
653
+ "source_model": summary.get("source_model", "locked_multiwindow_nifty50_ensemble"),
654
+ "threshold": float(summary.get("threshold", 0.54)),
655
+ "validation_accuracy": summary.get("validation_accuracy"),
656
+ "test_accuracy": summary.get("test_accuracy"),
657
+ "validation_prob_std": summary.get("validation_prob_std"),
658
+ "test_prob_std": summary.get("test_prob_std"),
659
+ "test_prob_min": summary.get("test_prob_min"),
660
+ "test_prob_max": summary.get("test_prob_max"),
661
+ "artifact_source": str(DAILY_FORECASTER_OUTPUT_DIR),
662
+ }
663
+ joblib.dump(artifact, TOMORROW_MODEL_PATH)
664
+ return latest or summary
665
+
666
+
667
+ def load_tomorrow_model_artifact() -> dict[str, Any]:
668
+ synced = sync_daily_forecaster_outputs()
669
+ if synced is not None and TOMORROW_MODEL_PATH.exists():
670
+ return joblib.load(TOMORROW_MODEL_PATH)
671
+ if TOMORROW_MODEL_PATH.exists():
672
+ return joblib.load(TOMORROW_MODEL_PATH)
673
+ summary = load_tomorrow_summary()
674
  return {
675
  "artifact_type": "daily_forecaster_snapshot",
676
  "model_name": summary.get("model_name", "nifty_tomorrow_direction_model"),
 
679
  }
680
 
681
 
682
+ def load_tomorrow_summary() -> dict[str, Any]:
683
+ synced = sync_daily_forecaster_outputs()
684
+ if synced is not None and TOMORROW_SUMMARY_PATH.exists():
685
+ return json.loads(TOMORROW_SUMMARY_PATH.read_text(encoding="utf-8"))
686
+ if TOMORROW_SUMMARY_PATH.exists():
687
+ return json.loads(TOMORROW_SUMMARY_PATH.read_text(encoding="utf-8"))
688
+ return {
689
+ "model_name": "nifty_tomorrow_direction_model",
690
+ "source_model": "locked_multiwindow_nifty50_ensemble",
691
+ "target": "next trading session NIFTY 50 direction",
692
+ "threshold": 0.54,
693
+ "validation_accuracy": 0.5673758865248227,
694
+ "test_accuracy": 0.6451612903225806,
695
+ "baseline_accuracy": 0.5053763440860215,
696
+ "n_test": 186,
697
+ "feature_count": 204,
698
+ }
699
 
700
 
701
  def latest_tomorrow_prediction() -> dict[str, Any]:
702
+ sync_daily_forecaster_outputs()
703
  latest_daily = latest_parquet_date(NIFTY_1D_PATH)
704
  if TOMORROW_LATEST_PATH.exists():
705
  row = pd.read_csv(TOMORROW_LATEST_PATH).iloc[-1].to_dict()
 
710
  input_day = None
711
  if latest_daily is not None and (input_day is None or input_day < latest_daily):
712
  try:
713
+ refreshed = refresh_tomorrow_prediction(session_date=latest_daily)
714
+ try:
715
+ refreshed_day = date.fromisoformat(str(refreshed.get("input_date"))[:10])
716
+ except Exception:
717
+ refreshed_day = None
718
+ if refreshed_day is not None and refreshed_day >= latest_daily:
719
+ return refreshed
720
  except Exception:
721
+ pass
722
  return cleaned
723
  summary = load_tomorrow_summary()
724
  try:
 
962
  return float(np.clip(score, 0.35, 0.65))
963
 
964
 
965
+ def refresh_tomorrow_prediction(session_date: date | None = None) -> dict[str, Any]:
966
+ synced = sync_daily_forecaster_outputs()
967
+ if synced is not None and TOMORROW_LATEST_PATH.exists():
968
+ latest = pd.read_csv(TOMORROW_LATEST_PATH).iloc[-1].to_dict()
969
+ cleaned = {k: (None if pd.isna(v) else v) for k, v in latest.items()}
970
+ if session_date is None:
971
+ clear_dashboard_payload_cache()
972
+ return cleaned
973
+ try:
974
+ input_day = date.fromisoformat(str(cleaned.get("input_date"))[:10])
975
+ except Exception:
976
+ input_day = None
977
+ if input_day is not None:
978
+ clear_dashboard_payload_cache()
979
+ return cleaned
980
+ summary = load_tomorrow_summary()
981
+ artifact = load_tomorrow_model_artifact()
982
  daily = pd.read_parquet(NIFTY_1D_PATH)
983
  daily["date"] = pd.to_datetime(daily["date"], errors="coerce").dt.normalize()
984
  daily = daily.dropna(subset=["date"]).sort_values("date")