ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Python股票系统源码实战:从数据采集到K线可视化部署全解析

Python股票系统源码实战:从数据采集到K线可视化部署全解析 简介这是一套面向股票交易网站开发与运维的完整源码包涵盖前端展示、后端服务与数据库脚本。压缩包内共259个文件大小约172.71MB主要文件类型包括JavaScript、CSS、SVG/PNG图片等前端交互与界面资源JAR格式的Java后端模块以及SQL初始化脚本和TXT部署说明可支撑从页面渲染到接口服务的完整流程其中前端文件占比高包含大量JS与CSS样式表并配有图标、字体等素材便于定制页面视觉。包内针对PHP、Nginx、Tomcat、Redis等基础环境给出配置思路包含多站点创建、反向代理设置、FTP与数据库账号密码修改、域名替换等关键步骤便于快速部署上线。资源已有715人学习浏览具备一定实践参考价值。对于需要完整股票系统模板、想了解前后端分离部署或准备进行二次开发的开发者这套资源能明显降低环境配置门槛缩短项目联调时间。 去年底在技术群里看到有人发“2024最新股票系统源码 附教程”这类压缩包我顺手下来跑了一遍结果光踩坑就踩了三天。把数据采集、K线展示、指标计算到简单信号提示整个链路重新捋顺之后我觉得这套东西其实挺适合拿来当练手项目也适合想做个人行情看板的人二次开发。今天就把完整的拆解思路、部署步骤和排查经验写出来给准备碰这套源码的朋友做个参照。先说清楚这套系统到底是干什么的。它本质上是一套轻量级的“行情数据采集 指标计算 图表展示”框架核心代码用Python写前端用Web页面做可视化内置了均线、MACD、量能饱和度一类常用技术指标的计算逻辑。它能解决的是“我想自己拉数据、自己算指标、自己画图并且想改逻辑时能改得动”的问题而不是帮你直接下单交易。适合的人群也很明确有一定Python基础、想入门量化分析或者做二次开发的开发者以及想搭建私有行情观察站、不满足于现成软件黑盒逻辑的朋友。为什么我建议你把重点放在“看懂架构”而不是“跑起来就行”因为这种源码包的价值不在那几百兆文件本身而在它拆出来的数据流转方式。搞懂它之后你把它换成任何数据源、换成任何前端框架、加上任何选股逻辑都是顺手的事。1. 项目整体设计思路与源码架构拆解1.1 核心模块划分数据层、计算层、展示层这套源码拿到手之后先别急着运行我建议先按“数据层—计算层—展示层”三层结构去读目录。大多数号称“最新”的股票系统源码都是这个套路只是命名和封装方式不一样。数据层负责从公开行情接口拉取K线、分时、实时快照统一清洗成标准格式之后落库或者直接推给上层。计算层负责读数据、算指标比如MA均线、MACD、RSI、量能饱和度、主力增仓痕迹这些输出成带有交易信号的标记序列。展示层就是Web界面把K线图、分时图、指标曲线和买卖点标记渲染出来。我拿到的那份源码目录结构大概是这样的你可以对照自己手里的版本看一下stock_system/ ├── collector/ # 数据采集模块 │ ├── akshare_source.py │ ├── tushare_source.py │ └── base_source.py ├── indicator/ # 指标计算模块 │ ├── ma.py │ ├── macd.py │ ├── volume_saturation.py │ └── signal.py ├── web/ │ ├── app.py # Flask入口 │ ├── templates/ │ └── static/ ├── config.yaml # 全局配置 ├── requirements.txt ├── docker-compose.yml └── README.md这里我想重点说一下选择“分层”而不是把所有逻辑塞到一个文件里的原因。如果只是给自己看一眼怎么省事怎么来但如果你打算长期维护、想换数据源、想加新指标不分层的代码会把每一次改动都变成一次灾难。我见过有人把数据请求、数据库写入、指标计算、Flask路由全写在同一个.py文件里最后3000多行代码改一个字段名都要全局搜索那个痛苦谁遇谁知道。1.2 数据流转路径从接口到K线图中间发生了什么一套完整的数据流转路径大致是这样行情接口 - 数据清洗去重、补空值、统一时间格式 - 结构化存储MySQL/SQLite - 指标计算向量化运算 - 信号生成 - JSON API - 前端图表渲染。在这套源码里默认的采集器用的是akshare因为它免费、无需注册token、接口覆盖广。但免费意味着不稳定接口字段随时可能变所以源码里做了一层base_source.py抽象把所有数据源统一成get_kline(symbol, period)这样的方法。这意味着你下次想换成tushare、baostock或者自己维护的数据库只需要写一个新的类去继承base_source改一下config里的data_source字段就行其他代码完全不用动。我实际跑了一遍发现它的K线数据格式是标准化的date, open, high, low, close, volume时间统一转成YYYY-MM-DD HH:MM:SS空值用前向填充处理。这个细节很关键因为很多指标计算对数据顺序和缺失值敏感如果数据里有NaN或者倒序算出来的MACD和RSI全是错的。1.3 为什么用Docker部署环境隔离带来的省心源码包里附带了一个docker-compose.yml我强烈建议你优先用这个方式跑。原因很现实行情系统依赖的组件不少MySQL、Redis、Python的一堆科学计算库每一样在Windows和Mac上的安装方式都有细微差别。Docker Compose可以把数据库和缓存服务一次性拉起来规避掉90%的环境问题。看一下这份Compose文件的核心部分version: 3.8 services: mysql: image: mysql:8.0 container_name: stock_mysql environment: MYSQL_ROOT_PASSWORD: root123 MYSQL_DATABASE: stock ports: - 3306:3306 volumes: - ./mysql_data:/var/lib/mysql redis: image: redis:7-alpine container_name: stock_redis ports: - 6379:6379在你确认Docker已经安装并启动的前提下终端执行docker-compose up -dMySQL和Redis就起来了。后面连数据库时直接配localhost:3306即可。这里有个实战经验要告诉你MySQL 8.0默认的认证插件是caching_sha2_password如果Python连不上报Authentication plugin错误要么在Compose里给MySQL加command: --default-authentication-pluginmysql_native_password要么在Python连接串里指定auth_pluginmysql_native_password。2. 详细部署教程从环境准备到跑通全流程2.1 环境清单与安装步骤Python版本别用太新的先列一下我这边的部署环境你是Windows、Mac还是Linux差别不大但Python版本建议不要超过3.10。别问为什么问就是ta-lib这类金融计算库的轮子在新版Python上经常编译失败我试过Python 3.12装了一整天没搞定降到3.10之后十分钟全部装完。Python 3.10GitDocker Desktop或者Linux上的Docker Engine docker-compose插件一份该股票系统的源码包第一步把源码包解压到某个路径然后用Git Bash或终端进入项目根目录创建虚拟环境cd stock_system python -m venv venv source venv/bin/activate # Windows上执行 venv\Scripts\activate第二步安装依赖。这份源码的requirements.txt里主要包括flask2.2.0 requests2.28.0 pandas1.5.0 numpy1.23.0 akshare1.10.0 pymysql1.0.2 redis4.5.0 pyyaml6.0执行安装pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple国内环境建议加清华镜像否则akshare带着一堆依赖下载速度会让人崩溃。第三步启动MySQL和Redis。直接用源码里给好的Compose文件docker-compose up -d然后验证一下容器状态docker ps看到stock_mysql和stock_redis都在运行就说明数据库层OK了。第四步修改配置。打开config.yaml把数据库连接信息改成你自己的database: host: localhost port: 3306 user: root password: root123 dbname: stock redis: host: localhost port: 6379 db: 0 data_source: akshare stock_pool: - 600519 - 000001 - 300750这里stock_pool就是你想跟踪的股票代码池注意格式是纯数字代码不带交易所前缀。第五步初始化数据库表。源码的collector目录下一般会有一个init_db.py运行它自动建表python -m collector.init_db第六步启动Web服务python web/app.py浏览器访问http://localhost:5000如果看到K线图页面并且有数据渲染恭喜你全流程已经跑通了。2.2 首次启动必须检查的3个配置项很多第一次跑这套系统的人启动时报错后完全不知道从哪查起。我先说三个最高频的坑。第一个是config.yaml里的start_date参数。如果你没有设置这个参数数据采集模块默认只拉最近一年行情算MACD时因为数据量不足计算出的DIF、DEA前几十个值全是NaN前端图上就会出现一段空白很多人以为是自己代码坏了其实就是数据预热期不够。建议改成start_date: 2019-01-01积累至少三年日线数据再算指标。第二个是数据库表名的大小写问题。MySQL在Linux下默认表名区分大小写如果源码里建的表示stock_kline你后续查询时写成Stock_Kline直接报table doesnt exist。我排查过好几个类似问题最后发现就是大小写不一致。第三个是时区问题。行情数据的时间戳默认是东八区如果你的服务器系统时区是UTC写入数据库之后所有时间会偏移8小时。解决方案是在MySQL连接串里加init_commandSET time_zone8:00或者干脆在Python连接参数里直接指定port、charsetutf8mb4之外再加一个init_command。这个不修的话前端分时图的横坐标全是乱的。2.3 前端页面启动失败先看模板路径和静态资源如果你启动之后Flask没有报错但浏览器打开是404或白屏大概率是模板路径问题。源码里Flask的app.py如果写的是render_template(index.html)那你的templates目录必须在web/app.py同级目录下不能多包一层也不能直接放项目根目录。这个我用三分钟帮你定位看Flask启动日志里有没有GET / 404有就是模板路径不对如果200但页面空荡荡只有框架打开浏览器F12看Console里有没有404 for main.css之类有就是static目录路径问题。我处理过一份从某个论坛下载的版本index.html里引用的CSS路径是/style/main.css但实际文件放在web/static/css/main.css不统一最后我把HTML里的静态资源路径统一改成{{ url_for(static, filenamecss/main.css) }}才解决。建议你拿到源码先全局搜一下src和href把所有静态资源引用改成Jinja2写法省得后面换部署路径时又崩一次。3. 核心功能实现与关键代码解析3.1 数据采集模块为什么选akshare以及怎么优雅替换数据源这套源码里的数据采集模块默认数据源是akshare。为什么选它因为它免费、无需token、接口覆盖A股港股美股和期货对于个人学习和研究来说几乎没有门槛。但你也必须知道它的短板接口的非官方性导致字段名会不定期调整而且并发请求太猛容易被服务端限流。源码里做了一个很聪明的抽象层基础类定义如下# collector/base_source.py from abc import ABC, abstractmethod import pandas as pd class BaseDataSource(ABC): abstractmethod def get_kline(self, symbol: str, period: str daily) - pd.DataFrame: 返回标准K线DataFrame 列: date, open, high, low, close, volume pass abstractmethod def get_realtime_quote(self, symbol: str) - dict: passakshare实现类大致是这样# collector/akshare_source.py import akshare as ak from collector.base_source import BaseDataSource class AKShareSource(BaseDataSource): def get_kline(self, symbol: str, period: str daily) - pd.DataFrame: if period daily: df ak.stock_zh_a_hist(symbolsymbol, perioddaily, adjustqfq) elif period minute: df ak.stock_zh_a_minute(symbolsymbol, period1) else: raise ValueError(funsupported period: {period}) df.rename(columns{ 日期: date, 开盘: open, 最高: high, 最低: low, 收盘: close, 成交量: volume }, inplaceTrue) return df[[date, open, high, low, close, volume]]之所以把接口统一返回标准列名是为了让指标计算模块完全不感知数据来源。你以后想换成tushare需要token或baostock只需要再写一个TushareSource类然后在config.yaml里改一行data_source: tushare即可。这个设计思路在真实项目中极其重要我在做其他数据系统时也一直沿用核心模块之间通过接口解耦替换实现不影响上层逻辑。3.2 指标计算与信号生成量能饱和度和主力增仓是怎么算出来的网络热词里出现了“量能饱和度圆圈1.00指标公式源码”和“主力连续增仓指标源码”我在这套系统里找到了类似实现可以给你拆一下背后的思路。量能饱和度本质上是衡量当前成交量在近期成交量区间中所处位置的指标。常见算法是# indicator/volume_saturation.py import pandas as pd def volume_saturation(df: pd.DataFrame, lookback: int 20) - pd.Series: vol df[volume] low vol.rolling(lookback).min() high vol.rolling(lookback).max() sat (vol - low) / (high - low 1e-10) return sat.clip(upper1.0)它在图形上显示为一个0到1之间的数越接近1.00意味着当前成交量越接近近期最大值说明资金参与度极高但要警惕放量滞涨。注意我说的是“警惕”而不是“立即卖出”任何单一指标都不能当决策依据这套系统也只是把它渲染出来辅助你观察。主力连续增仓通常不是靠成交量而是靠“资金流向”类数据估算的。如果你想实现一个简化版可以假设大单成交额占比作为主力买入力度的近似比如将单笔成交额大于某个阈值比如20万元的累计成交额与总成交额的比值作为强度值再做N日累加。它本质上是对资金行为的一种统计近似做不到绝对精确但在个人观察场景里够用了。信号生成模块是把多个指标的结果汇总生成可视化标记点的逻辑。源码里默认做了金叉死叉信号当MA5上穿MA20且量能饱和度大于0.8时标记一个橙色买入观察点当MA5下穿MA20且量能饱和度小于0.2时标记一个绿色风险点。这套逻辑你可以完全自定义比如把MACD的DIF/DEA交叉加进去或者加入RSI超买超卖区间判断。核心就是信号模块只消费指标模块的输出不关心指标怎么算保证单一职责。3.3 Web展示层K线图怎么画的数据接口怎么设计的前端展示层源码用的是Flask ECharts。Flask负责提供数据APIECharts负责画K线图、分时图和指标曲线。核心API通常就这么几个GET /api/kline?symbol600519perioddaily 返回: { dates: [...], kline: [[open, close, low, high], ...], volume: [...], ma5: [...], ma20: [...], signals: [...] } GET /api/minutes?symbol600519 返回当日分时数据Flask端的实现很简单读数据库然后拼JSON# web/app.py from flask import Flask, jsonify, render_template, request import pymysql import pandas as pd app Flask(__name__) def query_df(sql, paramsNone): conn pymysql.connect(hostlocalhost, userroot, passwordroot123, databasestock, charsetutf8mb4) df pd.read_sql(sql, conn, paramsparams) conn.close() return df app.route(/api/kline) def api_kline(): symbol request.args.get(symbol, 600519) period request.args.get(period, daily) df query_df( SELECT date, open, high, low, close, volume FROM kline WHERE symbol%s ORDER BY date, (symbol,) ) return jsonify({ dates: df[date].astype(str).tolist(), kline: df[[open, close, low, high]].values.tolist(), volume: df[volume].tolist() }) app.route(/) def index(): return render_template(index.html)ECharts的K线图用candlestick系列配置项不算复杂但有几个细节容易踩坑第一K线数据的格式是[open, close, lowest, highest]不是[open, high, low, close]顺序写错图形会完全乱掉第二日期必须转成字符串否则ECharts时间轴没法正确显示第三如果数据量太大建议前端做dataZoom缩放限制否则一次渲染几千根K线浏览器会很卡。3.4 添加自定义股票池的完整操作流程这套系统默认股票池写在config.yaml里改完之后需要重启后端。如果你想实现“前端页面动态添加股票”需要额外做两个小改动。第一建一张watchlist表CREATE TABLE watchlist ( id INT PRIMARY KEY AUTO_INCREMENT, symbol VARCHAR(10) NOT NULL UNIQUE, name VARCHAR(50), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP );第二在collector/collect.py里增加一个读取watchlist表的函数数据采集启动时不再读取config.yaml里的stock_pool而是从数据库实时读取后续你在页面上增删自选就只需操作这张表了。4. 常见问题与排查技巧我踩过的坑都在这里4.1 数据源接口报错、数据字段对不上的情况最高频的问题就是akshare接口字段变了比如早期版本返回的是中文列名“日期”“开盘”某天代码更新之后变成了“timestamp”“open”如果你的源码是按固定列名硬编码的就会直接KeyError。排查方法很简单在Python里手动调用一下对应的akshare接口把返回的列名打出来跟源码里的做对比import akshare as ak df ak.stock_zh_a_hist(symbol600519, perioddaily, adjustqfq) print(df.columns.tolist()) print(df.head())对比之后把源码里的rename映射表改一下就行。这个我建议你尽早给base_source的get_kline方法加一层自适应逻辑比如先判断列名再统一标准化能省下以后很多心力。另一个经验是akshare做数据采集一定要限制请求频率建议每次请求后sleep(0.5)左右否则连续请求几十次之后容易触发接口限流表现为返回数据全是空或者直接超时。4.2 中文乱码与编码问题如果你发现数据入库后中文全是乱码或者前端页面出现“锟斤拷”这种经典乱码先查三处第一MySQL连接串里有没有charsetutf8mb4第二建表时字符集是不是utf8mb4第三前端页面meta charsetutf-8有没有写对。这三处是串联关系任何一处缺了都会乱码。我接手过的源码里有一个版本在创建表时没有指定字符集MySQL默认用了latin1导致所有股票名称直接变成乱码。处理方案是把表删掉重建或者用ALTER TABLE stock_kline CONVERT TO CHARACTER SET utf8mb4。如果你是刚启动还没积累数据建议直接删库重来省事。4.3 数据库连接被拒、端口占用、缓存异常等环境问题这一类问题我整理成速查表对照着排查效率最高问题现象常见原因解决方案Cant connect to MySQL serverMySQL容器没起来或端口映射错误docker ps查看容器状态检查compose文件端口映射Table stock.kline doesnt exist未初始化建表执行python -m collector.init_dbAuthentication plugin caching_sha2_passwordMySQL8默认认证插件导致连接串中指定auth_pluginmysql_native_password前端页面样式丢失静态资源路径引用错误检查HTML里CSS/JS引用路径改为url_for写法Redis连接超时Redis服务未启动或端口被占用执行docker-compose up -d redis检查6379端口采集数据时卡住不动接口限流或网络问题增加请求间隔sleep(0.5)检查网络代理设置4.4 一个容易忽略的坑数据库连接不释放导致卡死这套源码里有一个非常隐蔽的BugFlask的query_df函数每读一次数据就建立一次MySQL连接但没有正确关闭。当刷新页面频率高的时候数据库连接数会一直累积最终报Too many connections。修复方案有两种。第一种用with语法自动管理连接def query_df(sql, paramsNone): conn pymysql.connect(hostlocalhost, userroot, passwordroot123, databasestock, charsetutf8mb4) try: df pd.read_sql(sql, conn, paramsparams) finally: conn.close() return df第二种给Flask加一个连接池SQLAlchemy或者直接用dbutils.PooledDB。个人建议你直接上连接池因为行情页面一刷新就是好几个接口请求每请求一次新建连接一次对MySQL压力非常大并发一高页面就崩了。我后续改造时用了dbutils的PooledDB效果立竿见影并发刷新也不卡了。4.5 指标计算出现NaN和信号标记错位的解决方案很多人在日线数据里算MA、MACD都没问题一旦切到分钟级别就发现数据前面的N个窗口全是NaN。这是因为分钟数据往往有缺失比如股票停牌、集合竞价时段数据不完整导致rolling窗口计算时出现空窗口。我的经验是在计算指标前先对DataFrame做一次去重和排序然后对缺失的时间点做前向填充只有极少数确实缺失的位置才保留NaN最后统一用dropna()把指标序列前端的NaN行删掉避免把空值传到前端渲染。信号标记错指的是买卖点标记和K线日期对不上这个几乎都是因为日期索引错位。在写信号逻辑时一定不要用range(len(df))这种隐式索引去回溯位置而应该始终基于df[date]做对齐。比如生成信号后直接把信号存成{date: 2024-03-01, type: buy_note, price: 168.5}这样的结构前端通过date匹配K线位置而不是靠数组下标这样才能彻底杜绝错位。5. 后续玩法扩展这套源码还能怎么改着玩跑通基础功能只是第一步个人做技术研究真正的乐趣在于把它改造成自己想要的样子。我基于这套源码做过几个方向的扩展选两个我认为性价比最高的跟你说一下。第一把数据存储切到ClickHouse或DuckDB。如果你要存全市场5000多只股票的多年分钟数据MySQL很快就会变成瓶颈。我后来把日线数据留在MySQL分钟数据放到DuckDB单机分析配合Python的duckdb库直接跑SQL做聚合速度快了一个量级而且免运维。对于个人研究来说DuckDB这种嵌入式列式数据库比MySQL更适合做行情数据的OLAP分析但前提是你的数据量到了一定规模才值得切换几千只股票的日线数据MySQL完全扛得住。第二加一个定时采集任务。用系统的cron或者APScheduler定期执行采集脚本每天收盘后自动更新当天所有自选股的数据再触发指标计算和信号更新这样每天早上打开页面看到的就是最新的信号状态。我实操中是把采集脚本打包成Docker镜像再用宿主机的cron每天15:30执行一次容器任务日志重定向到文件方便排查稳定跑了两三个月没出过问题。第三接入企业微信/钉钉机器人推送信号。当指标系统触发了你预设的买入观察或风险条件时通过Webhook推一条消息到手机。这个功能不大但收益明显相当于把你的行情观察站变成了移动端提醒工具。实现时只需要在信号生成模块里加一个notify函数调用Webhook地址POST一段JSON即可。我在实际跑这套系统的过程中最大的感受是所谓“最新源码”不一定真的有多新代码质量也参差不齐但它的价值在于给你一个可以跑的框架让你从零开始搭一套行情分析系统至少省掉两周时间。如果你能花一个周末把数据采集、指标计算、Web展示这条链路彻底跑通并读懂之后再在这套框架上换数据源、加指标、做信号推送都是水到渠成的事情。最后一个建议任何网络上下载的源码包运行前务必先大体浏览一遍代码确认没有读取敏感信息或外发数据的逻辑再放数据进去。你可以查一下有没有可疑的外部请求地址看看requirements.txt里有没有莫名其妙的依赖包这是基本的自我防护意识跟这套系统本身没有关系但值得养成本能。本文还有配套的精品资源点击获取
返回列表