☰
股市分析Notebook实战:从数据拉取到技术指标计算与可视化
2026/9/29 16:45:37 网站建设 项目流程

简介:这份资源是一套面向量化投资初学者与数据分析爱好者的股市分析项目,基于 Jupyter Notebook 构建,围绕标普500指数展开探索性数据分析、持仓模拟以及超级投资者持仓追踪等实战场景,帮助读者理解从数据获取到策略验证的完整分析链路。压缩包共34个文件,约1.75MB,以14个Python脚本和3个ipynb笔记本为核心,辅以Makefile、rst文档、ini配置模板及gitkeep占位文件,覆盖数据分层、特征工程、模型与可视化等模块,目录按data、src、models、docs等组织,结构清晰便于按需查阅。目前已有470人学习下载。项目内置数据分层目录与配置模板,读者可据此复现分析流程、理解特征构建与回测思路,并借助Makefile命令快速上手,适合作为量化入门与项目结构参考的实践素材。

1. 一份能跑起来的股市分析 Notebook:从数据拉取到指标落地的完整链路

很多人第一次接触量化分析,卡在的不是策略本身,而是环境。装完 Python、配好 Jupyter,打开一个空 Notebook,面对import之后该写什么完全没有头绪。这份stock_analysis资源就是冲着这个场景来的——它把股市分析里最常走的那条链路,从数据获取、清洗、技术指标计算到可视化,全部塞进了一个 Jupyter Notebook 里。你不需要先啃完一本量化教材再动手,打开就能看到每一步在做什么、输出长什么样。适合两类人:一是刚转量化方向、想找个能跑通的模板照着改的开发者;二是做数据分析出身、想快速把 Pandas 那套东西套到股票场景上的从业者。它不承诺帮你赚钱,但能帮你把“分析一只股票”这件事的工程骨架搭起来。

2. 拆开 Notebook 看结构:数据层、指标层、可视化层怎么分

2.1 先搞清楚这份资源的技术栈边界

stock_analysis的核心载体是一个 Jupyter Notebook 文件,关键词里也明确指向了 JupyterNotebook。这意味着它的运行方式不是python xxx.py那种脚本式执行,而是单元格逐块运行、中间结果保留在内存里的交互式分析。技术栈上,常见做法是pandas做数据处理、numpy做数值计算、matplotlib或plotly做可视化,数据源大概率走yfinance、tushare或akshare这类库。你拿到 Notebook 之后,第一件事不是急着 Run All,而是先看它 import 了哪些库、数据从哪个接口来、有没有硬编码的 token 或路径。

这一步很关键。我见过太多人拿到 Notebook 直接从头跑到尾,结果卡在某个数据接口超时或者 token 失效上,然后就开始怀疑是代码问题。实际上大部分翻车都发生在数据层,而不是分析逻辑本身。所以建议按这个顺序过一遍:

  • 看第一个单元格的 import 清单,确认本地环境缺哪些包
  • 找数据获取的那个单元格,看用的是哪个数据源、需不需要 API key
  • 看有没有pd.read_csv()这类本地文件读取,如果有,确认配套数据文件在不在
  • 最后再看指标计算和绘图部分

2.2 数据获取与清洗:Notebook 里最容易被忽略的环节

股市分析的第一步永远是把数据搞进来。Notebook 里常见的写法是定义一个时间区间和股票代码列表,然后循环拉取。下面这段代码是我按这类资源的典型结构还原的,你可以对照自己手里的 Notebook 看是不是这个套路:

import yfinance as yf import pandas as pd import numpy as np # 定义分析标的和时间窗口 tickers = ["AAPL", "MSFT", "GOOGL"] start_date = "2023-01-01" end_date = "2024-01-01" # 批量拉取日线数据 raw_data = {} for ticker in tickers: df = yf.download(ticker, start=start_date, end=end_date) # 只保留收盘价和成交量,减少后续处理维度 df = df[["Close", "Volume"]].copy() df.columns = ["close", "volume"] raw_data[ticker] = df # 合并成一个 MultiIndex DataFrame,方便统一计算 panel = pd.concat(raw_data, axis=1) print(panel.tail())

这段逻辑说明几件事:第一,数据源用的是yfinance,它不需要 token,适合做本地快速验证;第二,只保留了收盘价和成交量,说明后续指标计算大概率围绕价格和量能展开;第三,用pd.concat拼成面板数据,是为了后面能一次性对所有标的做同样的计算,而不是写循环逐个处理。参数上你需要注意start和end的格式,yfinance接受YYYY-MM-DD字符串,如果传成datetime对象一般也能识别,但跨版本行为不一致,建议统一用字符串。

