TradingAgents/orchestrator/signals.py

101 lines
2.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import logging
from dataclasses import dataclass, field
from datetime import datetime
from typing import Optional
logger = logging.getLogger(__name__)
@dataclass
class Signal:
ticker: str
direction: int # +1 买入, -1 卖出, 0 持有
confidence: float # 0.0 ~ 1.0
source: str # "quant" | "llm"
timestamp: datetime
metadata: dict = field(default_factory=dict) # 原始输出,用于调试
@dataclass
class FinalSignal:
ticker: str
direction: int # sign(quant_dir×quant_conf + llm_dir×llm_conf)sign(0)→0(HOLD)
confidence: float # abs(weighted_sum) / total_conf
quant_signal: Optional[Signal]
llm_signal: Optional[Signal]
timestamp: datetime
def _sign(x: float) -> int:
"""Return +1, -1, or 0."""
if x > 0:
return 1
elif x < 0:
return -1
return 0
class SignalMerger:
def merge(self, quant: Optional[Signal], llm: Optional[Signal]) -> FinalSignal:
now = datetime.utcnow()
# 两者均失败
if quant is None and llm is None:
ticker = ""
return FinalSignal(
ticker=ticker,
direction=0,
confidence=0.0,
quant_signal=None,
llm_signal=None,
timestamp=now,
)
ticker = (quant or llm).ticker # type: ignore[union-attr]
# 只有 LLMquant 失败)
if quant is None:
assert llm is not None
return FinalSignal(
ticker=ticker,
direction=llm.direction,
confidence=llm.confidence * 0.7,
quant_signal=None,
llm_signal=llm,
timestamp=now,
)
# 只有 Quantllm 失败)
if llm is None:
return FinalSignal(
ticker=ticker,
direction=quant.direction,
confidence=quant.confidence * 0.8,
quant_signal=quant,
llm_signal=None,
timestamp=now,
)
# 两者都有:加权合并
weighted_sum = (
quant.direction * quant.confidence
+ llm.direction * llm.confidence
)
final_direction = _sign(weighted_sum)
if final_direction == 0:
logger.info(
"SignalMerger: weighted_sum=0 for %s — signals cancel out, HOLD",
ticker,
)
total_conf = quant.confidence + llm.confidence
final_confidence = abs(weighted_sum) / total_conf if total_conf > 0 else 0.0
return FinalSignal(
ticker=ticker,
direction=final_direction,
confidence=final_confidence,
quant_signal=quant,
llm_signal=llm,
timestamp=now,
)