feat(s6): AlphaAssetSelector bucket-ban kwargs (BLUE no-op)
Add `asset_bucket_ban_set` and `asset_bucket_assignments` kwargs to AlphaAssetSelector.__init__ (both default None → BLUE unchanged). When active, assets whose KMeans bucket is in the ban set are skipped inside rank_assets() so the next-ranked asset takes the slot — capital is preserved rather than wasted by a 0× sizer multiplier. Plan ref: Task 9 — ban ≠ 0× is the critical caveat from the sprint plan. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,7 @@ import math
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
from numba import njit
|
from numba import njit
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import Dict, List, Optional, Tuple
|
from typing import Dict, List, Optional, Set, Tuple
|
||||||
|
|
||||||
|
|
||||||
# ── Constants (matching dolphin_vbt_real.py lines 104-115) ────────────────────
|
# ── Constants (matching dolphin_vbt_real.py lines 104-115) ────────────────────
|
||||||
@@ -195,9 +195,13 @@ class AlphaAssetSelector:
|
|||||||
self,
|
self,
|
||||||
lookback_horizon: int = IRP_LOOKBACK,
|
lookback_horizon: int = IRP_LOOKBACK,
|
||||||
ars_weights: Optional[List[float]] = None,
|
ars_weights: Optional[List[float]] = None,
|
||||||
|
asset_bucket_ban_set: Optional[Set[int]] = None,
|
||||||
|
asset_bucket_assignments: Optional[Dict[str, int]] = None,
|
||||||
):
|
):
|
||||||
self.H = lookback_horizon
|
self.H = lookback_horizon
|
||||||
self.weights = ars_weights or ARS_WEIGHTS
|
self.weights = ars_weights or ARS_WEIGHTS
|
||||||
|
self.asset_bucket_ban_set = asset_bucket_ban_set
|
||||||
|
self.asset_bucket_assignments = asset_bucket_assignments or {}
|
||||||
|
|
||||||
def rank_assets(
|
def rank_assets(
|
||||||
self,
|
self,
|
||||||
@@ -236,6 +240,15 @@ class AlphaAssetSelector:
|
|||||||
best_eff = valid[ri, 4]
|
best_eff = valid[ri, 4]
|
||||||
|
|
||||||
asset = asset_names[asset_idx]
|
asset = asset_names[asset_idx]
|
||||||
|
|
||||||
|
# GREEN-only bucket-ban filter. BLUE passes None → no-op.
|
||||||
|
# Skips banned-bucket assets so the next-ranked asset takes the slot
|
||||||
|
# (preserves capital; a sizer 0× would waste the slot).
|
||||||
|
if self.asset_bucket_ban_set:
|
||||||
|
bkt = self.asset_bucket_assignments.get(asset)
|
||||||
|
if bkt is not None and bkt in self.asset_bucket_ban_set:
|
||||||
|
continue
|
||||||
|
|
||||||
action = "SHORT" if trade_dir == -1 else "LONG"
|
action = "SHORT" if trade_dir == -1 else "LONG"
|
||||||
orientation = "DIRECT" if trade_dir == regime_direction else "INVERSE"
|
orientation = "DIRECT" if trade_dir == regime_direction else "INVERSE"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user