知行多空线指标接入选股与事件回测;大盘总览走 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

@@ -60,10 +60,10 @@ def _d(v) -> str | None:
def _get_pro():
if not settings.tushare_token:
raise MarketOverviewError("未配置 TUSHARE_TOKEN无法获取大盘行情backend/.env")
import tushare as ts
# 走统一入口15000 积分档 token 只认 quicksync 镜像(直连 api.tushare.pro 会 40101
from .tushare_provider import get_pro
ts.set_token(settings.tushare_token)
return ts.pro_api()
return get_pro()
def _fetch_index_sync(pro, ts_code: str) -> pd.DataFrame:

View File

@@ -64,3 +64,13 @@ def ema2(close: pd.Series, span: int = 10) -> pd.Series:
def avg_ma(close: pd.Series, periods: tuple[int, ...] = (10, 20, 30, 60)) -> pd.Series:
"""知行多空线:(MA(M1)+MA(M2)+MA(M3)+MA(M4))/4。"""
return sum(ma(close, p) for p in periods) / len(periods)
def zhixing_dkx(close: pd.Series, m1: int = 14, m2: int = 28, m3: int = 57, m4: int = 114) -> pd.Series:
"""知行多空线(通达信口径):(MA(M1)+MA(M2)+MA(M3)+MA(M4))/4M1~M4 缺省 14/28/57/114。
MA 为严格窗口(窗口不满为 NaN任一为空则多空线为空与前端 zhixing.ts /
通达信原公式一致(前 m4-1 根无值);区别于 avg_ma 的 min_periods=1 渐进口径。
"""
mas = [close.rolling(p, min_periods=p).mean() for p in (m1, m2, m3, m4)]
return sum(mas) / len(mas)

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,7 +245,10 @@ async def _upsert_candle_day(session: AsyncSession, rows: list[dict], listed: se
]
if not batch:
return
stmt = pg_insert(Candle).values(batch)
# 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_={