
daily_stock_analysis 这个名字说得很直白每天拉一次股票行情、算几个常用技术指标、按规则筛选再把结果整理成能看的报告。ZhuLinsen/daily_stock_analysis 这类仓库在 GitHub 上很常见核心就是把数据获取、指标计算、条件筛选、报表输出串成一条自动化链路。如果你正在找 Python 数据分析或定时任务练手项目它比单纯的“爬虫拉数据”多一层分析逻辑比完整量化回测框架又轻很多正好卡在中间。我建议先别急着 clone 下来就跑先想清楚它到底解决什么问题很多人手里有行情数据也有 pandas 基础但每天开盘前或收盘后都要重复做同样的事——拉数据、过滤无效股票、算指标、挑出符合条件的标的。daily_stock_analysis 就是把这段重复过程脚本化。下面按实际落地顺序拆开讲涉及数据链路、指标计算、筛选输出、定时调度和常见坑。先提醒一件事这类工具最大的价值是让重复工作自动化不是“算出一个能稳赚的信号”。技术指标本质上是对历史价格和成交量的数学描述不能保证预测未来。用工程化心态看它收获比单纯盯结果大得多。1. 先想清楚 daily_stock_analysis 的数据链路在做什么1.1 核心字段和处理对象任何日常股票分析脚本核心输入都是日线行情数据。最常见的一组字段包括字段含义常见用途date交易日期排序、按日期切片code股票代码区分标的name股票名称可读性、筛选 STopen / close开盘价 / 收盘价计算涨跌幅、K 线high / low最高价 / 最低价波动范围、ATR 等指标volume成交量量能判断amount成交额过滤流动性差的股票turnover换手率活跃度判断第一步不是写代码而是确认数据源能不能稳定返回这些字段。很多接口字段名不一致有的叫vol有的叫volume有的成交量单位是手有的是股。正确做法是先把返回数据打印一条样本确认字段、类型和单位再开始存库和分析。这个步骤省掉之后后面会在数据清洗上反复返工。1.2 数据范围决定项目复杂度分析范围通常有三种选择只分析自选股或指数代码量最少适合新手跑一遍只要几秒。分析某个板块或指数成分股数据量适中可以做横向对比。分析全市场 A 股最完整但数据量大、接口调用频繁、运行时间长还要处理停牌、新股、退市等特殊情况。我建议从第一种开始。先用三五只股票把整个链路跑通再逐步扩大范围。一上来就拉全市场报错时你很难判断是数据源问题、指标问题还是脚本逻辑问题。把变量控制住排错成本会低很多。1.3 数据源和存储方式怎么选国内常见的免费数据源有 akshare、tushare、baostock 等各有特点。选型时主要看三件事是否需要注册和 token单次能返回多少条数据、有没有频率限制返回的数据质量如何需不需要额外清洗。无论用哪个数据源我都会先把原始数据存到本地再分析。免费接口稳定性通常一般每天重复请求相同的历史数据既慢又容易被限流。落盘之后每天只需要增量拉取最新交易日的数据分析时直接从本地读取速度会快很多。存储方面小规模用 CSV 或 SQLite 就够了没必要为这个项目专门上 MySQL。注意数据源接口经常升级字段名和返回结构可能变化。把数据获取单独封装成一个模块以后迁移数据源时只需要改一个文件。2. 环境、依赖和目录结构跑之前先定好2.1 运行环境与依赖这类项目用 Python 最合适生态里数据分析、定时任务、图表输出都很成熟。常见环境是 Python 3.9 及以上版本配合这几个库pandas处理行情表格requests调用数据源 HTTP 接口schedule 或 APScheduler定时触发任务matplotlib画 K 线和指标图openpyxl导出 Excel。如果你在 Linux 服务器上跑需要注意中文字体问题画图时中文会变成方块。提前安装 wqy-zenhei 这类字体或者在 matplotlib 里指定中文字体路径。这个问题在 Windows 上不明显一上 Linux 就立刻暴露。2.2 目录结构可以参考这个不用一开始搞得很复杂但要有区分否则跑几天之后报表、日志、临时数据混在一起很难维护。daily_stock_analysis/ ├── config.py # 配置数据源、股票池、规则参数 ├── fetcher.py # 数据获取模块 ├── indicators.py # 技术指标计算模块 ├── screener.py # 筛选规则模块 ├── reporter.py # 报表输出模块 ├── scheduler.py # 定时调度入口 ├── data/ │ ├── raw/ # 原始行情 │ └── processed/ # 清洗后的数据 ├── reports/ # 每日输出 └── logs/ # 运行日志这个结构没有高深的地方核心是让每个环节可以单独测试。fetcher 可以单独跑indicators 可以单独验证screener 可以只针对本地数据运行。模块之间通过 DataFrame 传递接口保持简单。2.3 配置和参数单独放股票池、指标参数、筛选条件、输出路径不要写死在代码里。放一个 config.py 或 config.yaml每次调整只改配置。比如# config.py 示例实际参数按你的环境调整 STOCK_POOL [000001, 600519, 300750] INDICATORS { ma_window: [5, 10, 20, 60], rsi_window: 14, macd: {fast: 12, slow: 26, signal: 9}, } SCREEN_RULES { min_amount: 1e8, # 成交额下限单位元 exclude_st: True, # 是否排除 ST limit_up_limit: 0.095, # 接近涨停时忽略避免追不进 } OUTPUT_DIR reports为什么强调配置分离因为每天运行时会频繁调整筛选条件。如果每次都改代码很容易把正常功能改坏。配置独立之后分析逻辑和业务参数互不影响改起来也放心。3. 技术指标计算先做基础指标再谈花样3.1 从均线和涨跌幅开始指标里最基础的是均线 MA 和涨跌幅。pandas 里用滚动窗口就能算# 示例计算 5 日和 20 日均线 df[ma5] df[close].rolling(window5).mean() df[ma20] df[close].rolling(window20).mean() # 示例计算日涨跌幅 df[pct_change] df[close].pct_change() * 100这里有个容易忽略的点rolling窗口是从当前行往前数 N 行不是往后。如果数据顺序排反了计算出来的均线就是“未来函数”后面的筛选结果全都会错。计算之前先按日期升序排序算完再考虑要不要倒序展示。这是一个非常隐蔽但后果很严重的坑。3.2 MACD 和 RSI 的实现要点MACD 由快线 EMA12、慢线 EMA26、差离值 DIF 和信号线 DEA 组成最终得到柱状图。RSI 是相对强弱指标常见窗口是 14 天。这些指标 pandas 没有现成函数可以自己写也可以用 ta 库。自己写的好处是理解每一步在算什么不推荐无脑调库。实现时要注意EMA 带递推关系第一天的初始值会影响前几天的结果。一般会多拉一部分历史数据参与计算然后从中间截取结果避免起始数据不稳定带来的误差。这也是为什么不要只拉最近 30 天数据——算 MACD 时前面缺的样本会影响当前值。3.3 特别容易出错的边界情况新股上市不足 N 天rolling 窗口算出来是 NaN筛选时要跳过。停牌股票成交量可能为 0或者当天没有行情涨跌幅显示异常。ST 股票名称带 ST如果不打算纳入筛选需要按名称过滤。除权除息前后价格不连续复权因子要处理。免费数据源一般提供前复权或后复权接口分析时统一用一种方式不要混用。这些边界情况不会天天遇到但遇到一次就会让脚本崩溃或输出错误结果。稳妥做法是清洗阶段把 NaN 和异常值标记出来筛选阶段显式跳过而不是直接让代码崩。你可以在脚本开头加一个数据校验函数检查 DataFrame 是否为空、关键字段是否缺失、日期是否为最新交易日。校验不过就记录日志并退出不要继续往下算。注意本文所有指标计算都只针对历史行情的数据处理练习不构成任何投资建议。做这个项目的重心应该放在计算逻辑、数据清洗和工程稳定性上。4. 筛选规则和报告输出结果要让人能看懂4.1 规则拆分不要一锅煮筛选规则建议拆成独立函数每个函数只判断一个条件。例如def filter_st(df): return ~df[name].str.contains(ST, naFalse) def filter_amount(df, min_amount1e8): return df[amount] min_amount def filter_ma_trend(df): return (df[ma5] df[ma20]) (df[ma20] df[ma60])规则拆开之后可以单独验证每个条件的结果也可以自由组合。后续想加一条“成交量放大”的规则只需要新增一个函数不影响已有逻辑。这种做法的核心收益是出问题时能快速定位是哪条规则导致结果为空而不是在一个几十行的复合条件里排查。4.2 结果输出格式最常用的输出是 CSV 和 Markdown 表格。CSV 方便继续处理Markdown 方便直接贴到笔记或文档里。例如日期,代码,名称,收盘价,涨跌幅,ma5,ma20,信号 2025-01-10,600519,贵州茅台,1500.00,1.23,1490.50,1480.20,走强再进一步可以生成一个 reports/YYYY-MM-DD.md 文件按规则分块展示结果今日涨幅居前、均线多头排列、放量突破等。输出文件名带日期很重要这样历史报告不会被覆盖。如果你用 Windows 写文件建议统一指定encodingutf-8-sigExcel 打开 CSV 时中文不会乱码。4.3 图表用在哪里图表不是必须的但 K 线叠加均线能让人快速看出一只股票的状态。matplotlib 画图时可以输出整页图也可以每天只给筛选结果里前几名画图。要注意图片数量不能太多否则报告变得很重。我一般限制在 10 张以内每张图标注股票代码和日期。画图时有个细节沪深股票代码带交易所前缀文件命名要做处理。如果你同时用了多个数据源时间戳和时区不一致会让 K 线错位画图前先统一日期格式和时区。5. 每天自动跑定时调度、日志和失败重试5.1 定时任务怎么选daily_stock_analysis 的关键是 daily所以定时执行是核心功能。常见方案有两种操作系统级Linux 用 crontabWindows 用任务计划程序。优点是稳定能通过系统日志看到执行状态缺点是换机器要重新配置。程序内部用 schedule 库或 APScheduler 在进程里定时触发。优点是跨平台、配置简单缺点是进程必须一直运行服务器重启后要记得拉起。我的习惯是让脚本本身不依赖定时库入口函数只负责“运行一次并退出”由 crontab 或任务计划程序在固定时间调用。这样手动测试方便排查问题也方便。Linux 下的示例# 每个交易日 17:30 运行一次 30 17 * * 1-5 cd /path/to/daily_stock_analysis python scheduler.py logs/cron.log 21Windows 任务计划程序里操作类型选“启动程序”程序填 python.exe参数填 scheduler.py 的绝对路径。注意不要把当前工作目录搞错最好在入口脚本里用绝对路径拼数据目录。5.2 日志是排查问题的第一入口脚本跑完没有输出你根本不知道是没执行、报错了还是结果为空。所以日志一定要有。最简单的方式是用 Python logging 模块同时输出到控制台和文件import logging logging.basicConfig( levellogging.INFO, format%(asctime)s %(levelname)s %(message)s, handlers[ logging.FileHandler(logs/run.log, encodingutf-8), logging.StreamHandler(), ], )日志里至少记录数据拉取条数、指标计算耗时、筛选结果条数、输出文件路径。下次定位问题先翻日志永远比对着代码猜快。尤其是定时任务白天没时间盯拿到日志一眼就能看出哪一步断了。5.3 失败重试和幂等输出数据接口偶尔超时是常态。获取数据时加一层重试比如连续 3 次失败才放弃每次间隔 2 秒。但重试逻辑写不好会重复插入数据所以存储要注意幂等要么用“日期 代码”作为唯一键写入前检查要么每天单独存一个文件不覆盖历史。另一个经验不要把“数据没拉到”和“筛选结果为空”混为一谈。先检查数据是否拉取成功再执行筛选。很多新手看到结果为空第一反应是改筛选条件实际问题是接口根本没返回数据。日志里单独打一条“数据拉取完成”的标记能帮你快速区分这两种情况。6. 实际跑起来最容易踩的坑6.1 数据源报错先看返回内容不要只盯着异常免费数据源偶尔返回空列表、字段缺失或类型错误。脚本里加一个校验函数检查 DataFrame 是否为空、必填字段是否存在、日期是否为最新数据。校验不过就发一条告警而不是继续往下算。接口限流也很常见。全市场几千只股票逐个请求很容易触发限制。应对办法是请求之间加短暂 sleep或者优先使用数据源提供的批量接口一次获取全部股票。不要一上来就开 50 个线程接口容易拒绝内存也会飙升。6.2 指标算出来的数字对不上行情软件同一个指标你用 Python 算出来和行情软件显示不一致多数原因不是代码错而是参数或复权方式不同。比如 RSI 有 Wilder 平滑和简单平均两种算法MA 有是否包含当天的区别。遇到对不上的情况先检查你用的算法、窗口、复权方式和软件是否一致不要急着怀疑数据源。6.3 Windows 下中文编码问题Windows 上跑 Python 写 CSV 时默认编码可能是 GBK数据里如果有特殊符号写入会报 UnicodeEncodeError。建议写文件时统一指定encodingutf-8-sig。这个编码带 BOMExcel 打开时中文不会乱码。日志文件如果用 UTF-8 写入而 Windows 记事本默认用 ANSI 打开会显示乱码。这不是脚本 bug是编辑器编码问题换成 VS Code 或 Notepad 打开即可。6.4 运行时间过长和资源占用全市场行情分析比较耗时瓶颈通常在网络请求不是计算。第一次全量拉历史数据可能要好几分钟之后每天增量拉取会很快。如果服务器配置低减少并发请求数量一次拉一小批处理完再拉下一批。我习惯把流程分成两段先“全量补历史数据”再“每天增量更新”。历史数据只在第一次运行时拉取增量更新放进定时任务。这样每天任务量小失败恢复也容易不会因为一次网络抖动导致当天整个流程中断。6.5 结果怎么看项目怎么继续扩展最后说一点和工程无关但很重要的事。daily_stock_analysis 的输出是技术指标和筛选列表它解决的是“把数据整理成规则化结果”不是“预测明天涨跌”。同一套规则在不同行情环境下表现差异很大也没有哪种技术指标是稳定有效的。做这个项目时建议把它当作数据工程练习而不是寻找交易圣杯。如果后续想扩展可以按这个顺序来接入多个数据源做交叉验证增加回测模块验证规则的历史表现把日报改成网页服务再加入异常告警。每一步都不难但要先把基础链路跑稳。我个人更推荐的做法是先挑两三只股票把一个完整交易日跑通确认数据、指标、筛选、报告、定时五部分都正常再逐步扩到自选股和全市场。跑得稳比跑得多重要。踩过几次之后你会发现很多问题不是工具能力不够而是前置环境和输入数据没有处理干净。