Files
cryptoHermes/ai/adr/0001-architecture-foundations.md
dela cc7f5a4f32 feat: 初始化 cryptoHermes 行情网关 v1 MVP + harness 工程文档
Binance USDⓈ-M Futures 行情网关,给上游 Hermes 量化分析引擎提供单一聚合
接口 /v1/market/context(K 线 + funding + OI + 多空比 + taker volume)。
只读公共行情,不下单、不接私钥、不查账户。

## v1 实现范围(Milestone 1-5)

- Clean Architecture 4 层(controller/usecase/repo/entity),接口边界在
  internal/usecase/ports.go
- Binance Futures REST client(K 线 / ticker24h / funding / OI / 多空比
  / taker volume 共 9 个接口),全链路 string 价格避免 float64 精度问题
- TimescaleDB 5 张 hypertable(market_klines / funding_rates /
  open_interest / long_short_ratio / taker_buy_sell_volume),主键含
  时间维度,UpsertMany 幂等
- robfig/cron 定时采集(15m/1h/4h/1d/1w 多周期 K 线 + 衍生品 15 分钟
  落库),未收线 K 线 (close_time > now) 由 mapper/repo 双重过滤
- pkg/httpclient 统一限流(默认 20 req/s, burst 40)+ 重试,避免触发
  Binance 2400 weight/min IP 上限
- /v1/market/context 聚合接口:errgroup 并发拉 snapshot/funding/OI,DB
  K 线不足 200 根回源 Binance 异步补
- cmd/backfill CLI 支持指定 from/to 大段回填(Binance 历史 OI / 多空比
  官方只保留 30 天,必须自己存)
- Docker Compose + Makefile + golang-migrate,本地一键启

技术指标(support/resistance/Vegas/箱体)留待 v2,技术段返回空对象 +
warning 占位。

## Harness 工程文档

- AGENTS.md — AI agent 工作速查(10 个章节)
- ai/project-map.md — 仓库结构、扩展点、控制流
- ai/risk-guardrails.md — G1-G10 守卫规则(每条带可机械验证命令)
- ai/adr/0001-architecture-foundations.md — 9 条架构基础决策
- ai/task-templates.md — 6 种任务契约模板
- ai/harness-health.md — 当前 harness 健康度评估

3 个 grep 守卫已验证通过:controller / usecase 无具体实现依赖,全项目
无私钥/签名字段。
2026-05-24 17:20:51 +08:00

