ARTICLE DETAIL

资讯详情

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

自建开源股票分析系统:OpenStock从零到一实战指南

自建开源股票分析系统:OpenStock从零到一实战指南 刚把 OpenStock 折腾起来的时候我就在想一个问题市面上现成的股票软件那么多为什么还要自己搭一套开源的用了几天之后我有了答案——数据、策略、界面全部握在自己手里你需要什么就加什么不舒服就改这才是个人投资者该有的工具状态。这篇就把 OpenStock 从零到一的搭建过程、数据采集、策略计算、展示看板这些环节完整拆开讲适合有一点 Linux 和 Python 基础、想自建个人股票分析系统的朋友参考。1. 为什么我选择自建一套开源股票分析系统1.1 OpenStock 解决的是什么问题我们平时打开券商 App 或者行情软件能做的事情其实非常固定看行情、看 K 线、看几个预设指标顶多加个自选股提醒。真正做投资分析的时候痛点马上就冒出来了。第一是数据不够灵活。你想统计某只股票过去三年每个季度的营收增速和股价表现之间的关系行情软件做不到这种颗粒度的分析。第二是指标不能自定义。软件里给你什么指标你就用什么想改个参数、想组合两个因子完全没门。第三是数据不透明。很多技术指标到底怎么算的软件不给你看公式你只能当黑箱用。OpenStock 就是奔着这几个痛点去的。它是一个开源的个人股票数据分析系统把行情数据采集、本地化存储、技术指标计算、策略信号生成、可视化展示整合到一套体系里。部署好之后所有数据都存在你自己的机器上所有指标算法都是代码里写得明明白白的你可以随时改、随时加、随时看。我当时就想要一个东西能让我自己定义“什么时候买入、什么时候卖出”规则的系统。OpenStock 恰好做到了这一点而且整个项目结构简单清晰适合个人用户深耕。1.2 项目整体架构与设计思路OpenStock 的整体架构可以拆成四个核心模块数据采集层、数据存储层、计算分析层和展示层。数据采集层负责从公开行情接口拉取股票的日线、分钟线、财务等基础数据。这一层是定时执行的每天收盘后自动跑一遍把当天的数据更新到本地数据库里。数据存储层用的是一套非常轻量的时序数据方案我在后文会详细讲。计算分析层是核心中的核心所有技术指标、策略信号都在这一层算出来。展示层就是一个 Web 界面你打开浏览器就能看到 K 线图、指标曲线、信号标记也可以作为简单的量化研究入口。这套架构最值得称道的地方是解耦。每一层都是独立的模块互不干扰。想换数据源只动采集层想加策略只写计算层的代码想换漂亮的界面只换展示层。对于个人项目来说这种设计意味着你可以随时在某个局部进行升级而不需要把整个系统推倒重来。1.3 技术选型背后的权衡关于技术选型我看过不少同类项目有的用 Java 写后端、有的用 Go、有的干脆就是 Jupyter Notebook 一堆笔记本。OpenStock 最终选择 Python 生态我觉得核心原因是 Python 在数据处理上有绝对优势。pandas 处理 DataFrame 数据的效率极高写个技术指标计算也就几行代码的事。而且 Python 的量化生态太成熟了backtrader、TA-Lib、numpy 这些都是现成的轮子不用自己造。再加上 Python 社区的文档质量普遍不错遇到问题搜一下基本就能解决对个人开发者非常友好。存储层选型我多说两句。有些项目用 MySQL 存行情数据有些用 MongoDBOpenStock 这类项目通常用的是 SQLite 加内存缓存或者直接基于文件存储。原因很简单——行情数据是典型的时序数据写入多、查询多、修改少用传统关系型数据库反而杀鸡用牛刀。而且个人用的行情数据量并不大A 股全市场 5000 多只股票每天日线数据也就几万条SQLite 完全撑得住省去部署数据库服务的麻烦。2. 环境准备与基础部署2.1 硬件与系统要求先说说跑 OpenStock 需要什么样的环境。别担心要求很低我手头一台几年前的老笔记本4 核 CPU、8GB 内存跑起来都很流畅。如果要跑全市场数据采集建议至少 4GB 内存只关注自选股的话2GB 内存都够。操作系统方面Linux 和 macOS 都行Windows 用户建议装个 WSL2 或者直接用 Docker。我对 Docker 方案也很推荐后面的部署流程会给出两种方式。磁盘空间的话只存日线数据几百兆就够用了。但如果你想存分钟线数据那就要按年乘以 240 个交易日来算一年大概 8GB 左右建议给足 50GB。2.2 两种部署方式Docker 与源码手动装部署 OpenStock 有两条路Docker 一键部署和源码手动安装。我个人推荐第一次先试 Docker跑通了再换源码方式去改代码。先看 Docker 方式。项目仓库里带了 docker-compose.yml 文件里面定义了数据库、定时任务、Web 服务这些服务。只需要一条命令就能把整套环境拉起来docker-compose up -d等几秒钟打开浏览器访问 http://localhost:8080 就能看到主界面。源码方式也不复杂。先把项目代码 clone 下来然后创建虚拟环境、安装依赖git clone https://github.com/openstock/openstock.git cd openstock python3 -m venv venv source venv/bin/activate pip install -r requirements.txt这里特别提醒一句一定要用虚拟环境不要直接装在系统 Python 里。我之前偷懒图省事直接把依赖装进了全局环境结果和系统自带包冲突折腾了一个多小时。用虚拟环境隔离是最稳妥的做法。2.3 初始化配置的五项关键设置第一次启动前需要修改配置文件。OpenStock 的配置集中在 config 目录下核心是 config.yaml 文件。我挑几个第一次部署必须设置的参数说明数据源配置。配置文件里有一项 data_source可以指定使用哪个行情接口。有些数据源需要申请 API token建议把 token 写到环境变量里而不是直接写死在配置文件中防止将来把配置上传到 GitHub 时泄露密钥。股票池设置。stock_pool 参数控制系统监控哪些股票。你可以填“全部 A 股”也可以填自己关注的十来只股票。我先用自选股测试跑通全流程之后才扩大到全市场这个循序渐进的方式可以大大降低排查问题的难度。更新频率。update_schedule 参数控制数据采集频率。默认是每个交易日 15:30 执行一次完整更新。如果你想盘中盯盘也可以配置成每 5 分钟拉一次实时数据。预警规则。alert_rules 是信号告警的配置可以设置某些指标触发的提醒条件我后面会展开讲。时区设置。这个很多人漏掉但非常重要。如果你的服务器部署在海外或者使用 Docker 容器时默认时区是 UTC那数据采集的“定时”就会差 8 个小时。一定要在配置中显式设置 Asia/Shanghai 时区。提示配置完成后先手动执行一次python manage.py init_db初始化数据库再执行采集命令测试数据源是否正常确认无误后再开启定时任务。3. 数据采集与存储实战3.1 行情数据源怎么选择数据源是整个系统的基础数据不准后面全是白搭。OpenStock 目前支持多个公开数据源接入使用频率较高的有 akshare、baostock 这类开源库也有项目自带的接入模块。这里需要说明一句行情数据的获取依赖公开数据接口不同数据源在字段完整度、更新延迟、调用频率限制上差别很大。我实测下来的体验是日线数据几个主流源差距不大但分钟线和财务数据差异就很明显了。我建议的策略是日线数据用源 A 作为主力分钟线数据用源 B 作为补充。OpenStock 的架构支持多源并存通过配置就可以实现。我自己的配置是日线、周线数据从一个源拉财务数据从另一个源拉两个源的数据在数据库里用不同的表前缀区分。3.2 数据库表设计要点这一节虽然是技术细节但理解了表结构你就知道数据是怎么流转的后面排查问题会轻松很多。OpenStock 的数据库核心表结构大致是这样的stock_basic股票基础信息表包括股票代码、名称、行业、上市日期等。这张表是系统运行的基石其他所有表的外键基本都关联到这里。daily_price日线行情表包含日期、开盘价、收盘价、最高价、最低价、成交量、成交额这些标准字段。为了查询速度这张表通常按股票代码加日期建立联合索引。minute_price分钟线数据表字段和日线类似多了一个 timeframe 字段来区分是 5 分钟还是 30 分钟线。indicator_value指标计算结果表保存各种技术指标在每一天的值。设计这张表时把指标名称和参数编码成一个字符串这样可以灵活扩展不用每个指标建一张表。trade_signal策略信号表记录策略触发的买卖信号包括信号类型、触发时间、当时的市场价格、策略名称等。我在第一次看这套表结构的时候觉得有个细节非常精妙指标结果不直接覆盖在行情数据上而是单独存一张表通过股票代码加日期关联。这样设计的好处是你可以跑多个不同参数的指标随时切换对比互不影响。3.3 数据采集任务的运行机制数据采集的核心逻辑不复杂但边界情况很多。OpenStock 的采集流程是这样设计的每到一个采集时间点调度器会检查所有股票代码逐只拉取数据。对于已经有历史数据的股票系统会获取数据库里最新一条记录的日期然后只增量拉取这个日期之后的数据。对于数据库里没有的新股票则执行一次全量历史数据拉取。这里有个参数需要配置初始回测日期的设置。如果你只想研究最近一年的数据把 init_start_date 设成一年前的日期第一次采集就会只拉一年的数据。我当时直接设成了八年前因为想拿一只股票在上一轮完整牛熊周期的表现来验证策略后来发现数据量太大拖慢了采集速度最后压缩到了三年。采集任务本身支持断点续传。如果某只股票拉到一半网络中断重新运行采集任务时不会从头开始而是从断点继续。这个机制在实际使用中太重要了我第一次跑全市场采集时断了三次全靠断点续传保住了进度。4. 策略分析与信号计算4.1 技术指标的计算原理数据到位之后重点戏来了策略分析和信号计算。OpenStock 内置了均线、MACD、RSI、布林带等常用技术指标的计算模块。以均线为例它的计算逻辑简单得不能再简单把最近 N 天的收盘价加起来除以 N。但 OpenStock 在实现上用的不是普通数组循环而是借助 pandas 的 rolling 方法做滑动窗口计算速度极快import pandas as pd def calculate_ma(df, window): return df[close].rolling(windowwindow).mean()MACD 的计算稍微复杂一些涉及到 EMA 指数移动平均然后求 DIF、DEA、MACD 柱。OpenStock 的实现用了 ewm 方法可以避免自己写递归循环def calculate_macd(df, fast12, slow26, signal9): ema_fast df[close].ewm(spanfast, adjustFalse).mean() ema_slow df[close].ewm(spanslow, adjustFalse).mean() dif ema_fast - ema_slow dea dif.ewm(spansignal, adjustFalse).mean() macd (dif - dea) * 2 return dif, dea, macd你可能已经发现了这些指标本质上就是对历史价格数据做数学变换用来辅助判断市场状态。但我想多说一句自己的体会指标本身不产生超额收益产生超额收益的是你对指标含义的理解和组合方式。4.2 自定义策略规则的写法OpenStock 最能打的功能之一就是你可以直接写 Python 函数自定义策略规则。系统提供了一个策略基类你只需要实现一个generate_signals方法输入是行情数据输出是买卖信号。举个例子我想实现一个“均线金叉买入、死叉卖出”的经典策略class MaCrossStrategy: def __init__(self, fast_window5, slow_window20): self.fast_window fast_window self.slow_window slow_window def generate_signals(self, data): fast_ma data[close].rolling(self.fast_window).mean() slow_ma data[close].rolling(self.slow_window).mean() signals [] for i in range(1, len(data)): if fast_ma[i-1] slow_ma[i-1] and fast_ma[i] slow_ma[i]: signals.append({date: data.index[i], type: BUY}) elif fast_ma[i-1] slow_ma[i-1] and fast_ma[i] slow_ma[i]: signals.append({date: data.index[i], type: SELL}) return signals代码逻辑说白了就两层判断金叉买入、死叉卖出。但这里有两个细节值得注意。一是信号生成的延迟问题。用“当天的收盘价”计算均线信号在收盘之后才能确认你实际买入要等到第二天。所以真正落到策略回测时需要考虑信号延迟一个交易日。二是避免未来函数。如果你在回测时不小心用了未来数据比如当天的信号里包含了当天的数据回测结果会虚高得离谱。OpenStock 在回测模块里做了防未来函数的检查但你在自己写策略的时候依然要留意数据对齐问题。4.3 回测验证的关键细节策略写完当然要拿历史数据验证一下。OpenStock 内置了一个轻量回测引擎如果你之前用过券商软件里的回测功能可能会觉得这个引擎简单得有点“简陋”。但它是符合投资逻辑的源码摆在那里每一笔交易都算得明明白白不会像黑箱一样只给你一个收益率数字。回测的核心参数有三个初始资金、手续费率、滑点模型。手续费率我直接用万二点五加上卖出印花税千分之一滑点模型设置了固定滑点 0.02%尽量模拟真实交易环境。跑完回测之后不要只看总收益率和最大回撤我建议重点关注月度收益分布。如果一个月赚 20%、下个月亏 25%这种策略的体验会非常痛苦。OpenStock 的报告模块会生成收益曲线和回撤曲线配合监控列表里的最大连续亏损天数能比较全面地评估策略的真实表现。我自己的经验是一个策略至少要经过三轮验证才不会“见光死”第一轮用牛市的数据看它能不能跟上行情第二轮用熊市的数据看它能不能控住回撤第三轮用震荡市的数据看它会不会反复打脸。三轮测试下来还稳定的策略才值得放进实战观察名单。5. 可视化看板与告警配置5.1 界面功能拆解OpenStock 的可视化界面是基于 Web 的虽然不像专业行情软件那样酷炫但胜在干净实用。打开主界面后左侧是股票列表中间是 K 线主图下面是成交量副图技术指标的曲线可以叠加在主图上策略信号用红绿箭头标记。有几个功能我用下来觉得特别顺手自选股分组。你可以建不同的分组比如“白马股”“周期股”“高股息”每个分组单独查看行情和信号。对于同时关注多个板块的人来说这个功能省去了每次大量翻找的麻烦。信号复盘模式。把某只股票的历史信号全部显示在 K 线上每个买卖点都标出来。想验证策略的历史表现直接在这个模式下扫一眼就心里有数。数据导出。界面上可以一键导出 CSV 格式的行情数据或者信号记录。我用这个功能把信号记录导出来做二次分析用 Excel 透视表拉了按月胜率统计确实是自有数据才能做到的灵活度。5.2 告警通知的两种触发方式告警是 OpenStock 里非常实用的功能。它支持两种触发方式基于策略信号触发和基于价格阈值触发。基于策略信号触发就是你在策略里定义好的 BUY 和 SELL 信号被计算出来后系统会立刻推送消息。我在测试的时候特意把某只股票的买卖信号触发条件写得很敏感推消息验证确认链路没有问题后才调到正常参数。基于价格阈值触发则是给某只股票设置“涨到多少提醒我”或者“跌到多少提醒我”适用于对特定价位有心理预期的场景。告警的推送渠道开箱即用的通知渠道支持邮件和 Webhook。我的配置方式是服务器把信号推到 Webhook再由 Webhook 转发到个人常用的消息工具。邮件作为兜底备用。这样配置的好处是Webhook 通道如果偶尔延迟邮件记录还会保留一份完整的信号历史。5.3 日常怎么用才顺手系统搭好之后建议你给自己定一个相对固定的使用节奏。我的习惯是这样的每个交易日收盘后半小时打开 OpenStock 看一眼当天的信号变化每周五收盘后花半小时复盘本周所有触发的策略信号每月底做一次完整的持仓和策略表现统计。这套节奏不占用太多时间但能保证你不会错过关键的信息。如果连续几天都没有任何信号可能的情况有两种一是市场确实没有出现符合你策略的机会二是你的策略参数太迟钝了。这时就需要回头检查策略看是不是需要微调参数。6. 常见问题与排查技巧实录6.1 打开界面但看不到数据这是新手最容易遇到的问题服务启动正常界面也打开了但股票列表是空的K 线图也是空的。排查思路很简单按下面三步走第一步检查数据库里有没有数据。执行sqlite3 stock.db select count(*) from daily_price;看看行数。如果是 0说明数据采集根本没成功。第二步检查数据源接口是否正常。手动执行一次采集命令看输出的日志。如果报网络错误多半是源站限制或者网络不通如果报 token 无效就是配置的密钥有问题。第三步检查采集任务是否被调度执行。看定时任务的日志确认到了设定的时间点任务真的跑起来了而不仅仅停留在“已配置”的状态。我踩过的一个坑是采集命令手动执行成功了但定时任务没有执行。后来发现是容器里的时区不对默认 UTC 时间比北京时间晚 8 小时导致任务在“晚上 15:30”触发了排查日志看了半天才反应过来。这个问题在配置时区之后彻底解决。6.2 信号计算结果和行情软件对不上如果你同时用行情软件和 OpenStock可能会发现同一只股票的 MACD 值对不上。不要慌这不一定是 OpenStock 算错了很可能是指标参数的细节差异。最常见的差异来源有两个。一是 EMA 的初始值处理不一样有些软件用第一天的收盘价作为 EMA 初始值有些用前几天的平均值作为初始值这会导致前面几十个交易日的指标值有差异随着时间拉长逐渐收敛。二是复权方式不同前复权、后复权和不复权的数据算出来的指标差别很大。如果你用行情软件的前复权数据而 OpenStock 里存的是不复权数据那指标值对不上是必然的。解决方法是把复权设置保持一致。OpenStock 的数据源同步模块里通常会有复权配置选项设成和前复权一致计算结果就能基本对齐。6.3 回测结果过于理想要警惕如果你刚写完一个策略回测结果显示年化收益率 200%先别高兴这里面大概率有坑。最常见的问题是未来函数。比如你在算某个指标时用到了当天的收盘价和当天的某个未来确认信号实际上在收盘那一刻你是拿不到这个确认的。还有一种是数据泄露比如回测时用了整个时间段的数据做标准化这在真实交易中根本不可能实现。我的经验法是如果回测年化超过 50%先怀疑代码逻辑再怀疑策略本身。多数情况下回测结果过于漂亮都是因为参数过拟或者代码有 bug。6.4 关键注意事项速查表定期备份数据库文件OpenStock 的 SQLite 数据库可以直接复制备份建议每天收盘后自动备份一次。升级代码之前先备份配置文件和数据库新版代码可能包含数据库迁移逻辑降级会比较麻烦。行情数据源有调用频率限制不要盲目加大采集频率控制好任务调度的间隔。策略参数不要频繁修改数据会帮助你判断哪些修改有效哪些纯属手痒。最后再分享一个小技巧。如果你打算长期使用 OpenStock建议在拿到源码后先完整读一遍数据采集模块的代码。就算不深入改它理解它怎么处理重复数据、怎么应对接口返回缺失字段也能让你在系统出问题的时候更快定位原因。个人用开源项目最大的好处不就是什么都看得见、什么都能改吗搭建只是开始真正有意思的是在用的过程中把它逐步打磨成适合自己投资习惯的分析工具。
返回列表