功能更新

This commit is contained in:
2026-08-15 08:57:15 +08:00
parent 50fd032b45
commit c1c43d2ff7
30 changed files with 1908 additions and 888 deletions

View File

@@ -13,7 +13,7 @@ import re
import httpx
from ..config import settings
from ..schemas import ScreenConditions
from ..schemas import EventBacktestSpec, ScreenConditions
SYSTEM_PROMPT = """你是 A 股选股条件解析器。把用户的自然语言解析成一个 JSON 对象,只输出 JSON不要任何解释、注释或代码块围栏。完全无法理解时输出 {"error": "原因"}。
@@ -149,3 +149,69 @@ async def parse_conditions(text: str) -> ScreenConditions:
except Exception as e: # noqa: BLE001 —— JSON/校验失败,带错误重试
retry_error = str(e)[:300]
raise ScreenerError(f"AI 解析结果两次未通过校验,最后错误:{retry_error}")
# ---------- 事件回测解析(自然语言 -> EventBacktestSpec ----------
EVENT_SYSTEM_PROMPT = """你是 A 股事件回测参数解析器。用户描述一个「入场信号 + 买卖时机 + 持有期」的事件回测需求,把它解析成 JSON只输出 JSON不要任何解释或代码块围栏。完全无法理解时输出 {"error": "原因"}。
输出结构:
{"entry": {"indicator": [...], "snapshot": [], "exclude_st": true, "exclude_delisted": true, "exclude_bj": true}, "entry_timing": "next_open", "holding_days": 3, "exit_timing": "close"}
【entry.indicator 数组】入场信号条件(必填,至少 1 条),元素字段与白名单:
- "indicator": kdj_k / kdj_d / kdj_jKDJ 的 K/D/J 值、rsi、macd_dif / macd_dea / macd_histMACD 的 DIF/DEA/柱、ma收盘价均线、boll_upper / boll_mid / boll_lower布林轨道、close收盘价、pct_chg日涨跌幅%
- "params": 指标参数可选默认KDJ {"n":9,"m1":3,"m2":3}RSI {"period":14}MACD {"fast":12,"slow":26,"signal":9}MA {"period":20}BOLL {"period":20,"std":2}
- "op": "gt" | "ge" | "lt" | "le" | "between""value"between 时为下界)、"value2"(上界)
- "value_indicator": 指标与指标比较时填另一指标名(同白名单),如 "DIF 大于 DEA" -> indicator=macd_dif, op=gt, value_indicator=macd_dea, value=0
- "value_params": 比较对象指标参数不同时指定,如 "MA5 上穿 MA20" -> indicator=ma, params={"period":5}, op=gt, value_indicator=ma, value_params={"period":20}, value=0
- "lookback": 信号需连续/曾经满足的交易日窗口(默认 1
- "match": "all"(窗口内每天满足,默认)或 "any"(窗口内任一天满足)
【时间语义】"连续三天 J 小于 10" -> lookback=3, match="all""近 5 天曾经金叉" -> lookback=5, match="any"
【entry_timing】买入时机"第二天开盘购买/次日开盘买入" -> "next_open"(默认);"第二天收盘买入" -> "next_close"
【holding_days】买入后持有 N 个交易日int默认 3"未来三天的涨幅" -> holding_days=3"持有 10 天" -> 10"持有一个月" -> 20。
【exit_timing】到期卖出价"close"(收盘卖,默认)或 "open"(开盘卖)。
【entry.snapshot】截面过滤条件一般不适用于历史回测除非用户明确说"只回测市值大于 X 亿的股票"才填,其余情况留空数组。
示例:
输入:在连续三天 J 小于 10 的时候第二天开盘购买,之后未来三天的涨幅有多少
输出:{"entry":{"indicator":[{"indicator":"kdj_j","params":{"n":9,"m1":3,"m2":3},"op":"lt","value":10,"lookback":3,"match":"all"}],"snapshot":[],"exclude_st":true,"exclude_delisted":true,"exclude_bj":true},"entry_timing":"next_open","holding_days":3,"exit_timing":"close"}
示例:
输入RSI 低于 30 的第二天开盘买入持有 5 天收盘卖出
输出:{"entry":{"indicator":[{"indicator":"rsi","params":{"period":14},"op":"lt","value":30,"lookback":1,"match":"all"}],"snapshot":[],"exclude_st":true,"exclude_delisted":true,"exclude_bj":true},"entry_timing":"next_open","holding_days":5,"exit_timing":"close"}"""
def _build_event_messages(text: str, retry_error: str | None = None) -> list[dict]:
user = f"解析以下事件回测需求:{text}"
if retry_error:
user += f"\n\n上一次输出无法通过校验,错误:{retry_error}。请修正后重新只输出 JSON。"
return [{"role": "system", "content": EVENT_SYSTEM_PROMPT}, {"role": "user", "content": user}]
async def parse_event_spec(text: str) -> EventBacktestSpec:
"""自然语言 -> EventBacktestSpec。复用 _chat/_extract_json失败带错误重试 1 次。"""
if not settings.llm_api_key:
raise ScreenerError(
"未配置 LLM_API_KEY请在 backend/.env 填入 DeepSeek API Keyplatform.deepseek.com 获取)后重启后端"
)
retry_error: str | None = None
for _ in range(2):
content = await _chat(_build_event_messages(text, retry_error))
try:
obj = _extract_json(content)
if "error" in obj and not obj.get("entry"):
raise ScreenerError(f"AI 无法理解该回测需求:{obj['error']}")
spec = EventBacktestSpec.model_validate(obj)
if not spec.entry.indicator:
raise ValueError("entry.indicator 不能为空")
return spec
except ScreenerError:
raise
except Exception as e: # noqa: BLE001
retry_error = str(e)[:300]
raise ScreenerError(f"AI 解析回测参数两次未通过校验,最后错误:{retry_error}")