Files
stock/stock-html/docs/全景扫描算法梳理.md
freedakgmail 9c7d7abdd4 Initial commit
2026-07-17 18:49:35 +08:00

10 KiB
Raw Permalink Blame History

全景扫描算法梳理

一、整体流程

全景扫描是对全市场股票做一次技术信号全量检测,结果写入 stock_signal_scan 表,供前端「全景扫描」页、策略建议、提醒、模拟交易等使用。

1.1 触发方式

方式 说明
用户点击 前端「全景扫描」按钮 → 后台执行 full_signal_scan.py(可选)
定时任务 crontab 配置,如 11:50、16:30 或凌晨 01:000 1 * * 1-5
管理员 管理后台「启动全景扫描」触发

1.2 入口与脚本

  • 脚本full_signal_scan.py
  • 扫描日期scan_date = date.today(),支持按日断点续扫
  • 环境变量FORCE_RESCAN=1 时先清空当日 stock_signal_scan 再扫

1.3 数据源

数据类型 来源 说明
股票列表 stock_realtime_price SELECT code, name ORDER BY code,全市场
K 线 多级回退 见下文「K 线获取顺序」
结果存储 stock_signal_scan 不写价格;现价由 stock_realtime_price 等更新

K 线获取顺序get_kline_data()):

  1. 本地 DBget_kline_from_local_db_threaded(code, days)stock_kline_daily
  2. 阿里云 K 线 API:北交所跳过
  3. 腾讯 K 线 API:全市场(含北交所)
  4. 麦蕊智数get_kline(period='d', days=120)
  5. AKSharestock_zh_a_hist 日 K

取数长度:K_DAYS = 120 日。


二、单只股票扫描流程

对每只待扫描股票(pending = 全市场 - 当日已扫):

1. get_kline_data(code, days=120)  →  DataFrame (date, open, high, low, close, volume)
2. 若 df 为空或 len(df) < 30 → 跳过,记失败
3. detect_all_signals(df, lookback=LOOKBACK)  →  7 个信号 + 指标 + signal_status
4. 汇总 triggered_count、signal_status、indicators、latest_signals
5. 写入内存缓冲;满 BATCH_SAVE_SIZE 条后批量 INSERT/UPDATE stock_signal_scan

并发与批参数full_signal_scan.py):

  • WORKERS = 8
  • BATCH_SIZE = 80(任务批)
  • BATCH_SAVE_SIZE = 40(每 40 条写一次库)
  • LOOKBACK = 5(检测最近 5 天内的信号)

三、核心算法:detect_all_signals

位置:services/signal_detector.pydetect_all_signals(df, lookback=5)

3.1 输入输出

  • 输入df 需含列 date, open, high, low, close, volumelookback 默认 5。
  • 输出
    signalslatest_signalssignal_summaryindicatorssignal_status(用于推荐与展示)。

3.2 内部步骤

  1. 列类型:必要列缺失则返回错误;对 open/high/low/close/volume 若非 float 则转成 float64。
  2. 指标计算calc_all_indicators(df),得到 MACD、SKDJ、KDJ、EMA、MA 等。
  3. 7 个信号检测(均在 lookback 窗口内):
    • detect_main_rising_wave(df, lookback)
    • detect_daily_bottom_divergence(df, lookback)
    • detect_dragon_head(df, lookback)
    • detect_true_dragon(df, lookback)
    • detect_short_bottom_divergence(df, lookback)
    • detect_rat_trading(df, lookback)
    • detect_rebound(df, lookback)
  4. 汇总
    • 所有信号按 (strength 降序, date) 排序;
    • latest_date 当天的信号为 latest_signals
    • 统计 signal_summary
    • 取最后一根 K 的指标 → indicatorsmacd/skdj/kdj/ema/ma);
    • _check_all_signal_status(df)signal_status(每条为 7 个信号的 triggered/description/readiness 等)。

全景扫描写库用的是 signal_statustriggered_countsignal_statustriggered==True 的个数),推荐与策略建议也用同一套 signal_status + compute_recommend


四、七个信号的判定条件(与 _check_all_signal_status 一致)

序号 信号名 强度 判定逻辑概要(当前 K / 最近窗口)
1 主升浪 85% DIF>0 且 DEA>0,且前一根 DIF≤DEA、当前 DIF>DEA(零上金叉)
2 日线底背离 80% 20 日内:收盘价在窗口新低附近(≤1.01×min);当前是窗口最低点;DIF 高于前低且 DIF<0
3 龙抬头 75% SKDJ 曾超跌(K<20 或 K<30)K 上穿 D;最近 3 根 K 的 K 值标准差<15(稳定)
4 真龙 70% 4 条件中≥3 且必须含「价格>MA20」:价格>MA20、MA5>MA20、MACD 翻红(柱>0)、放量(>10 日均量 1.2 倍)
5 短底背离 65% 10 日内:收盘在窗口新低附近;当前是窗口最低点;DIF 高于 10 日内 DIF 前低
6 老鼠仓 60% 盘中跌幅 (low-open)/open < -3%;回收率 (close-low)/(high-low) > 60%;收盘较开盘跌幅 > -1%;成交量 > 10 日均量 1.3 倍
7 反弹 55% EMA3 前根 ≤ EMA21,当前 EMA3 > EMA21(金叉)
  • detect_* 系列:在 lookback 天内逐日检测,若有满足条件的 K 线则生成一条信号(含 date/type/strength/description 等)。
  • _check_all_signal_status:只对最后一根 K 线判断 7 个信号是否「当前触发」,并给出描述与就绪度;全景扫描的「是否触发」以 signal_status[].triggered 为准。

