Fix manual refresh dropping qualified ranks and clarify trade UI.
Deploy / lint (push) Successful in 9s
Deploy / test (push) Successful in 1m20s
Deploy / deploy (push) Successful in 39s

Single-ticker fetch now attaches residual-momentum ranks so setups do not silently fail the activation gate. Exit plan is a timeline, chart labels move left of the price scale, and missing ranks surface explicitly.
This commit is contained in:
2026-07-14 10:10:30 +02:00
parent cd7dc7973c
commit 8db535b889
10 changed files with 468 additions and 94 deletions
+12 -1
View File
@@ -23,7 +23,10 @@ from app.models.ticker import Ticker
from app.models.user import User
from app.providers.alpaca import AlpacaOHLCVProvider
from app.providers.fundamentals_chain import build_fundamental_provider_chain
from app.services.rr_scanner_service import scan_ticker
from app.services.rr_scanner_service import (
resolve_activation_ranks_for_symbol,
scan_ticker,
)
from app.services.sentiment_provider_service import build_sentiment_provider
from app.schemas.common import APIEnvelope
from app.services import (
@@ -216,15 +219,23 @@ async def fetch_symbol(
sources_out["scores"] = {"status": "error", "message": str(exc)}
# --- Derived pipeline: scanner (free, always) ---
# Attach the same residual-momentum / strategy ranks the daily scan writes.
# Without them the new setup lands with null momentum_percentile and fails
# the activation gate (missing ranks do not qualify).
try:
ranks = await resolve_activation_ranks_for_symbol(db, symbol_upper)
setups = await scan_ticker(
db,
symbol_upper,
rr_threshold=settings.default_rr_threshold,
momentum_percentile=ranks.get("momentum_percentile"),
strategy_rank=ranks.get("strategy_rank"),
volatility_percentile=ranks.get("volatility_percentile"),
)
sources_out["scanner"] = {
"status": "ok",
"setups_found": len(setups),
"momentum_percentile": ranks.get("momentum_percentile"),
"message": None,
}
except Exception as exc: