Spaces:
Sleeping
Sleeping
Delete scorer.py
Browse files
scorer.py
DELETED
|
@@ -1,144 +0,0 @@
|
|
| 1 |
-
"""
|
| 2 |
-
scorer.py — Multi-factor scoring with regime confidence as 4th dimension.
|
| 3 |
-
|
| 4 |
-
Key fixes vs prior version:
|
| 5 |
-
- WEIGHT_CONFIDENCE (0.15) added as explicit 4th score axis
|
| 6 |
-
- Absorption hard-zeroes volume_score regardless of other signals
|
| 7 |
-
- Failed breakout penalty applied at scoring level (defence in depth)
|
| 8 |
-
- Structure score uses ADX to weight trend quality, not just HH/HL
|
| 9 |
-
- format_score_bar returns richer display with quality tier label
|
| 10 |
-
"""
|
| 11 |
-
|
| 12 |
-
from typing import Dict, Any, List, Tuple
|
| 13 |
-
|
| 14 |
-
import numpy as np
|
| 15 |
-
|
| 16 |
-
from config import (
|
| 17 |
-
WEIGHT_REGIME,
|
| 18 |
-
WEIGHT_VOLUME,
|
| 19 |
-
WEIGHT_STRUCTURE,
|
| 20 |
-
WEIGHT_CONFIDENCE,
|
| 21 |
-
ADX_TREND_THRESHOLD,
|
| 22 |
-
ADX_STRONG_THRESHOLD,
|
| 23 |
-
REGIME_CONFIDENCE_MIN,
|
| 24 |
-
)
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
def compute_structure_score(regime_data: Dict[str, Any]) -> float:
|
| 28 |
-
trend = regime_data.get("trend", "ranging")
|
| 29 |
-
structure = regime_data.get("structure", 0)
|
| 30 |
-
vol_expanding = regime_data.get("vol_expanding", False)
|
| 31 |
-
vol_contracting = regime_data.get("vol_contracting", False)
|
| 32 |
-
adx = regime_data.get("adx", 0.0)
|
| 33 |
-
vol_expanding_from_base = regime_data.get("vol_expanding_from_base", False)
|
| 34 |
-
|
| 35 |
-
if trend == "bullish":
|
| 36 |
-
base = 0.75
|
| 37 |
-
elif trend == "ranging":
|
| 38 |
-
base = 0.35
|
| 39 |
-
else:
|
| 40 |
-
base = 0.10
|
| 41 |
-
|
| 42 |
-
# ADX quality modifier
|
| 43 |
-
if adx >= ADX_STRONG_THRESHOLD:
|
| 44 |
-
base = min(1.0, base + 0.15)
|
| 45 |
-
elif adx < ADX_TREND_THRESHOLD:
|
| 46 |
-
base = max(0.0, base - 0.20)
|
| 47 |
-
|
| 48 |
-
# Structure alignment
|
| 49 |
-
if structure == 1 and trend == "bullish":
|
| 50 |
-
base = min(1.0, base + 0.12)
|
| 51 |
-
elif structure == -1 and trend == "bullish":
|
| 52 |
-
base = max(0.0, base - 0.20)
|
| 53 |
-
elif structure == -1 and trend == "bearish":
|
| 54 |
-
base = min(1.0, base + 0.12)
|
| 55 |
-
|
| 56 |
-
# Volatility context
|
| 57 |
-
if vol_expanding_from_base:
|
| 58 |
-
base = min(1.0, base + 0.08)
|
| 59 |
-
if vol_expanding and not vol_expanding_from_base:
|
| 60 |
-
base = max(0.0, base - 0.10)
|
| 61 |
-
if vol_contracting:
|
| 62 |
-
base = max(0.0, base - 0.05)
|
| 63 |
-
|
| 64 |
-
return float(np.clip(base, 0.0, 1.0))
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
def score_token(
|
| 68 |
-
regime_data: Dict[str, Any],
|
| 69 |
-
volume_data: Dict[str, Any],
|
| 70 |
-
vetoed: bool,
|
| 71 |
-
) -> Dict[str, float]:
|
| 72 |
-
if vetoed:
|
| 73 |
-
return {
|
| 74 |
-
"regime_score": 0.0,
|
| 75 |
-
"volume_score": 0.0,
|
| 76 |
-
"structure_score": 0.0,
|
| 77 |
-
"confidence_score": 0.0,
|
| 78 |
-
"total_score": 0.0,
|
| 79 |
-
}
|
| 80 |
-
|
| 81 |
-
regime_score = float(np.clip(regime_data.get("regime_score", 0.0), 0.0, 1.0))
|
| 82 |
-
confidence_score = float(np.clip(regime_data.get("regime_confidence", 0.0), 0.0, 1.0))
|
| 83 |
-
structure_score = compute_structure_score(regime_data)
|
| 84 |
-
|
| 85 |
-
raw_volume_score = float(np.clip(volume_data.get("volume_score", 0.0), 0.0, 1.0))
|
| 86 |
-
|
| 87 |
-
# Absorption hard-zeroes the volume signal regardless of other factors
|
| 88 |
-
if volume_data.get("absorption", False):
|
| 89 |
-
volume_score = 0.0
|
| 90 |
-
elif volume_data.get("failed_breakout", False):
|
| 91 |
-
# Failed breakout halves the volume score
|
| 92 |
-
volume_score = raw_volume_score * 0.5
|
| 93 |
-
else:
|
| 94 |
-
volume_score = raw_volume_score
|
| 95 |
-
|
| 96 |
-
# Climax penalty (not a veto here — defence in depth after veto layer)
|
| 97 |
-
if volume_data.get("climax", False):
|
| 98 |
-
volume_score = min(volume_score, 0.30)
|
| 99 |
-
|
| 100 |
-
total_score = (
|
| 101 |
-
regime_score * WEIGHT_REGIME
|
| 102 |
-
+ volume_score * WEIGHT_VOLUME
|
| 103 |
-
+ structure_score * WEIGHT_STRUCTURE
|
| 104 |
-
+ confidence_score * WEIGHT_CONFIDENCE
|
| 105 |
-
)
|
| 106 |
-
|
| 107 |
-
# Confidence multiplier: low confidence compresses total score
|
| 108 |
-
if confidence_score < REGIME_CONFIDENCE_MIN:
|
| 109 |
-
total_score *= confidence_score / REGIME_CONFIDENCE_MIN
|
| 110 |
-
|
| 111 |
-
return {
|
| 112 |
-
"regime_score": round(regime_score, 4),
|
| 113 |
-
"volume_score": round(volume_score, 4),
|
| 114 |
-
"structure_score": round(structure_score, 4),
|
| 115 |
-
"confidence_score": round(confidence_score, 4),
|
| 116 |
-
"total_score": round(float(np.clip(total_score, 0.0, 1.0)), 4),
|
| 117 |
-
}
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
def rank_tokens(scored_map: Dict[str, Dict[str, Any]]) -> List[Tuple[str, Dict[str, Any]]]:
|
| 121 |
-
return sorted(
|
| 122 |
-
scored_map.items(),
|
| 123 |
-
key=lambda item: item[1].get("total_score", 0.0),
|
| 124 |
-
reverse=True,
|
| 125 |
-
)
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
def quality_tier(score: float) -> str:
|
| 129 |
-
if score >= 0.80:
|
| 130 |
-
return "A+"
|
| 131 |
-
if score >= 0.65:
|
| 132 |
-
return "A"
|
| 133 |
-
if score >= 0.50:
|
| 134 |
-
return "B"
|
| 135 |
-
if score >= 0.35:
|
| 136 |
-
return "C"
|
| 137 |
-
return "D"
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
def format_score_bar(score: float, width: int = 18) -> str:
|
| 141 |
-
filled = int(round(score * width))
|
| 142 |
-
bar = "█" * filled + "░" * (width - filled)
|
| 143 |
-
tier = quality_tier(score)
|
| 144 |
-
return f"[{bar}] {score:.3f} ({tier})"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|