清洗环节通常包括处理缺失值、对齐交易日历、去除停牌日。Notebook 里如果只写了dropna(),你要留意它是按行删还是按列删。股票数据里常见的是某只票在某天没有成交,dropna()默认按行删,会把其他票当天的数据也一起干掉。更稳妥的做法是dropna(how="all")只删全空行,或者用ffill()前向填充。这个细节在资源里不一定写得很显眼,但你自己跑的时候一定要检查。

2.3 技术指标计算:从移动平均到 RSI 的代码落地

数据进来之后,Notebook 的核心价值就体现在指标计算上。最常见的几个指标是移动平均线(MA)、相对强弱指数(RSI)和布林带(Bollinger Bands)。下面这段代码展示了怎么在面板数据上批量算这些指标:

# 计算 5 日和 20 日移动平均线 for ticker in tickers: panel[(ticker, "MA5")] = panel[(ticker, "close")].rolling(window=5).mean() panel[(ticker, "MA20")] = panel[(ticker, "close")].rolling(window=20).mean() # 计算 RSI(14 日) def compute_rsi(series, period=14): delta = series.diff() gain = delta.where(delta > 0, 0.0) loss = -delta.where(delta < 0, 0.0) avg_gain = gain.rolling(window=period).mean() avg_loss = loss.rolling(window=period).mean() rs = avg_gain / avg_loss return 100 - (100 / (1 + rs)) for ticker in tickers: panel[(ticker, "RSI14")] = compute_rsi(panel[(ticker, "close")]) # 布林带:20 日均线 ± 2 倍标准差 for ticker in tickers: ma20 = panel[(ticker, "close")].rolling(window=20).mean() std20 = panel[(ticker, "close")].rolling(window=20).std() panel[(ticker, "BB_upper")] = ma20 + 2 * std20 panel[(ticker, "BB_lower")] = ma20 - 2 * std20

逻辑上,MA 是最直观的趋势指标,rolling(window=5)表示取最近 5 个交易日求均值,窗口大小你可以按自己的交易周期改。RSI 的计算稍微绕一点,核心是先算涨跌幅,再把涨幅和跌幅分别做移动平均,最后套公式。这里用的是简单移动平均,有些实现会用指数移动平均(EMA),结果会有差异,但方向一致。布林带的关键参数是窗口 20 和倍数 2,这两个值在业界比较默认,但并不是铁律,波动大的标的可以适当放宽。

参数说明方面,window越大,指标越平滑但滞后越明显;window越小,反应越快但假信号越多。RSI 的period通常取 14,改成 7 会更敏感,改成 21 会更稳。这些在 Notebook 里如果写死了,你复制出来自己调的时候要心里有数。

2.4 可视化:把指标叠在 K 线上看

算完指标不画图,等于白算。Notebook 里通常会用matplotlib画收盘价和均线,用子图展示 RSI。下面是一个典型的绘图代码块:

import matplotlib.pyplot as plt ticker = "AAPL" fig, axes = plt.subplots(2, 1, figsize=(12, 8), sharex=True) # 上图:收盘价 + 均线 + 布林带 axes[0].plot(panel.index, panel[(ticker, "close")], label="Close", color="black") axes[0].plot(panel.index, panel[(ticker, "MA5")], label="MA5", color="blue") axes[0].plot(panel.index, panel[(ticker, "MA20")], label="MA20", color="orange") axes[0].fill_between(panel.index, panel[(ticker, "BB_lower")], panel[(ticker, "BB_upper")], alpha=0.1, color="gray") axes[0].legend() axes[0].set_title(f"{ticker} Price & Indicators") # 下图:RSI axes[1].plot(panel.index, panel[(ticker, "RSI14")], color="purple") axes[1].axhline(70, linestyle="--", color="red", linewidth=0.8) axes[1].axhline(30, linestyle="--", color="green", linewidth=0.8) axes[1].set_title("RSI (14)") plt.tight_layout() plt.show()

这段代码里,sharex=True让上下两张图共用 X 轴,缩放时同步。fill_between用来填充布林带区间,alpha=0.1控制透明度,太深会挡住 K 线。RSI 图里画了 70 和 30 两条参考线,这是常用的超买超卖阈值。如果你在 Notebook 里看到的是plotly版本,交互性会更好,但代码结构类似,只是 API 换成go.Figure那套。

3. 避坑与排查:Notebook 跑不通时先查这五个地方