五、结果落库与表结构

  • 表名stock_signal_scan
  • 写入字段code, name, scan_date, triggered_count, signal_status, indicators, latest_signals
  • 唯一约束(code, scan_date),重复写入时 ON CONFLICT DO UPDATE
  • 说明:脚本不写 stock_realtime_price;列表页现价、涨跌幅等来自该表或实时接口。

六、与推荐算法的一致性

  • 统一推荐函数services/stock_algorithms.compute_recommend(signal_status, indicators, triggered_count, is_holding)
    • 被「全景扫描结果列表」「策略建议」「提醒」「模拟交易自动买卖」共用。
  • 体系最强战法(suanfa.md)在推荐中的体现:
    • 日线底背离 → 纳入关注
    • 龙抬头 → 买入(核心买点)
    • 真龙/主升浪 → 持有/加仓
    • 不见主升浪 → 可出场(如 MACD 死叉且无主升浪 → 卖出)

即:全景扫描只负责「全量信号检测 + 落库」;「买/卖/加仓/持有/关注/观望」由同一套 compute_recommend 基于 signal_status 计算,保证与策略建议、提醒、模拟交易一致。


七、小结

项目 内容
入口 full_signal_scan.py,按日断点续扫
股票池 stock_realtime_price 全表 code+name
K 线 120 日,本地 DB → 阿里 → 腾讯 → 麦蕊 → AKShare
核心函数 detect_all_signals(df, lookback=5) → 7 信号 + signal_status
7 信号 主升浪(85%)、日线底背离(80%)、龙抬头(75%)、真龙(70%)、短底背离(65%)、老鼠仓(60%)、反弹(55%)
落库 stock_signal_scan,不写价格
推荐 与策略/提醒/模拟交易共用 compute_recommend(signal_status, ...)

如需调整「哪些算触发」,只需改 signal_detector.py 中对应 detect_*_check_all_signal_status;如需调整买卖建议,只需改 stock_algorithms.compute_recommend


八、全景扫描结果的「每日推荐买入」是如何获取的?

8.1 数据来源

  • 每日推荐依赖的是当日(或最近一次)全景扫描的结果表 stock_signal_scan
  • 若当天没有跑全量扫描,接口会自动回退到「最近一次有数据的 scan_date」(见 8.2)。

8.2 接口与参数

  • 接口GET /api/scan_resultsroutes/analysis.pyget_scan_results())。
  • 关键参数
    • date:扫描日期,默认当天;若该日无数据且未显式传 date,则用 MAX(scan_date) 回退。
    • recommend_text:推荐文案筛选,例如 买入加仓持有关注观察观望卖出
    • holding_codes:当前用户持仓 code 列表(逗号分隔),用于区分「持仓 / 非持仓」下的推荐。

8.3 「推荐买入」的获取流程(recommend_text=买入)

  1. 按日期取扫描数据
    stock_signal_scan 中取出 scan_date 当天的全部记录:
    code, signal_status, indicators, triggered_count

  2. 逐条计算推荐
    对每条记录调用统一推荐函数(_compute_recommendstock_algorithms.compute_recommend):

    _compute_recommend(signal_status, indicators, triggered_count, is_holding)
    
    • is_holding = (code in holding_codes)
      返回 (signal_type, display_text, reason, recommend_rate),其中 display_text 即「买入 / 加仓 / 持有 / 关注 / 观察 / 观望 / 卖出」。
  3. 筛选「买入」
    只保留 display_text == recommend_text(例如 display_text == '买入')的股票,得到「每日推荐买入」列表。

  4. 排序与分页
    triggered_count 降序、其次 code 升序排序;再按 pageper_page 分页,取当前页的 code 列表。

  5. 补全当前页展示数据
    用当前页的 code 再查 stock_signal_scan + stock_realtime_price,对每条再次调用 _compute_recommend,得到 recommend_textrecommend_reason、现价等,返回前端。

8.4 何时会得到「买入」?

compute_recommend(体系最强战法)决定,非持仓时出现「买入」的条件包括:

  • 最佳买入:日线底背离 + 龙抬头,且 MACD 未死叉 → display_text = '买入'(评分 95)。
  • 龙抬头买入:有龙抬头且 MACD 金叉或暂无数据 → display_text = '买入'(评分 80);若同时有主升浪且 MACD 正常 → 也是「买入」(评分 90)。
  • 若 MACD 死叉则会被降级为「关注」等,不会出现在「推荐买入」筛选中。

因此:「每日推荐买入」= 当日(或回退日)stock_signal_scan 中,在给定 holding_codes 下经 compute_recommend 计算得到 display_text == '买入' 的股票列表,经排序分页后返回。

8.5 与策略建议的关系

  • 策略建议GET /api/scan_strategy)同样读 stock_signal_scan 当日数据,对每条记录调用同一个 _compute_recommend,再按 display_text 分成 4 档(立即买入、持仓加仓、关注、纳入关注)。
  • 「立即买入」档即 display_text == '买入',与全景扫描里筛选 recommend_text=买入 的列表算法一致,只是接口与展示形式不同(一为分档统计,一为分页列表)。