mytrashcan/MarketGuard
GitHub: mytrashcan/MarketGuard
一款基于规则的韩国股票市场异常检测系统,通过 Toss 证券公开 API 实时监测行情异动并提供运维告警仪表盘。
Stars: 1 | Forks: 0
# MarketGuard
[](https://github.com/mytrashcan/MarketGuard/actions/workflows/ci.yml)
MarketGuard 是一个组合项目,它**仅读取** Toss 证券 Open API 的**公开市场数据**,通过基于规则的模型检测异常迹象,并在运维仪表盘中进行记录和告警。
## 核心特性
- 仅查询当前价、报价、K线、涨跌停限制、投资警告、交易日历以及 KRX 各市场投资者交易额
- 基于 `BigDecimal` 的价格/比例计算,并保留官方市场时间戳
- 包含 8 种检测规则、结构化的观测依据、按规则进行故障隔离、持久化的原子冷却机制
- 对同一股票信号进行事件分组,提供可解释的 0~100 关注度评分,支持审查状态、备忘录及历史记录
- 具备超时控制、按官方调用分组的 rate limit、选择性重试、`Retry-After` 以及 circuit breaker
- 运维 HTTP Basic 认证,loopback 写入 token,严格的 WebSocket Origin 校验,输入限制,分 peer 的 API rate limit,以及 CSP/SRI 防护
- 使用 PostgreSQL + Flyway + Hibernate schema validation
- 支持 Prometheus 指标、liveness/readiness 探针及安全的审计日志
- 采用真实的 PostgreSQL Testcontainers 测试与 Docker Compose 冒烟测试
## 架构
```
flowchart LR
Browser["Operator browser"] -->|"Basic auth / HTTPS"| Web["Dashboard + read API"]
Web --> App["Application services"]
Scheduler["Bounded schedulers"] --> App
App --> Core["Framework-free detection core"]
App --> DB[("PostgreSQL / Flyway")]
App -->|"OAuth2 + bounded REST"| Toss["Toss Open API"]
Core --> App
App -->|"STOMP alerts"| Browser
```
源代码依赖方向为 `config/collector/dashboard/domain -> application/detection`。`detection` 核心模块没有引入 Spring/JPA/外部层,这一点由架构测试强制保证。详情请参阅 [architecture.md](docs/architecture.md)。
## 检测规则
| 规则 | 判定基准 |
|---|---|
| `PRICE_SPIKE` | 相对于近期平均价格的波动达到设定比例以上 |
| `PRICE_LIMIT` | 达到涨停/跌停价或接近至设定比例以内 |
| `ORDERBOOK_IMBALANCE` | 买/卖总订单量比例超过阈值 |
| `VOLUME_SURGE` | 最新一分钟成交量达到前一平均值的阈值倍数以上 |
| `INVESTMENT_WARNING` | 当前存在有效的投资警告、风险、短期过热或清算交易指定 |
| `PRICE_VOLUME_SURGE` | 价格波动与 1 分钟成交量同时超过各自阈值 |
| `INSTITUTIONAL_NET_BUY_SURGE` | KOSPI/KOSDAQ 机构净买入同时超过近期中位数的指定倍数与最低金额 |
| `INSTITUTIONAL_NET_SELL_SURGE` | KOSPI/KOSDAQ 机构净卖出同时超过近期中位数的指定倍数与最低金额 |
每个信号都会同时记录标题、摘要、通俗说明、观测值、基准值、阈值、比较范围、上下文标签以及补充确认项。各规则独立运行,某一个规则的异常不会中断对其他规则的评估。如果市场日历获取失败,采集器会将其视为收盘状态,以避免用过期数据产生误报。计算公式与边界条件请参阅 [检测规则文档](docs/detection-rules.md)。
## 界面数据的含义
- 主界面展示 Toss 市场的整体交易额、交易量、上涨和下跌排行。排名及 `lastPrice`、`basePrice`、`changeRate`、交易量、交易额均使用同一响应中的数据。
- 兼容 API `/api/prices/live` 中的“买/卖”并非实际成交比例或各投资者净买入,而是公开买卖盘中的**未成交买/卖订单量比例**。系统会区分场外、未提供数据与 upstream 错误,将其与 0 区分开来。
- 机构资金流向信号是 KOSPI/KOSDAQ **市场整体合计**数据。它不代表个别股票或特定机构的交易,收盘前的当日数据均为不断更新的暂定值。
- 检测事件会同时保存股票或市场名称及其代码。历史数据在迁移时会将股票代码作为安全的名称回退。
## 快速开始
环境要求为 JDK 17 和 Docker。
```
./gradlew clean test
./gradlew bootRun
```
默认配置为安全的本地开发模式。
- 仅绑定至 `127.0.0.1:5050`
- 禁用采集器
- 禁用身份验证
- 使用内存 H2 及本地 H2 控制台
仪表盘地址:`http://127.0.0.1:5050/`
开启实际采集需要 Toss 的凭证,若缺失任何一项,程序将启动失败。
```
export TOSS_CLIENT_ID='...'
export TOSS_CLIENT_SECRET='...'
export COLLECTOR_ENABLED=true
./gradlew bootRun
```
## Docker Compose
```
cp .env.example .env
# 编辑 .env 的必填值
docker compose up --build --wait
```
若设置 `collector=false`,则无需 Toss 凭证即可验证安全的运行环境包。仅在需要实际采集时,才设置 `TOSS_CLIENT_ID`、`TOSS_CLIENT_SECRET` 和 `COLLECTOR_ENABLED=true`。
Compose 强制执行以下限制:
- 数据库密码无默认值;若开启身份验证,缺少运维密码将导致启动失败
- PostgreSQL 主机端口不对外公开,使用 named volume
- 应用端口仅对主机 loopback 公开
- 采用 non-root 应用、只读 root filesystem 并移除多余 capability
- 只有在 readiness 探针通过后才标记为 healthy 状态
完整且可复现的冒烟测试:
```
./scripts/compose-smoke.sh
```
## API 与运维端点
在生产配置下,除探针外,所有路径均默认需要身份验证。仅在主机 loopback 使用的个人部署环境,可以通过 `.env` 中的 `MARKETGUARD_SECURITY_ENABLED=false` 关闭登录界面。即使在该设置关闭的情况下,若缺少 `MARKETGUARD_OPERATOR_TOKEN`,更改事件状态或添加备忘录的写操作也会被拒绝。设置足够长的随机 token 后,仪表盘在首次写入时会要求输入 token,并将其存储在浏览器的 `localStorage` 中,随后作为 `X-Operator-Token` 请求头发送。
```
MARKETGUARD_SECURITY_ENABLED=false
MARKETGUARD_OPERATOR_TOKEN="$(openssl rand -hex 32)"
```
CSRF token 依然必需,并且审查者和作者由服务器根据已认证的 principal `operator` 来判定,而非由客户端输入决定。此模式下的查询 API 和 `/api/audit` 是有意允许匿名访问的,因此请勿将端口公开至外网,也不要连接到无需认证的 reverse proxy 或隧道中。该 token 仅用于保护写入完整性,并不提供查询数据的机密性保障。
下方的匿名访问表格基于默认开启身份验证的模式。
| 路径 | 说明 | 匿名访问 |
|---|---|---|
| `GET /api/prices/live` | 关注列表实时看板 | 否 |
| `GET /api/rankings?type=MARKET_TRADING_AMOUNT&limit=50` | 服务器缓存的 Toss 市场排行,`limit=1..100` | 否 |
| `GET /api/stocks/{code}/candles?interval=1m&count=60` | 1分钟/日 K 线,`count=1..200` | 否 |
| `GET /api/anomalies?limit=50` | 近期异常记录,`limit=1..200` | 否 |
| `GET /api/anomalies/{id}` | 结构化的单一信号依据 | 否 |
| `GET /api/cases?...` | 事件列表,支持 pagination 及状态/规则/严重程度/股票/时间/评分过滤 | 否 |
| `GET /api/cases/{id}` | 评分构成、时间线、备忘录及状态历史 | 否 |
| `PATCH /api/cases/{id}/status` | 基于版本的状态变更 | 否 |
| `POST /api/cases/{id}/notes` | 添加审查备忘录 | 否 |
| `GET /api/stocks/{code}/context` | 价格/成交量图表及当前可用的市场背景 | 否 |
| `GET /api/analytics/rules` | 各规则的触发、驳回、审查前列及平均审查时间 | 否 |
| `GET /api/csrf` | 浏览器写入请求所需的 CSRF token | 否 |
| `GET /api/audit?limit=100` | 近期审计记录 | 否 |
| `GET /api/stocks/{code}/snapshots?limit=50` | 近期行情快照 | 否 |
| `GET /actuator/health/liveness` | 进程存活状态 | 是 |
| `GET /actuator/health/readiness` | 应用/数据库准备状态 | 是 |
| `GET /actuator/prometheus` | Prometheus 指标 | 否 |
错误的输入将返回稳定的 `400` JSON,永久性 upstream 错误返回 `502`,临时性错误或 circuit breaker 触发返回 `503`。响应中不包含内部异常、upstream 响应体或任何凭证信息。
## 验证
```
# 如果没有 Docker socket,PostgreSQL 集成测试将不会作为成功跳过,而是直接失败。
./gradlew clean check bootJar
docker build -t marketguard:local .
./scripts/compose-smoke.sh
```
CI 包含 Gradle wrapper 校验、全量测试、65% 行覆盖率卡点、CodeQL/依赖审查、强化镜像构建与扫描,以及 Compose 冒烟测试。GitHub Actions 与 Docker base image 均通过 commit/digest 锁定。
## 运维与安全
- 生产环境部署、TLS reverse proxy、备份与恢复、指标与告警:[operations.md](docs/operations.md)
- 信任边界与安全控制:[threat-model.md](docs/threat-model.md)
- 设计与分层规则:[architecture.md](docs/architecture.md)
- 事件 API 契约:[api.md](docs/api.md)
- 综合评分:[composite-score.md](docs/composite-score.md)
- 审查状态流转:[case-workflow.md](docs/case-workflow.md)
- 数据模型:[data-model.md](docs/data-model.md)
- 误报与局限性:[false-positives-and-limitations.md](docs/false-positives-and-limitations.md)
- 漏洞报告与机密信息处理准则:[SECURITY.md](SECURITY.md)
- 初步审计结果及解决状态:[production-readiness.md](docs/review/production-readiness.md)
## 限制说明
- Toss 每个 client 仅允许保留一个有效 token,因此对于共享同一 client credential 的应用,仅支持 **1 个** replica。
- 内置的 STOMP broker 与 API rate limiter 仅在单进程范围内有效。
- 告警发送在数据库 commit 之后以 best-effort 方式进行。断开连接的浏览器可通过查询数据库中的近期 anomaly API 进行恢复。
- anomaly/audit 的长期保留策略需根据生产环境的合规与成本需求另行制定。
- 公开部署必须置于 TLS reverse proxy 及网络 ACL 保护之下。
- 由于缺乏行业/市场指数时间序列、公告、新闻及 corporate action 数据,相对收益率与事件背景不会被凭空捏造。当前 API 会将此类背景信息明确标记为 `unavailable`。
标签:JS文件枚举, PostgreSQL, Spring, 后台面板检测, 域名枚举, 异常检测, 测试用例, 版权保护, 监控大屏, 股票市场, 自定义请求头, 请求拦截, 金融科技