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

11 KiB
Raw Blame History

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.gocleanenv 加载,yaml + env 双源。环境变量优先(见 env: tag
  • config.yml:默认配置。不要在这里放敏感信息(没有敏感信息可放,因为本服务无私钥)。

扩展点:新增配置项 → config.go 加字段(同时加 yaml:env: tagconfig.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)
  • KlineIsClosed bool 字段——未收线 K 线 (close_time > now()) 由 mapper 自动判定。
  • LongShortRatio 有常量 RatioTypeGlobalAccount / RatioTypeTopTraderPosition / RatioTypeTopTraderAccount
  • market_context.go 还承载技术结构与衍生品信号的输出类型:TechnicalStructure(含 Intervals map[string]IntervalTechnicals,新增字段对消费方完全可选)、BollingerVegasDerivativesSignalfundingBias / oiSignal / lsrRegime)。所有数值仍是 string。

不依赖fiber、pgx、binance、任何外部库。可以从这里 import 到任何其他层。

internal/usecase/ — 业务接口与编排

  • ports.go全部对外接口在这里定义。这是 Clean Arch 的边界文件。
    • MarketDataProviderK线、ticker24h
    • DerivativesProviderfunding/OI/多空比/taker volume 共 7 个方法)
    • KlineRepository / FundingRepository / OpenInterestRepository / LongShortRatioRepository / TakerVolumeRepository
    • IndicatorComputerpivot S/R + range + LSR 中位 + 每周期 Bollinger/Vegas
    • DerivativesSignalComputerfunding/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.goderivatives_signal.go纯解析 usecase,零 repo 依赖。允许 transient float64G12 例外),输出转回 string 写入 entity。新增同形态文件时必须同步扩 Makefile G12.1 白名单与 G12.5/6 子规则,参考 ai/adr/0002-indicator-numeric-boundary.md

约束grep 可验证):

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.gofiber app、recover、logger、request-id
  • restapi/v1/health_routes.go/v1/health
  • restapi/v1/market_routes.go/v1/market/{context,klines,snapshot,derivatives}

约束

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 G11KlineRepo 暂时允许直查 /klines,因为它现在是 thin query。

扩展点:新增路由 → 加 handler → 通过 MarketDeps 注入依赖(不要直接 import repo 包)。

internal/repo/ — 外部依赖实现

子目录 实现哪些接口
webapi/binance/ MarketDataProviderDerivativesProvider
persistent/postgres/ 5 个 *Repository

Binance clientwebapi/binance/

  • client.go:包 pkg/httpclient,统一 base URL https://fapi.binance.com,错误用 ExternalAPIError{Source, Path, StatusCode, Message} 包装。
  • dto.go:贴近 Binance 原始响应K 线是数组)。
  • mapper.goDTO → entity。K 线按下标解析row[0]=openTime ... row[10]=takerBuyQuoteVolume),自动设置 IsClosed = close_time < now()
  • market.goGetKlines / GetKlinesRange / GetTicker24h
  • derivatives.gofunding × 2 + OI × 2 + 多空比 × 2 + taker volume

Postgres repospersistent/postgres/

  • 5 个 repo每个有 UpsertManyON CONFLICT DO UPDATE)和 FindRecent(按时间倒序拉,返回前反转成正序)。
  • kline_repo.goUpsertMany 会过滤掉 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.goDI 装配的唯一位置。
    • 顺序pool → binanceClient → repos → contextUC → collector → scheduler → fiber app
    • graceful shutdown监听 SIGINT/SIGTERM10s 超时,先停 cron、再停 fiber、最后关 pool。
  • scheduler.gocron 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 末尾必须有:

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 记录