Serve live recommendation context on trade setup APIs and alerts
Stored TradeSetup rows are point-in-time snapshots from the RR scan, so
the ticker page could show stale confidence/reasoning/composite (e.g.
sentiment=neutral in the setup card while the sentiment panel showed
bullish). Overlay current score/sentiment context onto the API payload
for GET /trades and GET /trades/{symbol}, gate and format Telegram
qualified-setup alerts on the same live values, and apply the
min_confidence/recommended_action filters after the overlay so they
judge what the caller actually sees. Stored setups stay frozen for
outcome analysis and backtests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -524,6 +524,56 @@ def _build_reasoning(
|
||||
)
|
||||
|
||||
|
||||
def build_recommendation_snapshot(
|
||||
dimension_scores: dict[str, float],
|
||||
sentiment_classification: str | None,
|
||||
config: dict[str, float],
|
||||
available_directions: set[str] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Build the ticker-level recommendation from the supplied live context."""
|
||||
conflicts = signal_conflict_detector.detect_conflicts(
|
||||
dimension_scores=dimension_scores,
|
||||
sentiment_classification=sentiment_classification,
|
||||
config=config,
|
||||
)
|
||||
|
||||
long_confidence = direction_analyzer.calculate_confidence(
|
||||
direction="long",
|
||||
dimension_scores=dimension_scores,
|
||||
sentiment_classification=sentiment_classification,
|
||||
conflicts=conflicts,
|
||||
)
|
||||
short_confidence = direction_analyzer.calculate_confidence(
|
||||
direction="short",
|
||||
dimension_scores=dimension_scores,
|
||||
sentiment_classification=sentiment_classification,
|
||||
conflicts=conflicts,
|
||||
)
|
||||
|
||||
action = _choose_recommended_action(
|
||||
long_confidence, short_confidence, config, available_directions
|
||||
)
|
||||
reasoning = _build_reasoning(
|
||||
action=action,
|
||||
long_confidence=long_confidence,
|
||||
short_confidence=short_confidence,
|
||||
conflicts=conflicts,
|
||||
dimension_scores=dimension_scores,
|
||||
sentiment_classification=sentiment_classification,
|
||||
config=config,
|
||||
available_directions=available_directions,
|
||||
)
|
||||
|
||||
return {
|
||||
"action": action,
|
||||
"reasoning": reasoning,
|
||||
"risk_level": _risk_level_from_conflicts(conflicts),
|
||||
"long_confidence": long_confidence,
|
||||
"short_confidence": short_confidence,
|
||||
"conflicts": conflicts,
|
||||
}
|
||||
|
||||
|
||||
PRIMARY_TARGET_MIN_RR = 1.5
|
||||
|
||||
|
||||
@@ -559,24 +609,15 @@ async def enhance_trade_setup(
|
||||
) -> TradeSetup:
|
||||
config = await get_recommendation_config(db)
|
||||
|
||||
conflicts = signal_conflict_detector.detect_conflicts(
|
||||
snapshot = build_recommendation_snapshot(
|
||||
dimension_scores=dimension_scores,
|
||||
sentiment_classification=sentiment_classification,
|
||||
config=config,
|
||||
available_directions=available_directions,
|
||||
)
|
||||
|
||||
long_confidence = direction_analyzer.calculate_confidence(
|
||||
direction="long",
|
||||
dimension_scores=dimension_scores,
|
||||
sentiment_classification=sentiment_classification,
|
||||
conflicts=conflicts,
|
||||
)
|
||||
short_confidence = direction_analyzer.calculate_confidence(
|
||||
direction="short",
|
||||
dimension_scores=dimension_scores,
|
||||
sentiment_classification=sentiment_classification,
|
||||
conflicts=conflicts,
|
||||
)
|
||||
conflicts = list(snapshot["conflicts"])
|
||||
long_confidence = float(snapshot["long_confidence"])
|
||||
short_confidence = float(snapshot["short_confidence"])
|
||||
|
||||
direction = setup.direction.lower()
|
||||
confidence = long_confidence if direction == "long" else short_confidence
|
||||
@@ -622,19 +663,8 @@ async def enhance_trade_setup(
|
||||
|
||||
# Action and reasoning are ticker-level: they consider both directions and
|
||||
# which directions are actually tradeable, and are identical on every setup.
|
||||
action = _choose_recommended_action(
|
||||
long_confidence, short_confidence, config, available_directions
|
||||
)
|
||||
reasoning = _build_reasoning(
|
||||
action=action,
|
||||
long_confidence=long_confidence,
|
||||
short_confidence=short_confidence,
|
||||
conflicts=conflicts,
|
||||
dimension_scores=dimension_scores,
|
||||
sentiment_classification=sentiment_classification,
|
||||
config=config,
|
||||
available_directions=available_directions,
|
||||
)
|
||||
action = str(snapshot["action"])
|
||||
reasoning = str(snapshot["reasoning"])
|
||||
|
||||
setup.confidence_score = round(confidence, 2)
|
||||
setup.targets_json = json.dumps(targets)
|
||||
|
||||
Reference in New Issue
Block a user