190 lines
7.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR 0001 — 架构基础决策
**状态**Accepted
**日期**2026-05-24
**决策者**:项目维护者
**适用范围**cryptoHermes v1 全部代码
---
## 背景
cryptoHermes 是给上游 Hermes 量化分析引擎用的 Binance Futures 行情网关。在 MVP 启动前需要锁定一组基础技术决策,避免后续 PR 反复重新评估。
需求边界(来自 `docs/dev.md` 第 1 章):
- 只读公共行情,不下单、不接私钥
- BTCUSDT / ETHUSDT分钟到周级 K 线 + 衍生品funding / OI / 多空比 / taker volume
- 历史数据必须自存Binance 历史 OI / 多空比官方只保留 30 天)
- Hermes 只调用 `/v1/market/context` 一个聚合接口
- 部署形态:单体服务 + Postgres国内开发机通过 HTTPS_PROXY 访问 Binance
---
## 决策
### D1. Web 框架Fiber v2
**选了 Fiber v2**(而不是 net/http 标准库、Gin、Echo、Chi
**理由**
- 性能足够fasthttp 底层),单体网关不需要再调优
- API 与 Express/Gin 相近,团队上手快
- 内置 recover/logger/req-id 中间件
- v2 稳定,社区活跃
**代价**
- 基于 fasthttp不兼容 `net/http` 中间件生态
- 错误类型用 `*fiber.Error`,需要在 controller 包一层
**何时重新评估**:如果需要 HTTP/2 server push、需要复用 `net/http` 生态中间件、或者 v2 长期不维护——届时考虑迁回标准库。
---
### D2. 数据库TimescaleDB on PG 16
**选了 TimescaleDB**(而不是纯 Postgres、InfluxDB、ClickHouse
**理由**
- 时序数据天然适合 hypertable5 张表全部按时间分片,查询近期数据走最新 chunk旧数据自动归档
- SQL 接口和普通 PG 完全兼容pgx 直连,无需新驱动
- 没有引入新的运维栈(开发机用 Docker 起 `timescale/timescaledb:latest-pg16` 即可)
- Chunk 间隔可按表调K 线 1 周、funding 30 天)
**代价**
- 必须跑 `SELECT create_hypertable(...)` 才能享受时序优化,新表容易忘
- 升级 PG 大版本需要看 Timescale 兼容矩阵
**何时重新评估**:如果数据量进入 TB 级、需要列存压缩或者 OLAP 复杂聚合——考虑 ClickHouse。
---
### D3. ArchitectureClean Architecture4 层 + ports.go 接口边界)
**4 层**`controller / usecase / repo / entity`
**接口边界**`internal/usecase/ports.go` 是唯一定义对外接口的地方。
**理由**
- 上游 Hermes 只通过 REST 调用本服务,但 Binance 这个数据源大概率会扩展到 CoinGlass / ETF / CME。把数据源抽象成 `MarketDataProvider` / `DerivativesProvider` 接口,新增数据源只需要新建 `internal/repo/webapi/<source>/`,不动业务编排。
- 单测可以 mock 接口,不需要起真 DB / 真 Binance。
- `internal/app/app.go` 是唯一的组合根DI 集中可见。
**强制约束**(见 `ai/risk-guardrails.md` G6
```
controller 不可直接 import binance/postgres
usecase 不可直接 import binance/postgres
```
**代价**
- 多一层 `ports.go`,每个新接口要写两次(接口 + 实现)
- 对小型项目可能略 overkill但本项目已经规划到 v3多数据源早做减少返工
**何时重新评估**:如果 v2 之后接口数量爆炸(> 30 个)→ 考虑按子域拆分 `ports.go` 为多个文件。
---
### D4. 传输层REST-onlyv1 不上 gRPC / 消息队列 / WebSocket
**选了 REST**(而不是 gRPC、NATS、WS 推送)。
**理由**
- Hermes 是同语言 Go 服务,但跨服务调用频率是分钟级(拿一次 contextREST + JSON 完全够
- gRPC 多一份 proto 维护负担,团队/工具收益不明显
- WebSocket 推送是独立工程量重连、消息丢失、订阅状态机v1 不进入
- Cron + REST 拉取模型对运维友好(任何 HTTP 监控就够)
**代价**
- 如果未来 Hermes 需要 sub-second 行情REST 拉模型撑不住
**何时重新评估**Hermes 接入实盘策略后,如果发现"分钟级"延迟成为瓶颈 → 写新 ADR 引入 WS。
---
### D5. 价格 / 成交量:全链路 `string`
**所有金额字段端到端用 `string`**Binance DTO 是 string、entity 是 string、JSON 响应是 string。落库时由 PG 转 `NUMERIC(36,18)`
**理由**
- Binance 原样返回字符串,避免 float64 转换丢精度
- `108000.12` 这种数 float64 表示就会丢尾数;累积统计后偏差更大
- 上游量化分析对价格精度敏感,宁可让 Hermes 自己决定怎么解析
**代价**
- 加减乘除需要 PG 端做或者引入 decimal 库
- JSON 响应里 price 是字符串,前端/客户端要适配
**强制约束**:见 `ai/risk-guardrails.md` G2。
---
### D6. 数据源边界:只用 Binance USDⓈ-M Futures 公共 API
**v1 不引入 CoinGlass、Glassnode、ETF Flow、CME、链上数据**
**理由**
- Binance 一家覆盖 80% 的需求K 线 / 衍生品 / 多空比)
- 引入新数据源等于引入新的鉴权、限流、错误模式、SLA——v1 优先把一条链路打通
- 路线图 v2 / v3 才扩展数据源README "路线图" 段)
**强制约束**
- 新增数据源前必须先写 `ai/specs/<source>.md`(见 AGENTS.md §10
- 不可使用 Binance 的私有签名接口(见 G1
---
### D7. 配置层cleanenvyaml + env override
**选了 cleanenv**(而不是 viper、koanf、env-only
**理由**
- 一份 yaml 默认值 + 环境变量覆盖,开发和部署都方便
- 比 viper 轻,没有多余抽象
- `env-default:` tag 让默认值跟字段定义放在一起,可读性好
**代价**:无明显缺点。如果后续需要热重载(不需要)才会考虑换。
---
### D8. 限流:`golang.org/x/time/rate` token bucket
挂在 `pkg/httpclient/client.go` 里,默认 RPS=20 / Burst=40从配置读。
**理由**
- 标准库附属,零外部依赖
- token bucket 适合突发场景
- Binance IP 限 2400 weight/min20 req/s × 60s = 1200 req/min留出一半余量给重试和 backfill
**强制约束**:所有外部 HTTP 调用走 `pkg/httpclient`,见 G5。
---
### D9. Schedulerrobfig/cron v3
**选了 robfig/cron v3**(而不是自己写 ticker、go-co-op/gocron
**理由**
- cron 表达式所有人都看得懂schedule 修改是配置而非代码
- 稳定老牌3.0 之后无破坏性变化
- 和 Fiber 在同一进程内运行graceful shutdown 容易做
**代价**
- 没有分布式锁——但本服务 v1 是单实例,不需要
---
## 不在本 ADR 范围
- **下单 / 账户 / 私钥**永久禁止G1。要做必须新仓库。
- **多交易所聚合**v3 才考虑,届时再写 ADR。
- **WS / 实时推送**:见 D4需要单独写 ADR。
- **观测性metrics / tracing**MVP 阶段只用 slog 结构化日志Prometheus / OTel 留待生产部署前评估。
---
## 后续 ADR 的触发条件(来自 AGENTS.md §10
- 换 HTTP 框架 → 新 ADR
- 引入消息队列 / WS → 新 ADR
- 跨服务通信改 gRPC → 新 ADR
- 数据库换型PG → ClickHouse→ 新 ADR
- 引入新数据源 → `ai/specs/<source>.md`(不一定要 ADR除非影响整体架构