fix: validate scraper metric semantics
This commit is contained in:
@@ -114,8 +114,15 @@ def collect_onchain_history(progress_cb=None):
|
||||
|
||||
for metric_key, trace_name in cfg["traces"].items():
|
||||
if trace_name is None:
|
||||
# Grab first trace with numeric data
|
||||
for candidate in traces:
|
||||
if metric_key == "lth_supply":
|
||||
from scrapers.lookintobitcoin import _find_lth_supply_trace
|
||||
candidates = [_find_lth_supply_trace(traces)]
|
||||
else:
|
||||
candidates = traces
|
||||
# Grab the first validated trace with numeric data.
|
||||
for candidate in candidates:
|
||||
if not candidate:
|
||||
continue
|
||||
y = candidate.get("y", [])
|
||||
if y and any(v is not None for v in y[-10:]):
|
||||
dates, values = _extract_series(candidate)
|
||||
|
||||
@@ -115,6 +115,30 @@ def _find_trace(traces, name):
|
||||
return None
|
||||
|
||||
|
||||
def _trace_signal_is_active(trace):
|
||||
"""Return true only when the signal trace is active at its latest point."""
|
||||
if not trace:
|
||||
return False
|
||||
values = trace.get("y", [])
|
||||
if not values:
|
||||
return False
|
||||
latest = values[-1]
|
||||
try:
|
||||
return latest is not None and float(latest) != 0
|
||||
except (TypeError, ValueError):
|
||||
return bool(latest)
|
||||
|
||||
|
||||
def _find_lth_supply_trace(traces):
|
||||
"""Select an explicitly named LTH supply series and never a price fallback."""
|
||||
for trace in traces or []:
|
||||
name = str(trace.get("name", "")).lower()
|
||||
is_lth = "long-term holder" in name or "long term holder" in name or "lth" in name
|
||||
if is_lth and "supply" in name and "price" not in name:
|
||||
return trace
|
||||
return None
|
||||
|
||||
|
||||
def _get_latest_value(trace):
|
||||
"""Get the most recent non-null y value from a trace."""
|
||||
if not trace:
|
||||
@@ -210,21 +234,16 @@ def scrape_all():
|
||||
],
|
||||
"value": None,
|
||||
}
|
||||
# Try to detect buy signal from trace names/colors
|
||||
# A named signal trace is not itself proof that the signal is active.
|
||||
for t in traces:
|
||||
name = t.get("name", "").lower()
|
||||
if "buy" in name or "signal" in name:
|
||||
if ("buy" in name or "signal" in name) and _trace_signal_is_active(t):
|
||||
results[metric_key]["buy_signal"] = True
|
||||
break
|
||||
|
||||
elif metric_key == "lth_supply":
|
||||
# Get main supply trace
|
||||
t = traces[0] if traces else None
|
||||
for candidate in traces:
|
||||
name = candidate.get("name", "").lower()
|
||||
if "supply" in name or "lth" in name:
|
||||
t = candidate
|
||||
break
|
||||
# Require an explicitly named LTH supply trace; price is not supply.
|
||||
t = _find_lth_supply_trace(traces)
|
||||
recent = _get_recent_values(t, 60)
|
||||
# Determine trend: compare recent avg to older avg
|
||||
trend = None
|
||||
|
||||
Reference in New Issue
Block a user