Files
cryptoHermes/ai/project-map.md
dela fa769331c2 feat(market): Phase 1 扩展 — 更多 symbol + Bollinger/Vegas + 衍生品信号
- collector.symbols 与 supportedSymbols 加 SOL/BNB/DOGE,env-default 与 README 同步
- entity 追加 TechnicalStructure.Intervals(每周期 Bollinger + Vegas,omitempty 不破坏既有字段)与 DerivativesBundle.Signal
- 新增纯解析 usecase derivatives_signal.go:fundingBias 绝对阈值、oiSignal 用 P20 baseline + 价格方向(OI up + 价格 up/down → long/short_building,funding 不参与方向)、lsrRegime 绝对阈值;signal 数据不足走 warnings 进 DataQuality
- indicator.go 加 sma/stddev/ema/bollinger/vegas + computeIntervalTechnicals;IndicatorComputer 签名收 klines map
- harness 同步:G12 扩入 derivatives_signal.go(含 Makefile G12.5/6 + ADR-0002 适用范围 + project-map / harness-health 更新)
2026-05-24 23:19:57 +08:00

237 lines
11 KiB
Markdown
Raw 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.
# Project Map — cryptoHermes
代码 agent 工作的地形图。每个目录写明:**职责**、**可以依赖谁**、**不可以依赖谁**、**扩展点在哪**。
完整设计见 `docs/dev.md`
---
## 顶层布局
```
cryptoHermes/
├── cmd/ 二进制入口
├── config/ cleanenv 加载
├── internal/ 业务代码(不可被外部 import
├── migrations/ SQL含 hypertable
├── pkg/ 项目内可复用基础设施
├── docs/ 设计文档dev.md 是源头)
├── ai/ harness 工程文档(本目录)
├── docker-compose.yml Timescale + 服务
├── Dockerfile multi-stage golang:1.23-alpine → alpine:3.20
├── Makefile 所有验证命令
└── go.mod Go 1.23
```
---
## `cmd/` — 二进制入口
| 路径 | 职责 |
|---|---|
| `cmd/app/main.go` | 主服务。读 config → 调 `internal/app.Run(cfg)` |
| `cmd/backfill/main.go` | 历史 K 线回填 CLI。直接装配 binance client + kline repo不走 fiber |
**约束**`cmd/` 里只允许装配 + 调用,不允许写业务逻辑。
---
## `config/` — 配置
- `config.go`cleanenv 加载,`yaml + env` 双源。环境变量优先(见 `env:` tag
- `config.yml`:默认配置。**不要在这里放敏感信息**(没有敏感信息可放,因为本服务无私钥)。
**扩展点**:新增配置项 → `config.go` 加字段(同时加 `yaml:``env:` tag`config.yml` 加默认值 → 在 README "配置" 段补一行。
---
## `internal/` — 业务核心
Clean Architecture 四层。**依赖方向单向:`controller → usecase → entity ← repo`**。
```
┌──────────────┐
│ controller │ HTTP 层:参数校验、调 usecase、序列化
└──────┬───────┘
│ depends on
┌──────────────┐
│ usecase │ 业务编排。只依赖 ports.go 中的接口
└──────┬───────┘
│ depends on (interface only)
┌──────────────┐ ┌──────────────┐
│ entity │ ◄────── │ repo │ 外部依赖实现
└──────────────┘ └──────────────┘
(binance / postgres)
```
### `internal/entity/` — 纯业务实体
- `kline.go`, `ticker.go`, `funding.go`, `open_interest.go`, `long_short_ratio.go`, `taker_volume.go`, `market_context.go`
- **价格/成交量字段全部 `string`**,避免 float64 精度问题。落库时 PG 转 `NUMERIC(36,18)`
- `Kline``IsClosed bool` 字段——未收线 K 线 (`close_time > now()`) 由 mapper 自动判定。
- `LongShortRatio` 有常量 `RatioTypeGlobalAccount` / `RatioTypeTopTraderPosition` / `RatioTypeTopTraderAccount`
- `market_context.go` 还承载技术结构与衍生品信号的输出类型:`TechnicalStructure`(含 `Intervals map[string]IntervalTechnicals`,新增字段对消费方完全可选)、`Bollinger``Vegas``DerivativesSignal``fundingBias` / `oiSignal` / `lsrRegime`)。所有数值仍是 string。
**不依赖**fiber、pgx、binance、任何外部库。可以从这里 import 到任何其他层。
### `internal/usecase/` — 业务接口与编排
- `ports.go`**全部对外接口在这里定义**。这是 Clean Arch 的边界文件。
- `MarketDataProvider`K线、ticker24h
- `DerivativesProvider`funding/OI/多空比/taker volume 共 7 个方法)
- `KlineRepository` / `FundingRepository` / `OpenInterestRepository` / `LongShortRatioRepository` / `TakerVolumeRepository`
- `IndicatorComputer`pivot S/R + range + LSR 中位 + 每周期 Bollinger/Vegas
- `DerivativesSignalComputer`funding/OI/LSR → fundingBias/oiSignal/lsrRegime返回 warnings 由 caller 合并到 DataQuality
- `market_context.go`:聚合 `/v1/market/context`。errgroup 并发拉 snapshot/funding/OIDB K 线不足 200 根回源 Binance 补,异步写回。`supportedSymbols` 白名单当前为 BTC/ETH/SOL/BNB/DOGE USDT 五个。
- `market_query.go``/v1/market/derivatives` 后端。`GetDerivatives(symbol, period)` 并发拉 current funding/OI + 串行查 funding/OI/多空比历史,错误降级为 warnings 返回。
- `indicator.go``derivatives_signal.go`**纯解析 usecase**,零 repo 依赖。允许 transient `float64`G12 例外),输出转回 string 写入 entity。新增同形态文件时必须同步扩 Makefile G12.1 白名单与 G12.5/6 子规则,参考 `ai/adr/0002-indicator-numeric-boundary.md`
**约束**grep 可验证):
```bash
grep -r "repo/webapi/binance\|repo/persistent" internal/usecase # 必须无输出
```
usecase 不可直接 import 任何具体实现。新增业务流程 → 在 `ports.go` 加接口 → 在 usecase 编排 → 由 `internal/app/app.go` 注入实现。
### `internal/controller/` — HTTP 层
- `restapi/router.go` + `middleware.go`fiber app、recover、logger、request-id
- `restapi/v1/health_routes.go``/v1/health`
- `restapi/v1/market_routes.go``/v1/market/{context,klines,snapshot,derivatives}`
**约束**
```bash
grep -r "repo/webapi/binance\|repo/persistent" internal/controller # 必须无输出
grep -rn "FundingRepo\|OIRepo\|LSRepo\|TakerRepo" internal/controller # 必须无输出G11
```
controller 只能依赖 usecase 和 entity不能直接调 binance client 或 postgres repo。衍生品多源查询必须经 usecase详见 `ai/risk-guardrails.md` G11`KlineRepo` 暂时允许直查 `/klines`,因为它现在是 thin query。
**扩展点**:新增路由 → 加 handler → 通过 `MarketDeps` 注入依赖(不要直接 import repo 包)。
### `internal/repo/` — 外部依赖实现
| 子目录 | 实现哪些接口 |
|---|---|
| `webapi/binance/` | `MarketDataProvider``DerivativesProvider` |
| `persistent/postgres/` | 5 个 `*Repository` |
**Binance client**`webapi/binance/`
- `client.go`:包 `pkg/httpclient`,统一 base URL `https://fapi.binance.com`,错误用 `ExternalAPIError{Source, Path, StatusCode, Message}` 包装。
- `dto.go`:贴近 Binance 原始响应K 线是数组)。
- `mapper.go`DTO → entity。**K 线按下标解析**`row[0]=openTime ... row[10]=takerBuyQuoteVolume`),自动设置 `IsClosed = close_time < now()`
- `market.go``GetKlines` / `GetKlinesRange` / `GetTicker24h`
- `derivatives.go`funding × 2 + OI × 2 + 多空比 × 2 + taker volume
**Postgres repos**`persistent/postgres/`
- 5 个 repo每个有 `UpsertMany``ON CONFLICT DO UPDATE`)和 `FindRecent`(按时间倒序拉,返回前反转成正序)。
- `kline_repo.go``UpsertMany` 会过滤掉 `IsClosed=false` 的 K 线。
- 使用 pgxpool + transaction。
**扩展点**
- 新增数据源CoinGlass / ETF→ 新建 `webapi/coinglass/`,实现新的 Provider 接口(先在 `ports.go` 定义)。
- 新增表 → 新 migration + 新 repo + 在 `ports.go` 加新接口。
### `internal/worker/` — Collector
- `collector.go`:被 cron 调度的采集逻辑。每个 `Collect*` 方法遍历 `symbols × intervals/periods`,拉数据 → upsert。
- **不直接被 controller 调用**,只通过 `internal/app/scheduler.go` 触发。
### `internal/app/` — 装配与生命周期
- `app.go`DI 装配的唯一位置。
- 顺序pool → binanceClient → repos → contextUC → collector → scheduler → fiber app
- graceful shutdown监听 SIGINT/SIGTERM10s 超时,先停 cron、再停 fiber、最后关 pool。
- `scheduler.go`cron spec 在这里。
**这里是 Clean Arch 的"组合根"**——所有具体类型在这里被实例化并注入抽象接口。
---
## `pkg/` — 项目内可复用基础设施
| 包 | 职责 |
|---|---|
| `pkg/httpclient/` | 通用 HTTP client + 重试429/5xx 最多 2 次)+ `x/time/rate` 限流 |
| `pkg/logger/` | slog 包装(按 env 选 JSON / Text |
| `pkg/postgres/` | pgxpool 初始化 + Ping |
**约束**`pkg/` 不依赖 `internal/`,反向依赖。可以被外部项目 import虽然目前没有
---
## `migrations/` — SQL
10 个文件5 张表 × up/down
每个 `.up.sql` 末尾必须有:
```sql
SELECT create_hypertable('<table>', '<time_col>',
chunk_time_interval => <ms>,
if_not_exists => TRUE,
migrate_data => TRUE);
```
chunk 间隔:
- K 线 / OI / LS / taker → 1 周 = 604800000 ms
- funding → 30 天 = 2592000000 ms
**改 migration 前必读 `ai/risk-guardrails.md` 中"DB migration"段**
---
## 数据流(控制流)
### 写路径(采集)
```
cron tick
└→ internal/app/scheduler.go
└→ internal/worker/collector.go (Collect*)
├→ binance.GetXxx (HTTP → DTO → entity)
└→ repo.UpsertMany (entity → SQL upsert)
```
### 读路径API
```
HTTP request
└→ internal/controller/restapi/v1/market_routes.go
├→ /context → usecase.MarketContext.Build
│ ├→ marketData.GetTicker24h ┐
│ ├→ derivatives.GetCurrent… ├ errgroup 并发
│ ├→ derivatives.GetCurrent… ┘
│ ├→ klineRepo.FindRecent × 5 周期
│ │ └ DB 不足 → 回源 binance.GetKlines异步写回
│ └→ fundingRepo / oiRepo / lsRepo.FindRecent
├→ /derivatives → usecase.MarketQuery.GetDerivatives
│ ├→ derivatives.GetCurrentFunding ┐ errgroup
│ ├→ derivatives.GetCurrentOI ┘
│ └→ fundingRepo / oiRepo / lsRepo.FindRecent
├→ /klines → klineRepo.FindRecentthin query允许直查
└→ /snapshot → marketData.GetTicker24h
```
---
## 不可逾越的边界(自动验证见 AGENTS.md §6
1. **controller ↛ binance/postgres**:必须经 usecase。
2. **usecase ↛ binance/postgres 包**:只依赖 `ports.go` 接口。
3. **entity ↛ 任何外部库**:可被所有层 import。
4. **pkg ↛ internal**:基础设施不知道业务。
5. **任何代码 ↛ 私钥/签名**grep `apikey|hmac|x-mbx-apikey|secret_key|api_secret` 必须无 Go 代码命中。
---
## 关键扩展点速查
| 场景 | 改哪 |
|---|---|
| 新增 REST 路由 | `internal/controller/restapi/v1/`,依赖通过 `MarketDeps` 注入 |
| 新增业务编排 | `internal/usecase/ports.go` 加接口 → 新 usecase 文件 → `internal/app/app.go` 装配 |
| 新增数据表 | 新 migration → 新 entity可选→ 新 repo → `ports.go` 接口 → 装配 |
| 新增数据源 | `ai/specs/<source>.md` → 新 `internal/repo/webapi/<source>/` → 新 Provider 接口 |
| 新增定时任务 | `internal/worker/collector.go` 加方法 → `internal/app/scheduler.go` 注册 cron |
| 改配置项 | `config/config.go` 加字段 → `config/config.yml` 加默认 → README 记录 |