知行多空线指标接入选股与事件回测;大盘总览走 quicksync 统一入口;candles 批量 upsert 分批防 asyncpg 参数超限

This commit is contained in:
2026-09-02 16:51:52 +08:00
parent 6ef8c585d6
commit bec4e8149c
5 changed files with 48 additions and 21 deletions

View File

@@ -59,6 +59,12 @@ def _boll(df: pd.DataFrame, p: dict) -> dict[str, pd.Series]:
return {"boll_upper": out["upper"], "boll_mid": out["mid"], "boll_lower": out["lower"]}
def _zhixing(df: pd.DataFrame, p: dict) -> dict[str, pd.Series]:
dk = ind.zhixing_dkx(df["close"], m1=int(p["m1"]), m2=int(p["m2"]),
m3=int(p["m3"]), m4=int(p["m4"]))
return {"zhixing_dkx": dk, "zhixing_trend": ind.ema2(df["close"])}
def _close(df: pd.DataFrame, p: dict) -> dict[str, pd.Series]:
return {"close": df["close"]}
@@ -82,6 +88,8 @@ FAMILIES: dict[str, FamilyDef] = {
"rsi": FamilyDef("RSI", ("period",), {"period": 14}, 25, _rsi),
"ma": FamilyDef("MA", ("period",), {"period": 20}, 25, _ma),
"boll": FamilyDef("BOLL", ("period", "std"), {"period": 20, "std": 2}, 25, _boll),
"zhixing": FamilyDef("知行", ("m1", "m2", "m3", "m4"),
{"m1": 14, "m2": 28, "m3": 57, "m4": 114}, 114, _zhixing),
"close": FamilyDef("收盘价", (), {}, 1, _close),
"pct_chg": FamilyDef("日涨跌幅", (), {}, 1, _pct_chg),
}
@@ -91,12 +99,14 @@ INDICATOR_FAMILY: dict[str, str] = {
"macd_dif": "macd", "macd_dea": "macd", "macd_hist": "macd",
"rsi": "rsi", "ma": "ma",
"boll_upper": "boll", "boll_mid": "boll", "boll_lower": "boll",
"zhixing_dkx": "zhixing", "zhixing_trend": "zhixing",
"close": "close", "pct_chg": "pct_chg",
}
_IND_SUFFIX = {"kdj_k": "K", "kdj_d": "D", "kdj_j": "J",
"macd_dif": "DIF", "macd_dea": "DEA", "macd_hist": "",
"boll_upper": "上轨", "boll_mid": "中轨", "boll_lower": "下轨"}
"boll_upper": "上轨", "boll_mid": "中轨", "boll_lower": "下轨",
"zhixing_dkx": "多空线", "zhixing_trend": "趋势线"}
def _family_of(indicator: str) -> str:

View File

@@ -22,8 +22,8 @@ SYSTEM_PROMPT = """你是 A 股选股条件解析器。把用户的自然语言
indicator 与 snapshot 至少一个非空;用户没有提到的条件不要编造)
【indicator 数组】技术指标条件,元素字段:
- "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}
- "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布林轨道zhixing_dkx知行多空线四条收盘价均线的均值、zhixing_trend知行短期趋势线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};知行多空线 {"m1":14,"m2":28,"m3":57,"m4":114}
- "op": "gt" | "ge" | "lt" | "le" | "between"
- "value": 比较数值between 时为下界),"value2": between 上界
- "value_indicator": 可选。指标与指标比较时填另一指标名(同白名单),如 "DIF大于DEA" -> indicator=macd_dif, op=gt, value_indicator=macd_dea, value=0"股价在布林带下轨之下" -> indicator=close, op=lt, value_indicator=boll_lower, value=0
@@ -53,7 +53,11 @@ SYSTEM_PROMPT = """你是 A 股选股条件解析器。把用户的自然语言
示例3
输入:近 5 天曾经 MACD 金叉DIF 上穿 DEA换手率大于 5%,流通市值小于 100 亿
输出:{"indicator":[{"indicator":"macd_dif","params":{"fast":12,"slow":26,"signal":9},"op":"gt","value":0,"value_indicator":"macd_dea","lookback":5,"match":"any"}],"snapshot":[{"field":"turnover_rate","op":"gt","value":5},{"field":"circ_mv","op":"lt","value":100}],"exclude_st":true,"exclude_delisted":true,"exclude_bj":true}"""
输出:{"indicator":[{"indicator":"macd_dif","params":{"fast":12,"slow":26,"signal":9},"op":"gt","value":0,"value_indicator":"macd_dea","lookback":5,"match":"any"}],"snapshot":[{"field":"turnover_rate","op":"gt","value":5},{"field":"circ_mv","op":"lt","value":100}],"exclude_st":true,"exclude_delisted":true,"exclude_bj":true}
示例4
输入:近一个月股价曾经站上知行多空线的股票
输出:{"indicator":[{"indicator":"close","op":"gt","value":0,"value_indicator":"zhixing_dkx","params":{"m1":14,"m2":28,"m3":57,"m4":114},"lookback":20,"match":"any"}],"exclude_st":true,"exclude_delisted":true,"exclude_bj":true}"""
class ScreenerError(RuntimeError):
@@ -159,8 +163,8 @@ EVENT_SYSTEM_PROMPT = """你是 A 股事件回测参数解析器。用户描述
{"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}
- "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布林轨道zhixing_dkx知行多空线、zhixing_trend知行短期趋势线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};知行多空线 {"m1":14,"m2":28,"m3":57,"m4":114}
- "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

View File

@@ -245,18 +245,21 @@ async def _upsert_candle_day(session: AsyncSession, rows: list[dict], listed: se
]
if not batch:
return
stmt = pg_insert(Candle).values(batch)
stmt = stmt.on_conflict_do_update(
index_elements=["symbol", "timeframe", "ts"],
set_={
"open": stmt.excluded.open, "high": stmt.excluded.high,
"low": stmt.excluded.low, "close": stmt.excluded.close,
"volume": stmt.excluded.volume,
"amount": func.coalesce(Candle.amount, stmt.excluded.amount),
},
)
await session.execute(stmt)
await session.commit()
# on_conflict 语句整批渲染为占位符(非 executemanyasyncpg 单语句参数上限 32766
# 10 列 x 3000 行 = 30000 参数留出余量
for i in range(0, len(batch), 3000):
stmt = pg_insert(Candle).values(batch[i : i + 3000])
stmt = stmt.on_conflict_do_update(
index_elements=["symbol", "timeframe", "ts"],
set_={
"open": stmt.excluded.open, "high": stmt.excluded.high,
"low": stmt.excluded.low, "close": stmt.excluded.close,
"volume": stmt.excluded.volume,
"amount": func.coalesce(Candle.amount, stmt.excluded.amount),
},
)
await session.execute(stmt)
await session.commit()
async def _run_sync(days: int, force: bool) -> None: