1. 为什么要做"可视化+推荐"二合一:毕设选题的切入点与整体技术选型
先说个很现实的问题:市面上用Python做股票数据分析的项目一抓一大把,但大多数都停留在"拉数据、画K线、算个均线"的层面,功能上很像一个加强版Excel。而单纯做推荐系统又往往脱离真实场景,用户根本不知道推荐的依据是什么。这个课题比较聪明的点在于把两块需求拧在一起:先让用户看得懂行情,再根据看得懂的数据给出有依据的推荐。数据可视化解决的是"信息过载"的问题——几千只股票、几十个指标,光靠人眼盯盘根本筛不过来;推荐系统解决的是"选择困难"的问题——盯盘盯出来了候选池,但选哪只、为什么选,需要一套可解释的逻辑来辅助决策。
先说技术选型。我默认这个项目面向的是课程设计或者本科毕设,技术栈选择必须兼顾三点:难度适中、有东西可写、答辩时讲得清楚。推荐使用Python 3.8 + Pandas + Matplotlib + Pyecharts + Scikit-learn + SQLite。不要一上来就上什么深度学习和LSTM,那是给自己挖坑。大多数情况下,K线形态识别加简单的协同过滤加一个技术面评分卡,已经足够撑起一个完整闭环,而且每一步都能在白板上画出来。
模块划分也要符合"设计与实现"这个题目气质。我当时把系统切成四层:数据层、计算层、可视化层、推荐层。数据层负责从公开数据源拉取行情并做清洗入库;计算层负责技术指标计算和特征工程;可视化层做交互式图表和看板;推荐层基于用户的浏览/收藏行为做策略推荐。四层各干各的,联调时才不会互相牵制。
架构设计图我不知道你打算怎么画,但建议画一张四层结构加数据流向的图。注意,答辩老师最爱问的就是"数据流是怎么走的"——从原始数据变成最终推荐结果,中间每一步都要能说清楚。
2. 数据获取与预处理:90%的坑都埋在这层
股票数据可视化项目第一个绕不开的问题是:数据从哪来。这是个比写代码更磨人的环节。常见的公开数据源包括Tushare、AkShare、Yahoo Finance(美股)、东方财富的公开接口等。我比较推荐用AkShare,原因是免费、无需token、接口丰富,A股、港股、美股都能覆盖,而且返回的就是Pandas DataFrame,代码上非常顺手。
不过AkShare有几个使用细节你需要提前知道:一天内频繁调用接口容易触发对方的风控,建议爬取做节流,每次请求后sleep 0.3到0.5秒;数据偶尔会返回空值或复权因子不一致,必须做数据清洗。数据清洗不是简单地dropna,要分情况处理:日行情数据缺失的常用方案是前值填充(ffill),但前值填充对收盘价只是权宜之计,如果连续缺失超过三天,建议直接剔除该时间段数据,避免生成错误的均线和指标。
入库方案我用的是SQLite,因为整个项目体量不大,不需要上MySQL。建表结构建议至少两张表:stock_price存行情快照,字段包括code、date、open、high、low、close、volume、amount;stock_info存股票基础信息,包括code、name、industry、list_date。两张表通过code关联。所有数据写入之前先做去重,以(code, date)作为联合主键,后写入的覆盖先写入的,防止反复爬取产生脏数据。
这里有一个实操中的关键经验:建议先拉5年以上的日线数据存到本地,再启动可视化应用。我见过太多人做项目时,图表画到一半就空白,排查半天发现是网络断了或接口限了流。数据落地到本地后,整个开发调试不需要联网,稳得多。如果你要复现这个项目,先跑一个月数据的demo,再拉全量,别一上来就贪多。
提示:不要在这个环节过分纠缠实时数据。实时行情需要WebSocket申请授权、处理推送缓冲区、应对断线重连,复杂度会直接爆炸。实时推送针对毕设是加分可选项,不是必选项。先把日线级别的历史数据做成稳定闭环,再做实时扩展,层层递进风险小得多。
3. 可视化模块的核心实现:K线图的坑、指标叠加的逻辑和交互设计
可视化模块是"看起来最值钱"的部分。如果你用Matplotlib画普通折线图,虽然也能展示,但大概率会被打回重做——太像上课练习了。建议用Pyecharts 1.x 版本做交互式图表。它生成的是HTML格式,浏览器直接打开,支持鼠标悬停、缩放、平移,演示效果比静态Matplotlib高出不止一个档次。
K线图是可视化模块的核心。Pyecharts里K线用Kline组件实现,数据格式是[open, close, low, high],注意顺序和你在其他平台看到的OHLC不同。我当时在这块踩了个大坑:文档里写的是[open, close, lowest, highest],没仔细看文档直接按常规OHLC传数据,结果K线的实体方向全画反了,阳线阴线完全颠倒。视觉上看起来好像也能用,但严重误导判断。
K线之上叠加均线是另一个常见需求。MA5、MA10、MA20三条均线是标配。Pyecharts中可以用Line组件和Kline做overlap(层叠),但叠的时候有个重要参数不能漏:overlap之后的坐标轴类型要统一,且均线的数据长度要和K线完全对齐,否则尾部错位。更稳妥的做法是在K线图里加dataZoom缩放组件,让用户滑动查看特定时间窗口,而不是一屏塞所有数据。
除了K线,推荐系统决策的依据还需要几个副图指标。成交量是必须的;MACD或RSI可以选一个,其中RSI相对容易解释——它的计算不涉及复杂的EMA递归,对答辩更友好。我当时实现的是成交量柱状图 + RSI副图,作为附在图下方的第二和第三个区域。这里分享一个布局层面的心得:用Pyecharts的Grid组件实现多图拼接时,每个子图占位比例要调好,K线主体占60%以上,RSI占20%,成交量占20%,不然视觉上主次不分。
还有一点容易被低估:数据是按证券代码分文件存,还是统一存一张表后用字段过滤,这直接决定加载性能。如果用一张表存所有数据,date字段建索引,查询单只股票时走索引,返回很快;如果按代码分文件保存,读取时逻辑简单,但文件数量会很多。我实测下来,SQLite单表加索引的方式综合性能更好,因为一个连接搞定所有查询,不用频繁打开关闭文件。
提示:股票可视化项目的"交互"不止是图表的hover。你要让用户能输入股票代码切换标的、选择时间范围、切换指标组合,推荐结果要能联动到对应K线视图。这种"输入→展示→互动→推荐"的闭环,才是答辩时老师眼中"系统完整度"的关键评判点。
4. 推荐系统怎么做才有说服力:三路策略与特征相关性分析
推荐系统是这个项目的理论高地和得分点。但股票推荐和电商推荐逻辑上有所不同,电商推荐可以基于"买过A的人还会买B"这种协同过滤,而股票推荐需要结合"相似K线形态"和"技术指标共振"来做更解释得通的推荐。
我实际采用的是三路推荐策略,最终结果按加权融合输出。第一路是相似度推荐,基于协同过滤思想,不过不是算用户相似度,而是算股票在特征空间的距离。特征怎么选?用相对变化量而不用绝对价格,这一点至关重要——直接把收盘价丢进欧氏距离计算是没有意义的,因为高价股和低价股天然差很多,量纲完全不同。我选择了近20日收益率、近5日波动率、RSI值、成交量变化率这几个特征做Z-score标准化,随机森林(Random Forest)中常用的特征重要性方法可以用来给每个特征赋初始权重,再用K近邻(KNN)找出距离最近的Top-N只股票。
第二路是技术面共振推荐,规则引擎的设计思路。设置几条可解释的规则,例如:MA5上穿MA10且RSI在50~70之间且成交量放量1.5倍以上,条件全部满足就标记为"共振信号"候选。这一路的价值在于可解释性强,每条推荐理由都能对应到具体指标特征。
第三路是用户偏好协同过滤。基于用户的历史浏览/收藏/买入行为记录构建行为矩阵。用户A浏览了某只股票,系统在推荐时统计该股票被类似用户偏好集中的行为,进一步生成推荐候选池。这里的"类似用户"通过行为记录的余弦相似度计算。
这三路需要做数据融合。我当时用的策略是加权排序:相似度推荐权重在0.5,形态共振在0.3,协同过滤在0.2。各路的输出还是候选集合并集,取得分最高的Top-3作为最终结果。为什么是Top-3?列表太长会分散用户注意力,而且推荐系统的评测指标中,Top-3的精确率远比Top-10更直观、更容易在答辩时解释。
这里要回答一个常见问题:为什么不做严格的"收益率预测模型"?因为那是另一个研究问题,涉及时序平稳性、滑点、手续费、过拟合等一系列复杂工程,在课程设计的时间框架内很难做得严谨。而"推荐系统"的定位是辅助决策工具,它的评估指标是推荐列表中候选股票池与历史强势股的命中率,我建议采用命中率@N做评估:推荐Top-5中包含未来20日涨幅前10%的股票,算一次命中,最终统计整体命中率。这个指标实现简单、表达清晰、答辩时也拿得出手。
5. 系统整体联调时的三个大坑与最终版本的处理方式
设计文档写得再漂亮,联调才能发现真问题。这个项目我印象最深的是三个坑,写出来供你参考。
第一个坑是中文编码。Pyecharts在HTML中默认输出UTF-8,一般没问题。但如果股票名称中含有繁体字或者特殊字符(如"ST"和"退"标志),在文件名、命令行输出、日志打印时极易出现UnicodeEncodeError。我的处理方式是在项目启动入口处设置sys.stdout.reconfigure(encoding='utf-8'),并在所有文件写入操作中显式指定编码方式。这个坑虽小,但足以让演示现场直接崩溃。
第二个坑是推荐结果的时间穿越。这是最容易被忽视的逻辑漏洞:用今天的数据算出的特征,去匹配包含未来数据的样本,得出的相似股票纯属作弊。处理方式是数据切分必须严格按时间切——训练推荐模型的KNN只使用截止到某个交易日的历史数据,对某一天的推荐只允许使用这一天之前的数据。代码上只需要对特征矩阵做时间过滤即可,但很多人就是没做。
第三个坑是SQLite并发读写。如果用Flask做Web界面,可能同时多个请求访问数据库。SQLite默认同一时刻只允许一个进程写库,并发高时会出现database is locked。我建议连接时设置timeout=10,并把高频读操作做成缓存。另一个更省事的方案是所有查询接口加一个统一缓存装饰器,短期数据用字典存内存,过期时间设置为5分钟。这样不仅能解决锁问题,响应速度还快了很多。
最终版本的实现效果我用一句话概括:用户在系统页输入股票代码和时间范围,系统展示K线和指标副图,用户点击"相似股票"按钮生成推荐候选并按得分排序,每条推荐右侧显示推荐理由标签,用户可以将推荐结果标注为感兴趣/不感兴趣,行为数据回流数据库供后续协同过滤更新。
6. 文档与PPT的内容编排:答辩视角下的侧重优化
项目代码写完了只是完成50%。课程设计的另一半是文档和PPT,而这两样东西决定了答辩老师第一印象。
文档我建议分成五章:绪论、需求分析、系统设计(架构+数据库设计)、系统实现(界面截图+核心代码片段)、系统测试(功能测试用例表+推荐命中率结果分析)。如果学校要求"设计与实现"这个标题,章节命名直接对应标题逻辑最稳。需要注意,不要事无巨细把所有源码都贴进去,核心类和数据流图才是老师最想看的。
关于PPT,我强烈建议控制在15到20页以内。结构设计注意突出"数据流向"这条主线:数据从哪来,处理过后长什么样,特征如何构建,推荐如何计算,用户如何看到结果。每页只放一个核心图,宁可少讲,不要堆砌。答辩演示环节,先演示一个完整流程:输入股票代码→展示K线→点击推荐→展示Top-3候选及推荐理由。这个流程走完,再讲解核心代码片段和评估结果,整个逻辑链清晰,反而显得研究得很透。
一个加分的小设计:在系统测试章节,加入一个简单的对比实验表格,对比随机选股与推荐系统的命中率。我当时实测的数据,推荐Top-5在测试集上的命中率大约为27%到35%左右;随机选股基线只有4%。这个对比数据放在PPT里非常有力。别虚报数据,真实测出来的就好,老师更在意你是否理解评测方法。
7. 源码交付前最后该检查的核心点
项目的源码要保证让另一个同学拿到也能跑通。这一点在课程设计提交时特别重要,因为有些老师本身不看代码,但会抽测运行。
提交前检查清单可以做得很简洁:首次运行是否会自动创建数据库并拉取示例数据;requirements.txt是否包含完整的第三方库且版本号已锁;README是否写清楚运行步骤(建议三步走:安装依赖、运行初始化脚本、启动主程序);是否附带一个演示用的数据集文件,防止评审现场网络连不上外部的数据源。
其中演示用数据集文件可以重点加上。我当时放了一份近两年的日线数据CSV压缩包,README里写明"如网络不可用,可使用本地数据文件初始化数据库"。这个细节在答辩时遇到断网环境简直是救命稻草。
还有一个细节是项目的目录结构要清晰:data/、core/、visual/、recommender/、web/、docs/各归其位,入口文件放在根目录下命名为main.py或app.py。不要把所有代码堆在根目录下,这是代码洁癖的问题。
根据我这几年看过各种课程设计的经验,能真正拿到高分的项目不一定用了最前沿的技术,但一定在"数据链路完整、文档逻辑清晰、代码可直接运行"这三个基本盘上做得扎实。可视化模块负责直观展示你的工作量,推荐模块负责体现你的思考深度,文档和PPT负责让这一切被看见。把这三件事做透,这个课题拿高分并不难。