KarlQuant commited on
Commit
b379e71
Β·
verified Β·
1 Parent(s): 5df31eb

Upload Quasar_axrvi_ranker.py

Browse files
Files changed (1) hide show
  1. Quasar_axrvi_ranker.py +77 -44
Quasar_axrvi_ranker.py CHANGED
@@ -368,8 +368,6 @@ DERIV_WS_URL = "wss://ws.binaryws.com/websockets/v3?app_id=1089"
368
  # Deriv API symbol β†’ AXRVI internal symbol
369
  SYMBOL_MAP = {
370
  "R_25": "V25",
371
- "1HZ30V": "V30_1s",
372
- "R_50": "V50",
373
  "1HZ50V": "V50_1s",
374
  "R_75": "V75",
375
  "1HZ75V": "V75_1s",
@@ -398,8 +396,6 @@ del _reverse_check, _deriv_sym, _axrvi_id
398
  # Per-asset metadata: base volatility and max position fraction
399
  ASSET_REGISTRY: Dict[str, dict] = {
400
  "V25": {"symbol": "R_25", "base_vol": 25.0, "max_pos": 0.006},
401
- "V30_1s": {"symbol": "1HZ30V", "base_vol": 30.0, "max_pos": 0.004},
402
- "V50": {"symbol": "R_50", "base_vol": 50.0, "max_pos": 0.005},
403
  "V50_1s": {"symbol": "1HZ50V", "base_vol": 50.0, "max_pos": 0.004},
404
  "V75": {"symbol": "R_75", "base_vol": 75.0, "max_pos": 0.005},
405
  "V75_1s": {"symbol": "1HZ75V", "base_vol": 75.0, "max_pos": 0.003},
@@ -423,8 +419,6 @@ ASSET_REGISTRY: Dict[str, dict] = {
423
  #
424
  # Accepted ranges per Deriv broker:
425
  # V25 β€” [160, 400, 800, 1200, 1600] β†’ use 160
426
- # V30_1s β€” [140, 400, 700, 1000, 1400] β†’ use 140
427
- # V50 β€” [80, 200, 400, 600, 800] β†’ use 80 ← FIXED: broker confirmed, NOT [50,100,200,300,500]
428
  # V50_1s β€” [80, 200, 400, 600, 800] β†’ use 80
429
  # V75 β€” [50, 100, 200, 300, 500] β†’ use 50
430
  # V75_1s β€” [50, 100, 200, 300, 500] β†’ use 50
@@ -436,8 +430,6 @@ ASSET_REGISTRY: Dict[str, dict] = {
436
  # STEP200 β€” [400, 1000, 2000, 3000, 4000] β†’ use 400
437
  ASSET_MULTIPLIER: Dict[str, int] = {
438
  "V25": 160, # FIXED: was 50 β†’ rejected, now 160 βœ“
439
- "V30_1s": 140, # smallest accepted from [140, 400, 700, 1000, 1400] βœ“
440
- "V50": 80, # FIXED: was 50 β†’ rejected (broker accepts 80,200,400,600,800), now 80 βœ“
441
  "V50_1s": 80, # FIXED: was 30 β†’ rejected, now 80 βœ“
442
  "V75": 50, # FIXED: was 30 β†’ rejected, now 50 βœ“
443
  "V75_1s": 50, # FIXED: was 20 β†’ rejected, now 50 βœ“
@@ -452,8 +444,6 @@ ASSET_MULTIPLIER: Dict[str, int] = {
452
  # ── Broker's acceptable multiplier ranges (for validation & future fallback) ──
453
  ASSET_ACCEPTABLE_MULTIPLIERS: Dict[str, List[int]] = {
454
  "V25": [160, 400, 800, 1200, 1600],
455
- "V30_1s": [140, 400, 700, 1000, 1400], # confirmed: 140 is lowest accepted
456
- "V50": [80, 200, 400, 600, 800], # FIXED: broker confirmed NOT [50,100,200,300,500]
457
  "V50_1s": [80, 200, 400, 600, 800],
458
  "V75": [50, 100, 200, 300, 500],
459
  "V75_1s": [50, 100, 200, 300, 500],
@@ -469,8 +459,6 @@ ASSET_ACCEPTABLE_MULTIPLIERS: Dict[str, List[int]] = {
469
  # e.g. 0.50 = close when $0.50 of the $1 stake is lost
470
  ASSET_STOP_LOSS_FRAC: Dict[str, float] = {
471
  "V25": 0.60,
472
- "V30_1s": 0.55,
473
- "V50": 0.55,
474
  "V50_1s": 0.55,
475
  "V75": 0.50,
476
  "V75_1s": 0.45,
@@ -485,8 +473,6 @@ ASSET_STOP_LOSS_FRAC: Dict[str, float] = {
485
  # Take-profit as fraction of stake (exit early when profit target hit)
486
  ASSET_TAKE_PROFIT_FRAC: Dict[str, float] = {
487
  "V25": 1.00,
488
- "V30_1s": 0.90,
489
- "V50": 0.90,
490
  "V50_1s": 0.90,
491
  "V75": 0.80,
492
  "V75_1s": 0.75,
@@ -4620,8 +4606,8 @@ def create_axrvi_v8(num_assets: int = 5,
4620
 
4621
  Example::
4622
 
4623
- model = create_axrvi_v8(num_assets=9, config=cfg, device="cpu")
4624
- out = model(sequences) # (1, 9, 20, 26)
4625
  loss = v8_total_loss(out, rank_t, returns, model.distributional.quantile_levels)
4626
  """
4627
  if config is None:
@@ -6813,9 +6799,9 @@ class QuasarAXRVIBridge:
6813
  reward_strategy: str = "simple",
6814
  hub_ws_url: str = os.environ.get("QUASAR_HUB_URL", "ws://localhost:7860/ws/subscribe"),
6815
  enable_logging: bool = True,
6816
- checkpoint_dir: str = "./Ranker8", # FIX: fresh folder
6817
- resume: bool = False, # FIX: fresh start
6818
- hf_repo_id: Optional[str] = "KarlQuant/k1rl-checkpoints", # HF Dataset repo
6819
  ):
6820
  self.config = config or AssetRankerConfig()
6821
  self.trade_config = trade_config or TradeConfig()
@@ -6825,7 +6811,7 @@ class QuasarAXRVIBridge:
6825
  # ── Checkpoint manager (local + optional HF sync) ─────────────────────
6826
  self.checkpoint_mgr = RankerCheckpointManager(
6827
  checkpoint_dir=checkpoint_dir,
6828
- hf_repo_id=hf_repo_id, # "KarlQuant/k1rl-checkpoints"
6829
  )
6830
  self.resume = resume
6831
 
@@ -8737,6 +8723,22 @@ class HFDatasetCheckpointManager:
8737
  def _hf_ckpt_path(self, step: int) -> str:
8738
  return f"step_{step:07d}.pt"
8739
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8740
  # ── Upload ─────────────────────────────────────────────────────────────────
8741
 
8742
  def upload(
@@ -8758,6 +8760,9 @@ class HFDatasetCheckpointManager:
8758
  if not self._ensure_hf():
8759
  return False
8760
 
 
 
 
8761
  local_path = Path(local_path)
8762
  if not local_path.exists():
8763
  logger.warning(f"☁️ HF upload skipped β€” file not found: {local_path}")
@@ -9078,7 +9083,7 @@ class RankerCheckpointManager:
9078
 
9079
  def __init__(
9080
  self,
9081
- checkpoint_dir: str = "./Ranker8",
9082
  hf_repo_id: Optional[str] = None,
9083
  ):
9084
  self.checkpoint_dir = checkpoint_dir
@@ -9245,10 +9250,12 @@ class RankerCheckpointManager:
9245
  def _build_checkpoint(self, bridge, step: int, reason: str) -> dict:
9246
  """Collect all live bridge state into a flat checkpoint dict."""
9247
  ckpt: dict = {
9248
- "version": "2.0",
9249
- "step": step,
9250
- "reason": reason,
9251
- "timestamp": datetime.now().isoformat(),
 
 
9252
  }
9253
 
9254
  # ── Model ─────────────────────────────────────────────────────────────
@@ -9306,22 +9313,48 @@ class RankerCheckpointManager:
9306
  # ── Validate critical keys ─────────────────────────────────────────────
9307
  assert "step" in ckpt, "Checkpoint missing 'step' key"
9308
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9309
  # ── Model ─────────────────────────────────────────────────────────────
9310
  if "axrvi_net" in ckpt and bridge.axrvi_net is not None:
9311
- incompatible = bridge.axrvi_net.load_state_dict(ckpt["axrvi_net"], strict=False)
9312
- if incompatible.missing_keys:
9313
- logger.warning(f"[Restore] axrvi_net missing keys: {incompatible.missing_keys}")
9314
- if incompatible.unexpected_keys:
9315
- logger.warning(f"[Restore] axrvi_net unexpected keys: {incompatible.unexpected_keys}")
9316
- logger.info(" βœ… axrvi_net restored")
 
 
 
9317
 
9318
  # ── Trainer ───────────────────────────────────────────────────────────
9319
  if bridge.trainer is not None:
9320
  tr = bridge.trainer
9321
- if "optimizer" in ckpt:
9322
- tr.optimizer.load_state_dict(ckpt["optimizer"])
9323
- if "scheduler" in ckpt:
9324
- tr.scheduler.load_state_dict(ckpt["scheduler"])
 
 
 
9325
  tr.train_step = ckpt.get("train_step", ckpt.get("step", tr.train_step))
9326
  tr.lambda_ce = ckpt.get("lambda_ce", tr.lambda_ce)
9327
  tr.lambda_ql = ckpt.get("lambda_ql", tr.lambda_ql)
@@ -10387,9 +10420,9 @@ async def run_live_trading_system(
10387
  hub_ws_url: str = "ws://localhost:7860/ws/subscribe",
10388
  enable_logging: bool = True,
10389
  shreve_config: Optional[ShreveConfig] = None,
10390
- checkpoint_dir: str = "./Ranker8",
10391
  resume: bool = False, # FIX: fresh start
10392
- hf_repo_id: Optional[str] = "KarlQuant/k1rl-checkpoints", # HF Dataset repo
10393
  ) -> None:
10394
  config = AssetRankerConfig(
10395
  asset_symbols = asset_symbols or list(ASSET_REGISTRY.keys()),
@@ -10701,12 +10734,12 @@ def _parse_args():
10701
  help="[S6/S8] Trade horizon Ο„ in seconds (default 60)")
10702
  parser.add_argument("--martingale-epsilon", type=float, default=0.05,
10703
  help="[S7] Gate E martingale deviation threshold (default 0.05)")
10704
- parser.add_argument("--checkpoint-dir", default="./Ranker8",
10705
- help="Directory for full-state checkpoints (default ./Ranker7)")
10706
  parser.add_argument("--no-resume", dest="no_resume", action="store_true", default=True,
10707
  help="Default True β€” always fresh start.")
10708
  parser.add_argument("--resume", dest="no_resume", action="store_false",
10709
- help="Restore from latest Ranker7 checkpoint")
10710
  parser.add_argument("--hf-repo", default=None,
10711
  metavar="OWNER/REPO",
10712
  help="Hugging Face Dataset repo for checkpoint sync "
@@ -10763,8 +10796,8 @@ if __name__ == "__main__":
10763
  hub_ws_url = args.hub,
10764
  enable_logging = not args.no_logs,
10765
  checkpoint_dir = args.checkpoint_dir,
10766
- resume = not args.no_resume, # default False β€” always start fresh on Ranker8
10767
- hf_repo_id = args.hf_repo or "KarlQuant/k1rl-checkpoints",
10768
  )
10769
 
10770
  try:
@@ -10786,8 +10819,8 @@ if __name__ == "__main__":
10786
  hub_ws_url = args.hub,
10787
  enable_logging = not args.no_logs,
10788
  checkpoint_dir = args.checkpoint_dir, # FIX 1: was silently ignored
10789
- resume = not args.no_resume, # FIX 2: default True (always resume)
10790
- hf_repo_id = args.hf_repo or "KarlQuant/k1rl-checkpoints",
10791
  ))
10792
  except KeyboardInterrupt:
10793
  print("\nπŸ‘‹ Shutting down…")
 
368
  # Deriv API symbol β†’ AXRVI internal symbol
369
  SYMBOL_MAP = {
370
  "R_25": "V25",
 
 
371
  "1HZ50V": "V50_1s",
372
  "R_75": "V75",
373
  "1HZ75V": "V75_1s",
 
396
  # Per-asset metadata: base volatility and max position fraction
397
  ASSET_REGISTRY: Dict[str, dict] = {
398
  "V25": {"symbol": "R_25", "base_vol": 25.0, "max_pos": 0.006},
 
 
399
  "V50_1s": {"symbol": "1HZ50V", "base_vol": 50.0, "max_pos": 0.004},
400
  "V75": {"symbol": "R_75", "base_vol": 75.0, "max_pos": 0.005},
401
  "V75_1s": {"symbol": "1HZ75V", "base_vol": 75.0, "max_pos": 0.003},
 
419
  #
420
  # Accepted ranges per Deriv broker:
421
  # V25 β€” [160, 400, 800, 1200, 1600] β†’ use 160
 
 
422
  # V50_1s β€” [80, 200, 400, 600, 800] β†’ use 80
423
  # V75 β€” [50, 100, 200, 300, 500] β†’ use 50
424
  # V75_1s β€” [50, 100, 200, 300, 500] β†’ use 50
 
430
  # STEP200 β€” [400, 1000, 2000, 3000, 4000] β†’ use 400
431
  ASSET_MULTIPLIER: Dict[str, int] = {
432
  "V25": 160, # FIXED: was 50 β†’ rejected, now 160 βœ“
 
 
433
  "V50_1s": 80, # FIXED: was 30 β†’ rejected, now 80 βœ“
434
  "V75": 50, # FIXED: was 30 β†’ rejected, now 50 βœ“
435
  "V75_1s": 50, # FIXED: was 20 β†’ rejected, now 50 βœ“
 
444
  # ── Broker's acceptable multiplier ranges (for validation & future fallback) ──
445
  ASSET_ACCEPTABLE_MULTIPLIERS: Dict[str, List[int]] = {
446
  "V25": [160, 400, 800, 1200, 1600],
 
 
447
  "V50_1s": [80, 200, 400, 600, 800],
448
  "V75": [50, 100, 200, 300, 500],
449
  "V75_1s": [50, 100, 200, 300, 500],
 
459
  # e.g. 0.50 = close when $0.50 of the $1 stake is lost
460
  ASSET_STOP_LOSS_FRAC: Dict[str, float] = {
461
  "V25": 0.60,
 
 
462
  "V50_1s": 0.55,
463
  "V75": 0.50,
464
  "V75_1s": 0.45,
 
473
  # Take-profit as fraction of stake (exit early when profit target hit)
474
  ASSET_TAKE_PROFIT_FRAC: Dict[str, float] = {
475
  "V25": 1.00,
 
 
476
  "V50_1s": 0.90,
477
  "V75": 0.80,
478
  "V75_1s": 0.75,
 
4606
 
4607
  Example::
4608
 
4609
+ model = create_axrvi_v8(num_assets=10, config=cfg, device="cpu")
4610
+ out = model(sequences) # (1, 10, 20, 26)
4611
  loss = v8_total_loss(out, rank_t, returns, model.distributional.quantile_levels)
4612
  """
4613
  if config is None:
 
6799
  reward_strategy: str = "simple",
6800
  hub_ws_url: str = os.environ.get("QUASAR_HUB_URL", "ws://localhost:7860/ws/subscribe"),
6801
  enable_logging: bool = True,
6802
+ checkpoint_dir: str = "./Ranker10", # new folder for 10-asset build
6803
+ resume: bool = False, # FIX: fresh start
6804
+ hf_repo_id: Optional[str] = "KarlQuant/quasar-axrvi-v10", # new HF repo (10 assets)
6805
  ):
6806
  self.config = config or AssetRankerConfig()
6807
  self.trade_config = trade_config or TradeConfig()
 
6811
  # ── Checkpoint manager (local + optional HF sync) ─────────────────────
6812
  self.checkpoint_mgr = RankerCheckpointManager(
6813
  checkpoint_dir=checkpoint_dir,
6814
+ hf_repo_id=hf_repo_id,
6815
  )
6816
  self.resume = resume
6817
 
 
8723
  def _hf_ckpt_path(self, step: int) -> str:
8724
  return f"step_{step:07d}.pt"
8725
 
8726
+ def _ensure_repo_exists(self) -> None:
8727
+ """Create the HF Dataset repo if it does not already exist. No-op if it exists."""
8728
+ if not self._ensure_hf():
8729
+ return
8730
+ try:
8731
+ self._hfapi.create_repo(
8732
+ repo_id = self.repo_id,
8733
+ repo_type = "dataset",
8734
+ exist_ok = True, # safe to call even if repo already exists
8735
+ private = True,
8736
+ )
8737
+ if self.verbose:
8738
+ logger.info(f"☁️ HF repo ready (created or already exists): {self.repo_id}")
8739
+ except Exception as exc:
8740
+ logger.warning(f"☁️ Could not ensure HF repo exists (non-fatal): {exc}")
8741
+
8742
  # ── Upload ─────────────────────────────────────────────────────────────────
8743
 
8744
  def upload(
 
8760
  if not self._ensure_hf():
8761
  return False
8762
 
8763
+ # Auto-create the repo if this is a new HF folder (no-op if it already exists)
8764
+ self._ensure_repo_exists()
8765
+
8766
  local_path = Path(local_path)
8767
  if not local_path.exists():
8768
  logger.warning(f"☁️ HF upload skipped β€” file not found: {local_path}")
 
9083
 
9084
  def __init__(
9085
  self,
9086
+ checkpoint_dir: str = "./Ranker10",
9087
  hf_repo_id: Optional[str] = None,
9088
  ):
9089
  self.checkpoint_dir = checkpoint_dir
 
9250
  def _build_checkpoint(self, bridge, step: int, reason: str) -> dict:
9251
  """Collect all live bridge state into a flat checkpoint dict."""
9252
  ckpt: dict = {
9253
+ "version": "2.1",
9254
+ "step": step,
9255
+ "reason": reason,
9256
+ "timestamp": datetime.now().isoformat(),
9257
+ "num_assets": bridge.axrvi_net.num_assets if bridge.axrvi_net is not None else 0,
9258
+ "asset_symbols": list(bridge.config.asset_symbols),
9259
  }
9260
 
9261
  # ── Model ─────────────────────────────────────────────────────────────
 
9313
  # ── Validate critical keys ─────────────────────────────────────────────
9314
  assert "step" in ckpt, "Checkpoint missing 'step' key"
9315
 
9316
+ # ── num_assets compatibility guard ────────────────────────────────────
9317
+ # If the checkpoint was saved with a different asset count (e.g. 12 before
9318
+ # V50/V30_1s were removed), the QCSAM/FABLE weight tensors will have the
9319
+ # wrong shape. We detect this early and skip model + optimizer weights so
9320
+ # the rest of the state (replay, bandit, counters) can still be restored.
9321
+ ckpt_num_assets = ckpt.get("num_assets", -1)
9322
+ current_num_assets = bridge.axrvi_net.num_assets if bridge.axrvi_net is not None else -1
9323
+ _model_compatible = True
9324
+
9325
+ if ckpt_num_assets != -1 and ckpt_num_assets != current_num_assets:
9326
+ ckpt_assets = ckpt.get("asset_symbols", "unknown")
9327
+ logger.warning(
9328
+ f"⚠️ [Restore] Asset count mismatch: checkpoint has {ckpt_num_assets} assets "
9329
+ f"({ckpt_assets}), but current model has {current_num_assets} assets "
9330
+ f"({list(bridge.config.asset_symbols)}). "
9331
+ f"Skipping axrvi_net + optimizer weights β€” model starts fresh. "
9332
+ f"All other state (replay, bandit, counters) will be restored."
9333
+ )
9334
+ _model_compatible = False
9335
+
9336
  # ── Model ─────────────────────────────────────────────────────────────
9337
  if "axrvi_net" in ckpt and bridge.axrvi_net is not None:
9338
+ if _model_compatible:
9339
+ incompatible = bridge.axrvi_net.load_state_dict(ckpt["axrvi_net"], strict=False)
9340
+ if incompatible.missing_keys:
9341
+ logger.warning(f"[Restore] axrvi_net missing keys: {incompatible.missing_keys}")
9342
+ if incompatible.unexpected_keys:
9343
+ logger.warning(f"[Restore] axrvi_net unexpected keys: {incompatible.unexpected_keys}")
9344
+ logger.info(" βœ… axrvi_net restored")
9345
+ else:
9346
+ logger.info(" ⏭️ axrvi_net skipped (asset count mismatch β€” fresh weights kept)")
9347
 
9348
  # ── Trainer ───────────────────────────────────────────────────────────
9349
  if bridge.trainer is not None:
9350
  tr = bridge.trainer
9351
+ if _model_compatible:
9352
+ if "optimizer" in ckpt:
9353
+ tr.optimizer.load_state_dict(ckpt["optimizer"])
9354
+ if "scheduler" in ckpt:
9355
+ tr.scheduler.load_state_dict(ckpt["scheduler"])
9356
+ else:
9357
+ logger.info(" ⏭️ optimizer/scheduler skipped (asset count mismatch β€” fresh state kept)")
9358
  tr.train_step = ckpt.get("train_step", ckpt.get("step", tr.train_step))
9359
  tr.lambda_ce = ckpt.get("lambda_ce", tr.lambda_ce)
9360
  tr.lambda_ql = ckpt.get("lambda_ql", tr.lambda_ql)
 
10420
  hub_ws_url: str = "ws://localhost:7860/ws/subscribe",
10421
  enable_logging: bool = True,
10422
  shreve_config: Optional[ShreveConfig] = None,
10423
+ checkpoint_dir: str = "./Ranker10",
10424
  resume: bool = False, # FIX: fresh start
10425
+ hf_repo_id: Optional[str] = "KarlQuant/quasar-axrvi-v10", # new HF repo (10 assets)
10426
  ) -> None:
10427
  config = AssetRankerConfig(
10428
  asset_symbols = asset_symbols or list(ASSET_REGISTRY.keys()),
 
10734
  help="[S6/S8] Trade horizon Ο„ in seconds (default 60)")
10735
  parser.add_argument("--martingale-epsilon", type=float, default=0.05,
10736
  help="[S7] Gate E martingale deviation threshold (default 0.05)")
10737
+ parser.add_argument("--checkpoint-dir", default="./Ranker10",
10738
+ help="Directory for full-state checkpoints (default ./Ranker10)")
10739
  parser.add_argument("--no-resume", dest="no_resume", action="store_true", default=True,
10740
  help="Default True β€” always fresh start.")
10741
  parser.add_argument("--resume", dest="no_resume", action="store_false",
10742
+ help="Restore from latest Ranker10 checkpoint")
10743
  parser.add_argument("--hf-repo", default=None,
10744
  metavar="OWNER/REPO",
10745
  help="Hugging Face Dataset repo for checkpoint sync "
 
10796
  hub_ws_url = args.hub,
10797
  enable_logging = not args.no_logs,
10798
  checkpoint_dir = args.checkpoint_dir,
10799
+ resume = not args.no_resume, # default False β€” always start fresh on Ranker10
10800
+ hf_repo_id = args.hf_repo or "KarlQuant/quasar-axrvi-v10",
10801
  )
10802
 
10803
  try:
 
10819
  hub_ws_url = args.hub,
10820
  enable_logging = not args.no_logs,
10821
  checkpoint_dir = args.checkpoint_dir, # FIX 1: was silently ignored
10822
+ resume = not args.no_resume, # FIX 2: default False (always fresh start)
10823
+ hf_repo_id = args.hf_repo or "KarlQuant/quasar-axrvi-v10",
10824
  ))
10825
  except KeyboardInterrupt:
10826
  print("\nπŸ‘‹ Shutting down…")