- domain/entities/chart.py:ChartResult/OHLC/Volume/Series/EventMarker/ChartMetadata
(adjust_mode + execution_price_basis 口径元数据)+ SelectionHit
- application/services/chart_service.py:个股 K线/量/MA 指标;显示层 qfq/hfq 折算
(基于主口径 none 行情 × adjust_factor,绝回写研究数据);回测个股视图把实际成交
转 fills 标记并在显示口径不同时做坐标换算(v3 §20.3/§20.5)
- by-symbol 历史查询:SignalRepository/SelectionRepository.list_by_symbol(含溯源 id)
- api/charts.py:/stocks/{symbol}/chart|signals|selections、/backtests/{id}/stocks/{symbol}/chart
|trades|positions
- tests/test_charts.py(指标/qfq-hfq 折算断言/回测 fills/API 集成+404);全量 pytest 通过
69 lines
2.2 KiB
Python
69 lines
2.2 KiB
Python
"""交易信号领域实体(M8.1,v2 §15 Signal Engine)。
|
||
|
||
Signal 输入 = Selection 排序(score)+ 价格/技术条件 + 规则;输出事件可解释:
|
||
BUY / WATCH / SELL(破位警示),每条带 trigger_reason —— 回答
|
||
「某日为什么对该股票给 BUY/SELL」(v2 §8)。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from datetime import date, datetime
|
||
|
||
from pydantic import BaseModel, Field
|
||
|
||
|
||
class SignalRules(BaseModel):
|
||
"""规则(结构化,MVP):买入区间 + 趋势/动量条件 + 卖出/警示区间。"""
|
||
|
||
buy_rank_threshold: int = Field(default=20, ge=1, le=500, description="rank<=此值进入买入候选")
|
||
buy_require_trend: bool = Field(default=True, description="买入需 close > MA(trend_ma)")
|
||
buy_require_momentum: bool = Field(default=False, description="买入需 close > 20 日前 close")
|
||
trend_ma: int = Field(default=60, ge=10, le=250)
|
||
sell_rank_threshold: int = Field(default=50, ge=1, le=1000, description="rank>此值或破位 → SELL 警示")
|
||
sell_on_trend_break: bool = Field(default=True, description="买入区间内 close < MA(trend_ma) → SELL")
|
||
max_output_rank: int = Field(default=80, ge=1, le=2000, description="仅输出排名前 N 的信号")
|
||
|
||
|
||
class SignalEvent(BaseModel):
|
||
symbol: str
|
||
signal_date: date
|
||
signal_type: str = Field(pattern="^(BUY|WATCH|SELL)$")
|
||
score: float | None = None
|
||
price: float | None = None
|
||
trigger_reason: list[str] = Field(default_factory=list)
|
||
|
||
|
||
class SignalStatistics(BaseModel):
|
||
universe_size: int = 0
|
||
buy: int = 0
|
||
watch: int = 0
|
||
sell: int = 0
|
||
|
||
|
||
class SignalResult(BaseModel):
|
||
as_of_date: date
|
||
rules: SignalRules
|
||
statistics: SignalStatistics
|
||
events: list[SignalEvent] = Field(default_factory=list)
|
||
config_snapshot: dict = Field(default_factory=dict)
|
||
|
||
|
||
class SignalMeta(BaseModel):
|
||
id: str
|
||
as_of: date
|
||
buy: int = 0
|
||
watch: int = 0
|
||
sell: int = 0
|
||
created_at: datetime | None = None
|
||
|
||
|
||
class SignalHit(BaseModel):
|
||
"""个股在信号历史中的命中(by-symbol 查询,供 Chart 标记)。"""
|
||
|
||
signal_id: str
|
||
signal_date: date
|
||
signal_type: str
|
||
score: float | None = None
|
||
price: float | None = None
|
||
trigger_reason: list[str] = Field(default_factory=list)
|