
周六晚上朋友发来一张截图说他每天早上一到办公室习惯先打开行情软件把自选股列表翻一遍再切换周期看均线。十几只股票看完经常半小时就过去了。他问我能不能写个脚本每天早上自动更新这几只股票的数据顺便把均线、MACD、RSI 都算好生成一张表他只需要打开文件看结果当时我正好注意到 GitHub 上一个项目ZhuLinsen/daily_stock_analysis。名字很直白就是“每日股票分析”仓库本身也不大。但把它拆开看你会发现真正值得研究的不是某个算法而是“每日”这两个字背后的一整套工程问题数据要定时更新指标要稳定计算报告要每天生成中间还得处理停牌、复权、接口限流、日期错位和日志追溯。这也是我这篇文章想讲清楚的核心判断单次拉数据、算指标、出报告只要会一点 Python 和 pandas 就能做难的是让它每天自动、稳定、可追溯地跑起来并且遇到异常时还能给出有效输出。下面我会按从零搭建到工程化落地的顺序拆解这一类 daily_stock_analysis 项目应该怎么做以及它的适用边界到底在哪里。1. 先想清楚daily_stock_analysis 真正解决的是哪一类重复劳动很多人看到“股票分析”四个字第一反应是策略、预测、信号模型。但如果你每天固定做同一件事真正要解决的其实是“流程重复执行”的问题。1.1 手动每日分析的问题不是费时间而是口径不稳定手动流程看起来是这样的打开软件、找到股票、切换周期、看均线、瞄一眼成交量、偶尔看 MACD 和 RSI然后心里判断一下“今天强弱如何”。这个流程最大的问题不是耗时而是每次操作都不完全一致。今天你可能看的是 MA20明天变成 MA10今天用前复权看明天可能直接看不复权某只股票停牌一天你可能完全没注意到数据缺口昨天关注的五个指标今天可能只看了两个。更麻烦的是一周之后你想复盘“上周五我的判断依据是什么”往往想不起来。程序化流程可以保证同一套规则每天执行同一批股票、同一个复权口径、同一组指标参数、同一种输出格式。这看起来不性感但它让“每日分析”第一次变得可比较、可回溯、可审计。1.2 daily、stock、analysis 三个关键词分别坑在哪里把项目名拆开每个词都对应一个容易出问题的环节。daily对应的是时间和调度。A 股不是每天都交易节假日、调休、临时停市都会影响交易日历。定时任务如果只在工作日上午 8 点运行遇到长假后的周末补班就会跑空如果数据源当晚才更新行情你早上 8 点去拉可能只能拉到昨天的空壳。stock对应的是数据面和标的边界。股票代码格式要统一沪市、深市、北交所前缀不同上市日期、停牌区间、复权方式、数据源覆盖率也各不相同。单个股票跑通很容易股票池扩大到几十只后问题会被明显放大。analysis对应的是指标计算口径。均线窗口、RSI 周期、MACD 参数看起来都有标准定义但不同数据源、不同复权方式、不同缺失值处理策略都会让计算结果产生偏差。尤其当样本量少于指标窗口长度时你拿到的可能是一堆 NaN。1.3 我的判断这类项目的价值重心在流程固化而不是分析算法daily_stock_analysis 这类项目通常不会使用多复杂的量化模型。它的真正价值是把“打开软件、选股票、看指标、记录结论”这一套人工重复操作变成一个每天自动执行的脚本管道。它的核心产物不是某一天的涨跌判断而是一个可持续运行的数据处理流程。理解了这一点你就不会把精力浪费在纠结“RSI 用 6 还是 14 更准”这类问题上而是先考虑我的输入是什么输出是什么规则是什么中间哪一层最容易断。2. 从零搭一个最小可运行的每日分析流程不管项目名看起来多复杂第一版都应该走最小可用路径选几只股票、拉历史日线、算两三个指标、输出一份可读报告。2.1 先明确输入、输出和规则边界在写第一行代码前先把边界定清楚。输入通常包括股票代码列表、数据起止日期、日线频率、需要计算的指标列表。输出可以是控制台表格、CSV 文件、Markdown 报告甚至是一个纯文本摘要。规则边界则是“这个脚本只负责计算和展示不负责给出买卖建议”或者“信号只是技术指标交叉不等同于投资决策”。我见过不少半途夭折的脚本问题不是不会写而是输入输出边界一直变。今天加一个指标明天换一个股票池后天又想输出成 Excel。边界不确定脚本就一直处于“能跑但永远不稳定”的状态。2.2 环境准备和数据从哪里来环境上Python 3.9 以上版本加 pandas、numpy 基本够用。外部数据接口有很多选择常见的有 akshare、tushare、baostock 等。但要注意这些库的接口、权限和字段名称会不定期变化不要指望一份代码永远不动就能长期跑通。更稳妥的做法是在项目里先把数据获取独立成一个函数后续接口变动时只改一个地方。如果你的网络环境无法访问某些外部接口也可以先从本地 CSV 文件读数据先把流程跑通再替换数据源。2.3 一个不依赖外部接口的最小示例下面这个示例用本地 CSV 作为数据源结构简单适合先跑通流程。实际使用时把load_daily_data内部替换成你的数据接口即可。import pandas as pd def load_daily_data(csv_path): # 示例从本地 CSV 读取历史日线 # 文件至少包含列date, open, high, low, close, volume df pd.read_csv(csv_path, parse_dates[date]) df df.sort_values(date).reset_index(dropTrue) return df def compute_indicators(df): df df.copy() # 均线 df[ma5] df[close].rolling(5).mean() df[ma20] df[close].rolling(20).mean() # 简单动量 df[ret_5] df[close].pct_change(5) return df def generate_report(df): latest df.iloc[-1] return { date: latest[date].strftime(%Y-%m-%d), close: round(latest[close], 2), ma5: round(latest[ma5], 2) if pd.notna(latest[ma5]) else None, ma20: round(latest[ma20], 2) if pd.notna(latest[ma20]) else None, ret_5: round(latest[ret_5], 4) if pd.notna(latest[ret_5]) else None, } if __name__ __main__: df load_daily_data(sh600000_daily.csv) df compute_indicators(df) report generate_report(df) print(report)这个例子虽然简单但它已经具备了一个每日分析脚本的基本骨架加载数据、计算指标、生成结果。你可以在load_daily_data里接入真实接口把generate_report改成输出 Markdown 或 CSV。2.4 为什么必须先跑通单条样例再考虑批量新手最常见的误区是股票池一次拉 50 只然后发现四处报错根本不知道从哪里排查。更合理的做法是先选一只上市时间较久、流动性较好的股票用三个月以上历史数据跑一遍最小流程。单样例通过后再逐步扩大到三只、五只。这样做的好处是一旦出错你能快速定位到是数据源的问题、指标参数的问题还是报告格式的问题。批量任务一旦铺开网络波动、数据缺失、代码格式不统一等问题会叠加出现那时候再调试成本会高很多。注意先跑通再优化最后再扩大股票池。顺序反了你会同时面对数据、算法、调度、输出四个层面的 Bug很难快速定位根因。3. 从“跑一次”到“每天自动跑”还差哪几块关键拼图脚本能手动跑通离“daily”目标还差很远。每天自动运行意味着你要处理定时、日志、异常、重复运行、结果归档等一系列工程问题。3.1 定时任务不是“挂个 cron 就完事”把脚本挂到 cron 或 Windows 任务计划只是第一步。真正要思考的是时间策略A 股下午 15:00 收盘但数据源通常不会立刻更新完整日线可能要等一段时间。如果你设定工作日 16:00 运行有些接口可能已经更新如果设定早上 8:00 运行通常拿的是前一天收盘数据但也可能遇到接口缓存未刷新。更稳妥的方式是脚本运行后先检查最新交易日是否和预期一致再决定是否继续计算指标。不要假设“我定时跑了数据就一定是对的”。3.2 日志和结果可追溯是长期运行的地基每日运行的脚本最怕跑完没有任何记录。第二天你想知道“昨天到底成功了没有”如果只看到一个输出文件很难判断。建议每天运行后至少留下两类东西一是运行日志记录当天处理了哪些股票代码、每只拉取到的行数、缺失情况、耗时二是结果文件文件名带日期比如report_2025-01-10.csv不要用固定文件名覆盖。如果你不想引入复杂的日志框架用 Python 的logging模块就够了关键信息写入本地文件即可。长期看日志不是给人看的是给“未来的你”排查问题用的。3.3 异常重试和失败快速感知外部数据源不一定稳定。超时、限流、返回空值都是常见问题。脚本不能因为一次请求失败就整体崩溃也不能在失败后静默跳过。一个简单策略是对单只股票的数据拉取做 3 次重试重试之间等待 1 秒、3 秒、5 秒。重试仍失败时记录日志把这个代码标记为失败继续处理其他股票。最后生成一个汇总文件列出哪些股票成功、哪些失败、失败原因是什么。同时运行结束后的状态要能快速判断今天全部成功、部分失败、还是数据源异常。自动化流程里最怕的不是失败而是失败后没人发现。3.4 存储先简单但结果文件要带日期初期不需要引入数据库。一个合理的目录结构足够用data/ raw/ 2025-01-10/ sh600000.csv sz000001.csv reports/ report_2025-01-10.csv logs/ run_2025-01-10.log如果后续需要回测、统计多个股票的历史指标、做横截面分析再考虑引入 SQLite 或 PostgreSQL。不要在一开始就把存储复杂化否则很可能会花大量时间在设计表结构上而不是解决流程问题。3.5 建议先建立“运行状态检查”清单每天跑完后用一张检查清单判断运行是否正常今天是否成功拉取到目标股票的数据最新数据是否属于预期交易日每只股票的K线行数是否在合理范围内指标计算结果是否存在大面积 NaN是否有失败股票失败原因是否已知输出报告是否被正确写入带日期文件。这个检查清单可以靠人工看也可以写成脚本内的校验逻辑。长远看把它脚本化才是正路。4. 指标计算和报告生成里最容易埋坑的几个细节很多 daily_stock_analysis 项目不是挂在“数据拉取”而是挂在“指标算得不对”上。尤其当你拿自己和行情软件对比时差异往往来自下面这几个细节。4.1 复权口径不统一指标算出来就不一样股票发生分红、送股、配股后历史价格需要复权才能保持连续性。如果某只股票刚经历过除权不复权模式下价格会出现明显跳空导致均线、RSI、MACD 全部失真。常见的三种口径是不复权、前复权、后复权。前复权适合看当前视角下的历史走势后复权适合计算真实收益不复权则保留真实成交价但指标计算容易失真。我的建议是在项目配置里明确指定复权口径并且在报告里标注出来。否则同一天用不同数据源或不同默认设置分析同一只股票结果对不上时会很难解释。4.2 停牌和缺失值不能粗暴填充股票停牌期间日线数据可能缺失也可能数据源返回空行。如果你用fillna(0)填充缺失价格均线和涨跌幅会被严重拉偏。更稳妥的做法是保留 NaN让 pandas 的rolling()函数自动跳过缺失值但前提是你清楚每个指标对缺失值的处理方式。另外新股上市初期历史样本不够计算 MA20 时前 19 天必然全是 NaN。这不是代码 bug而是数据不足。报告里应该明确显示“样本不足”而不是硬算出一个没有意义的值。4.3 算指标时要注意避免“未来函数”未来函数指的是在计算当天信号时无意中用了当天之后才产生的数据。比如用pct_change()时如果 DataFrame 没有严格按日期排序或者索引错位就可能把后一天的数据当作当天计算依据。日线级别的分析通常会额外小心收盘后计算的信号必须只用到当日收盘及之前的数据。排序逻辑要显式执行不要依赖数据源返回顺序。4.4 报告要能解释不能只给一串数字很多初版脚本输出的报告就是一行行数字closing price、ma5、ma20、rsi14。看起来信息很全但阅读者很难快速理解“到底发生了什么”。更好的报告结构是股票代码、交易日、收盘价、MA5、MA20、5日涨跌幅、一句话摘要。一句话摘要是脚本根据预设规则自动生成的比如“收盘价高于 MA5且 MA5 向上穿越 MA20”这类中性描述。它不做买卖判断但能让看报告的人快速定位值得关注的标的。4.5 一个针对 daily_stock_analysis 的实际排查链路如果每天跑完发现结果异常不要慌按下面的顺序排查现象优先检查方向常见原因完全没数据数据源返回、代码格式、日期范围接口限流、代码前缀错误、非交易日数据量明显偏少股票池是否包含停牌股、次新股上市时间短、长期停牌指标全是 NaN数据窗口长度是否足够样本量小于均线窗口信号和行情软件不一致复权口径、交易日对齐不同数据源或复权方式差异今天结果和昨天不能衔接是否用了固定文件名覆盖结果没有带日期归档5. 适用边界这套系统适合谁、不适合谁以及往哪进阶最后必须说明边界。任何技术方案都不是万能的daily_stock_analysis 也一样。5.1 适合什么场景它适合个人研究者做行情观察记录。比如你有一个固定股票池想每天跟踪均线位置、涨跌幅、量能变化用它替代手动打开软件的操作完全合理。它也适合作为 Python 数据处理、数据管道和定时任务的练手项目。一次完整的 daily_stock_analysis涉及数据获取、清洗、计算、报告、日志、调度是一个很好的工程练习。它还适合小范围实验。比如研究“某几只股票在特定均线状态下的历史表现”用它生成每日快照持续积累一段时间后再做统计。5.2 不适合什么场景它不适合直接作为自动交易系统。脚本生成的指标信号只是技术指标驱动不能替代基本面、资金面、市场情绪和风险控制。它不适合作为完整回测平台。回测需要处理滑点、手续费、复权收益、资金管理、策略参数寻优这些远超普通 daily 分析脚本的职责。它也不适合高频数据分析。日线级别的每日分析关注的是长期趋势对分钟级或毫秒级决策没有参考意义。最后它不适合替代专业行情终端。免费数据源可能存在错误、延迟和字段缺失如果你需要做严格的数据研究还是需要额外的数据质量校验。5.3 如果要长期使用下一步该补什么如果决定把这类项目长期跑下去建议逐步补齐四块能力配置化。股票池、指标参数、输出格式都移到配置文件里不要写死在代码里。数据源容错。主数据源不可用时是否能够自动切换备用数据源。可视化。把 CSV 报告升级为带图表的 HTML 页面趋势变化会直观很多。数据质量校验。每天检查最新交易日、数据行数、复权口径、指标 NaN 占比异常时主动告警。这些能力不是第一版就要全部做而是应该在运行两周、积累到真实问题后按优先级逐个补。5.4 回到一个底层经验真正有价值的不是某一天的分析结果而是这条可复用的分析管道回头再看 ZhuLinsen/daily_stock_analysis 这个项目名它真正打动我的不是名字里出现了“股票”或“分析”而是“daily”这个限定词。它代表了一种工程意识把一次性的、人工的、依赖手感的事情变成一条每天自动执行、可以回溯、可以优化、可以扩展的数据管道。如果你想搭一个类似系统我的建议很简单明天就选三只股票准备一份至少一年的历史日线数据先写一个只算 MA5 和 MA20 的最小脚本手动跑通输出一份可读报告。然后再考虑定时任务、日志、失败重试和股票池扩展。先让流程立住再谈优化。