3.1 数据接口返回空 DataFrame

现象:yf.download()执行完不报错,但df.shape是(0, 0),后面所有计算全变成 NaN。原因通常是股票代码写错了、时间区间内没有交易日、或者接口本身临时抽风。解决:先单独跑一行yf.download("AAPL", start="2024-01-01", end="2024-01-10")看有没有数据,确认代码和日期格式没问题。如果还是空,换akshare或tushare试一下,别在一棵树上吊死。

3.2 指标列全是 NaN

现象:MA、RSI 这些列前几行是 NaN 可以理解,但整列都是 NaN。原因一般是rolling的窗口比数据长度还大,比如你只有 10 天数据却要算 20 日均线。解决:检查数据行数,len(df)小于window时要么拉更长的时间区间,要么把窗口调小。另外,如果close列本身有 NaN,rolling也会传染,先dropna()或ffill()处理干净。

3.3 绘图时中文显示成方块

现象:plt.title("股票价格")出来的标题里中文全是方框。原因是matplotlib默认字体不支持中文。解决:在绘图前加两行配置:

plt.rcParams["font.sans-serif"] = ["SimHei"] # Windows 常用 plt.rcParams["axes.unicode_minus"] = False # 解决负号显示问题

Mac 上把SimHei换成Arial Unicode MS或PingFang SC。这个坑几乎每个人都会踩一次,跟代码逻辑无关,纯粹是环境配置。

3.4 Jupyter 内核崩溃或内存溢出

现象:跑着跑着内核挂了,或者整个 Notebook 卡死。原因通常是数据量太大,比如一次性拉了上百只票好几年的分钟级数据,内存扛不住。解决:分批处理,别把所有数据都堆在内存里。可以先用日线数据验证逻辑,确认没问题再换更高频的数据。另外,panel这种 MultiIndex DataFrame 很吃内存,用完及时del掉不用的变量。

3.5 指标计算结果和券商软件对不上

现象:你自己算的 MA20 和某券商 App 上显示的数值有细微差异。原因可能是复权方式不同。yfinance默认返回的是未复权价格,而券商软件通常展示前复权或后复权价格。解决:在yf.download()里加auto_adjust=True让接口自动做复权调整,或者自己用Adj Close列来算。这个差异在短周期均线上不明显,但在长周期或者有分红送转的标的上会放大。

4. 进阶用法:把 Notebook 变成可复用的分析模板

4.1 参数化改造:从写死到可配置

原始 Notebook 里股票代码、时间区间、指标窗口大概率是写死的。每次换标的都要改代码,效率很低。我一般会做一层参数化,把所有可变项抽到开头一个单元格里:

# ========== 配置区 ========== TICKERS = ["AAPL", "MSFT", "GOOGL"] START_DATE = "2023-01-01" END_DATE = "2024-01-01" MA_WINDOWS = [5, 20, 60] RSI_PERIOD = 14 BB_WINDOW = 20 BB_STD = 2 # ============================

然后后面的计算逻辑全部引用这些变量。这样你换一批票或者调窗口,只改配置区就行,不用在几百行代码里翻找。更进一步,可以用ipywidgets做几个下拉框和输入框,把 Notebook 变成一个简易的交互式工具,但那是另一个话题了。

4.2 导出与自动化:Notebook 之外的落地方式

Notebook 适合探索,不适合定时任务。如果你想把分析结果每天自动跑一遍,常见做法是用nbconvert把 Notebook 转成脚本,再用crontab或Airflow调度:

jupyter nbconvert --to script stock_analysis.ipynb # 生成 stock_analysis.py,然后就可以用 python stock_analysis.py 执行

转成脚本后要注意,Notebook 里依赖单元格顺序的变量,在脚本里必须保证定义在使用之前。另外,plt.show()在无头环境里不会弹窗,改成plt.savefig("output.png")更稳妥。

4.3 验证分析结果是否靠谱的三个习惯

第一,拿一只你熟悉的股票,手动核对几个关键日期的收盘价和均线值,确认数据源和计算逻辑没问题。第二,把 RSI 的值和公开数据源对比,偏差超过 1 就说明复权或窗口设置有问题。第三,画图之后肉眼扫一遍,看有没有明显的断裂、跳空或者异常尖刺,这些往往是数据清洗没做干净留下的痕迹。我从第一次跑量化 Notebook 到现在,每次拿到新模板都强制走一遍这三步,踩过的坑基本都在这三个环节暴露出来。希望这份拆解能帮你少走点弯路,把这份stock_analysis真正用起来。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询