如何用 Python 做股价历史分位选股?(筛出处于历史低位的股票)

一句话回答: 股价历史分位就是"当前价格在过去 N 日价格区间里排第几(百分位) "。用 AlphaFeed 取全市场标的池 + klines.batch 批量日线,算每只票当前收盘价在近 N 日的百分位,筛出**低分位(如 ≤20%)**的股票,几十行就能扫出全市场处于历史低位的候选------但"低位"不等于"便宜"。

为什么会有这个问题 / 传统做法的痛点

"这只票是不是在历史低位"是很常见的问题,做成全市场选股要解决:

  • 全市场取数:先有全市场清单再批量取日线;
  • 分位口径:用"当前价 ≤ 窗口内价格的比例"衡量位置,比单看涨跌幅更直观;
  • 回看窗口:近 60 日、250 日(约一年)分位含义完全不同;
  • 复权:不用前复权,除权跳空会让历史价格错位。

AlphaFeed 用 universe + klines.batch 一次拿到全市场量价数据。

分步骤解决(每步配可运行代码)

第 1 步:定义价格分位

python 复制代码
def price_percentile(close, n=250):
    window = close.iloc[-n:]
    cur = close.iloc[-1]
    return float((window <= cur).mean() * 100)   # 当前价 ≤ 窗口内价格的比例(%)

分位选股参数:

参数 含义 常用取值
n 回看天数 250(约一年)、120、500
分位值 0~100,越小越低 ≤20 视为历史低位
高位阈值 接近前高 ≥80 视为历史高位
复权 用前复权收盘 adjust="forward"

第 2 步:批量计算并筛低位

python 复制代码
from alphafeed import AlphaFeed
import pandas as pd

af = AlphaFeed(api_key="your-api-key")  # 或 export ALPHAFEED_API_KEY 后 AlphaFeed()

def percentile_screen(symbols, count=250, n=250, thr=20.0):
    bt = af.klines.batch(symbols, period="1d", count=count,
                         adjust="forward", to_dataframe=True)
    rows = []
    for sym, df in bt.items():
        if df is None or len(df) < 60:
            continue
        d = df.sort_values("trade_date").reset_index(drop=True)
        p = price_percentile(d["close"], min(n, len(d)))
        rows.append({"symbol": sym, "pct": round(p, 1), "low_zone": p <= thr})
    res = pd.DataFrame(rows).sort_values("pct")     # 升序=最低位在前
    return res[res["low_zone"]] if not res.empty else res

第 3 步:全市场分批跑

python 复制代码
def run_full_market(n=250, thr=20.0):
    q = af.quotes.get(universes="CN_Stock", to_dataframe=True)
    symbols = q["symbol"].tolist()
    out = []
    for i in range(0, len(symbols), 150):     # 分批防限频
        out.append(percentile_screen(symbols[i:i + 150], n=n, thr=thr))
    return pd.concat([d for d in out if not d.empty], ignore_index=True).sort_values("pct")

# hits = run_full_market()
# print("历史低位只数:", len(hits)); print(hits.head(20))

小样本(10 只票)实测分位从约 0.4%(接近一年最低)到 95.6%(接近一年最高)不等,升序排名逻辑跑通;全市场同法按 150 只分批。

关键坑与注意事项

  • 低分位 ≠ 便宜/低估:分位只反映"价格在历史区间的相对位置",不代表估值便宜。持续下跌的股票会长期停在低分位(越跌越低),可能是价值陷阱。
  • 趋势下移问题:用价格分位而非估值分位时,基本面恶化的股票会不断创新低、分位始终很低,别把"跌不动"当"低估"。
  • 回看窗口敏感:60 日 vs 250 日分位差别大。短窗口反映近期位置、长窗口反映年度位置,固定口径。
  • 前复权 :一律 adjust="forward",否则除权跳空会让历史价格错位、分位失真。
  • 配合基本面/趋势:低分位宜与基本面、趋势企稳信号结合,别单看位置抄底。

常见问题(FAQ)

Q:分位和"距离最高点跌了多少"有什么区别?

A:回撤幅度只看和最高点的距离,分位则看当前价在整个历史分布中的位置,更能反映"多少时间价格比现在高/低",信息更丰富。

Q:为什么不用估值分位(如 PE 分位)?

A:估值分位需要基本面数据。本文用价格分位,只依赖行情,简单直观;若有 PE/PB 数据可做估值分位,逻辑相同。

Q:低分位股票能买吗?

A:不能只凭低分位买。它可能是超跌反弹机会,也可能是持续走弱的价值陷阱。需结合基本面、趋势和止损判断。

Q:需要付费吗?

A:少量标的的 K 线在免费额度内即可试;全市场 universe 取数需 Starter 及以上,详见 AlphaFeed 定价页。

小结

股价历史分位选股 = 全市场标的池 + 前复权日线 + 当前价在近 N 日的百分位 + 阈值筛选 。门槛在取数与口径(回看窗口、复权),AlphaFeed 用 universe + klines.batch 收敛掉,你几十行就能扫出全市场历史低位股------但请记住低分位 ≠ 便宜,趋势走弱的股票会长期低位,务必配合基本面与止损。

参考

相关推荐
倔强的石头1061 小时前
【Linux指南】动静态库系列(十一):PLT 与延迟绑定:第一次调用动态库函数时发生了什么
linux·人工智能·python
梦帮科技1 小时前
vLLM / TensorRT-LLM 极限推理:PagedAttention 细粒度物理页表管理与连续批处理(Continuous Batching)实战
数据结构·人工智能·分布式·python·深度学习·算法·vllm
殷色玫瑰1 小时前
C++入门基础复习:从命名空间到引用与nullptr,一篇重新捡回C++基础
java·开发语言·c++
(Charon)2 小时前
【C++面试】手写线程池:任务队列、工作线程与优雅退出
开发语言·c++
言乐62 小时前
Python概括后端原理
开发语言·python·django·virtualenv·pygame
Y3815326622 小时前
搜索 API 响应模块:featured_snippet、PAA 与 knowledge_graph 怎么用
python·搜索引擎
@大迁世界2 小时前
JEV RAG:更高效的 RAG 系统解决方案?
开发语言·rust
朝朝辞暮i3 小时前
C++ 第一阶段总结:从零基础到 ROS2 前置语法
开发语言·c++·算法
10年前端老司机3 小时前
实战分享:基于 PyMuPDF+Qwen-VL 实现图文兼容的 PDF RAG 方案
人工智能·python·agent