fix(orchestrator): code quality fixes in config and signals
- config: remove hardcoded absolute path for quant_backtest_path (now empty string) - config: add llm_solo_penalty (0.7) and quant_solo_penalty (0.8) fields - signals: SignalMerger now accepts OrchestratorConfig in __init__ - signals: use config.llm_solo_penalty / quant_solo_penalty instead of magic numbers - signals: apply quant_weight_cap / llm_weight_cap as confidence upper bounds - signals: both-None branch raises ValueError instead of returning ticker="" - signals: replace assert with explicit ValueError for llm-None-when-quant-None - signals: replace datetime.utcnow() with datetime.now(timezone.utc)
This commit is contained in:
parent
56dc76d44a
commit
dacb3316fa
|
|
@ -3,9 +3,12 @@ from dataclasses import dataclass, field
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class OrchestratorConfig:
|
class OrchestratorConfig:
|
||||||
quant_backtest_path: str = "/Users/chenshaojie/Downloads/quant_backtest"
|
# Must be set to the local quant backtest output directory before use
|
||||||
|
quant_backtest_path: str = ""
|
||||||
trading_agents_config: dict = field(default_factory=dict)
|
trading_agents_config: dict = field(default_factory=dict)
|
||||||
quant_weight_cap: float = 0.8 # quant 置信度上限
|
quant_weight_cap: float = 0.8 # quant 置信度上限
|
||||||
llm_weight_cap: float = 0.9 # llm 置信度上限
|
llm_weight_cap: float = 0.9 # llm 置信度上限
|
||||||
llm_batch_days: int = 7 # LLM 每隔几天运行一次(节省 API)
|
llm_batch_days: int = 7 # LLM 每隔几天运行一次(节省 API)
|
||||||
cache_dir: str = "orchestrator/cache" # LLM 信号缓存目录
|
cache_dir: str = "orchestrator/cache" # LLM 信号缓存目录
|
||||||
|
llm_solo_penalty: float = 0.7 # LLM 单轨时的置信度折扣
|
||||||
|
quant_solo_penalty: float = 0.8 # Quant 单轨时的置信度折扣
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,10 @@
|
||||||
import logging
|
import logging
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from datetime import datetime
|
from datetime import datetime, timezone
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
from orchestrator.config import OrchestratorConfig
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -36,30 +38,27 @@ def _sign(x: float) -> int:
|
||||||
|
|
||||||
|
|
||||||
class SignalMerger:
|
class SignalMerger:
|
||||||
|
def __init__(self, config: OrchestratorConfig) -> None:
|
||||||
|
self._config = config
|
||||||
|
|
||||||
def merge(self, quant: Optional[Signal], llm: Optional[Signal]) -> FinalSignal:
|
def merge(self, quant: Optional[Signal], llm: Optional[Signal]) -> FinalSignal:
|
||||||
now = datetime.utcnow()
|
now = datetime.now(timezone.utc)
|
||||||
|
|
||||||
# 两者均失败
|
# 两者均失败
|
||||||
if quant is None and llm is None:
|
if quant is None and llm is None:
|
||||||
ticker = ""
|
raise ValueError("both quant and llm signals are None")
|
||||||
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]
|
ticker = (quant or llm).ticker # type: ignore[union-attr]
|
||||||
|
|
||||||
# 只有 LLM(quant 失败)
|
# 只有 LLM(quant 失败)
|
||||||
if quant is None:
|
if quant is None:
|
||||||
assert llm is not None
|
if llm is None:
|
||||||
|
raise ValueError("llm signal is None when quant is None")
|
||||||
return FinalSignal(
|
return FinalSignal(
|
||||||
ticker=ticker,
|
ticker=ticker,
|
||||||
direction=llm.direction,
|
direction=llm.direction,
|
||||||
confidence=llm.confidence * 0.7,
|
confidence=min(llm.confidence * self._config.llm_solo_penalty,
|
||||||
|
self._config.llm_weight_cap),
|
||||||
quant_signal=None,
|
quant_signal=None,
|
||||||
llm_signal=llm,
|
llm_signal=llm,
|
||||||
timestamp=now,
|
timestamp=now,
|
||||||
|
|
@ -70,7 +69,8 @@ class SignalMerger:
|
||||||
return FinalSignal(
|
return FinalSignal(
|
||||||
ticker=ticker,
|
ticker=ticker,
|
||||||
direction=quant.direction,
|
direction=quant.direction,
|
||||||
confidence=quant.confidence * 0.8,
|
confidence=min(quant.confidence * self._config.quant_solo_penalty,
|
||||||
|
self._config.quant_weight_cap),
|
||||||
quant_signal=quant,
|
quant_signal=quant,
|
||||||
llm_signal=None,
|
llm_signal=None,
|
||||||
timestamp=now,
|
timestamp=now,
|
||||||
|
|
@ -88,7 +88,9 @@ class SignalMerger:
|
||||||
ticker,
|
ticker,
|
||||||
)
|
)
|
||||||
total_conf = quant.confidence + llm.confidence
|
total_conf = quant.confidence + llm.confidence
|
||||||
final_confidence = abs(weighted_sum) / total_conf if total_conf > 0 else 0.0
|
raw_confidence = abs(weighted_sum) / total_conf if total_conf > 0 else 0.0
|
||||||
|
final_confidence = min(raw_confidence, self._config.quant_weight_cap,
|
||||||
|
self._config.llm_weight_cap)
|
||||||
|
|
||||||
return FinalSignal(
|
return FinalSignal(
|
||||||
ticker=ticker,
|
ticker=ticker,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue