← 返回主页
TECH

ShareSim:虚拟股票交易系统前后端架构拆解

ShareSim 是部署在我本人博客 guyivip.top 下的一个“附加模块”。它既要像普通静态页面一样能从博客导航直达,又要具备用户注册登录、持仓、交易流水、行情查询等动态能力。 为了让它在你的服务器上长期稳定运行,同时最大化复用你现有站点环境(宝塔 Nginx、HTTPS、静态站点结构),整体采用“静态主站 + 子路径反向代理 + 轻量后端”的组合架构。

1. 技术栈一览

  • 后端:Flask(路由/API/会话) + Gunicorn(生产 WSGI 运行)
  • 数据:SQLite(单文件数据库,免运维,适合个人站点低并发场景)
  • 行情:Tushare(实时行情 + 历史 K 线)
  • 前端:多页 HTML + 原生 JavaScript(无构建依赖,便于上传部署)
  • 部署:宝塔 Nginx 监听 80/443,对外提供 HTTPS;反向代理到服务器本机 127.0.0.1:8080
一句话概括:Gunicorn 只负责“动态能力”,Nginx 负责“对外入口与 HTTPS”,ShareSim 只占用一个子路径 /share/,不影响主站静态页面。

2. 为什么采用这种架构(以及它的好处)

我本人博客主站是静态网站,稳定性很好;ShareSim 作为附属功能,不应该引入复杂的前端工程化或数据库运维。架构决策围绕三个目标: 最小侵入低成本运维上线可靠

  • 只新增一个子路径:对外入口固定为 /share/,主站其他路径继续走静态站点逻辑。
  • 后端端口不暴露公网:Gunicorn 绑定 127.0.0.1,外网无法直接访问 8080,降低安全风险。
  • HTTPS 一处管理:TLS 证书、HTTP/2 等交给 Nginx,后端不用处理证书配置。
  • SQLite 免运维:单文件、无需服务进程,迁移只需带走 app.db
  • 前端免打包:多页 + 原生 JS,减少 Node 依赖与构建步骤。

3. 目录结构与职责划分

guyivip.top/
└── share/
    ├── app.py                 # Flask 入口(create_app 工厂模式)
    ├── price_provider.py      # Tushare 行情(实时/历史)
    ├── app.db                 # SQLite 数据库(用户/持仓/流水)
    ├── requirements.txt       # Python 依赖
    ├── start.sh               # 一键启动(venv + gunicorn)
    └── static/
        ├── login.html
        ├── dashboard.html
        ├── trade.html
        ├── portfolio.html
        ├── transactions.html
        ├── styles.css
        └── js/
            ├── common.js      # 子路径适配、API 封装、鉴权跳转
            ├── auth.js
            ├── dashboard.js
            ├── trade.js
            ├── portfolio.js
            └── transactions.js

4. 后端:Flask + Gunicorn 的关键设计

后端使用 create_app() 工厂函数提供 Flask 实例,由 Gunicorn 以 app:create_app() 启动。 工厂模式的优势是启动入口清晰、初始化集中、部署与测试更稳定。

./venv/bin/gunicorn -w 2 -b 127.0.0.1:8080 'app:create_app()'

API 设计遵循“页面走 HTML、数据走 JSON”的方式:页面访问 /share/login.html,数据请求走 /share/api/*

5. 数据:SQLite 表与业务含义

  • users:用户名、密码哈希、现金余额
  • holdings:按用户维度记录持仓(股票代码、股数、均价)
  • transactions:每笔买卖成交记录(方向、价格、股数、时间)
为什么 SQLite 够用:个人博客场景用户少、并发低,SQLite 性能完全足够;而且不用维护 MySQL/Postgres 服务进程,部署体验更好。

6. 行情:实时 + 历史的组合链路

ShareSim 对行情的需求分为两块:下单前查价(实时)与图表展示(日 K、历史)。实时链路优先使用实时接口;历史数据需要 token。

export TUSHARE_TOKEN=你的token
export TUSHARE_PROXY=http://你的代理:端口/

生产环境下强烈建议把这些环境变量写进 systemd 或 shell profile,否则你用 nohup 重启服务时可能丢失 token,导致行情不可用。

7. 前端:多页 + common.js 的路径自适应

模块部署在 /share/ 下,前端通过 common.js 统一处理路径拼接、鉴权跳转与 API 请求,避免“登录后跳转 404”这类子路径问题。

页面之间跳转使用固定的 *.html 文件名,保证可读性与运维排查效率(看到 URL 就知道对应哪个页面)。

8. 部署过程(从 0 到上线)

典型部署顺序是:先确保 Gunicorn 本机可访问,再让 Nginx 把 /share/ 代理给它。

curl -I http://127.0.0.1:8080/login.html
curl -I https://guyivip.top/share/login.html

Nginx 反代配置示例:

location ^~ /share/ {
    proxy_pass http://127.0.0.1:8080/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

9. 这套架构的边界与改进方向

  • 并发:当前 2 个 sync worker 适合低并发;更高并发可评估 gevent/async 或引入缓存。
  • 交易规则:可加入手续费、滑点、涨跌停、交易时间等规则,让模拟更接近真实市场。
  • 可观测:可加入更清晰的日志与监控,但会增加运维复杂度。
入口虚拟股票交易交易页Trade