refactor: 把 /derivatives 的多源编排从 controller 搬进 usecase
为什么:原 controller handler 在 HTTP 层同时承担了 4 项 usecase 职责 (多源拼装、错误降级策略、limit 硬编码、响应结构组装),违反了 "controller 只做参数解析 + 调用 + 序列化" 的边界。等后续给衍生品加 缓存 / taker volume / 数据质量字段时,HTTP 层会持续变厚。 改动: - 新增 internal/usecase/market_query.go: MarketQueryUsecase.GetDerivatives() 并发拉 current funding/OI + 串行查历史 + 错误聚合为 warnings 返回 - /derivatives handler 退化到 4 行;MarketDeps / restapi.Deps 同步收窄 - /klines 保持直查 KlineRepo(thin query,G11 例外) - 新增 G11 守卫:grep "FundingRepo|OIRepo|LSRepo|TakerRepo" internal/controller 破坏性 API 变更(/derivatives 响应): - 删除 funding.error / openInterest.error - 新增顶层 warnings: []string 顶层 symbol / funding / openInterest / longShortRatio / takerBuySellVolume 保持。 harness 同步: - AGENTS.md §6 加 G11 grep - ai/project-map.md 加 market_query.go + /derivatives 数据流分支 - ai/task-templates.md T6 加"破坏性变体"分支(本次重构暴露了原假设过严) - ai/harness-health.md W1 记一次轻量验证 + 守卫数 10→11 验收: go build / go vet / G6 grep / G11 grep 全绿。
This commit is contained in:
@@ -103,11 +103,14 @@ grep -r "repo/webapi/binance\|repo/persistent" internal/controller # 必须无
|
|||||||
# usecase 不可直接 import binance/postgres
|
# usecase 不可直接 import binance/postgres
|
||||||
grep -r "repo/webapi/binance\|repo/persistent" internal/usecase # 必须无输出
|
grep -r "repo/webapi/binance\|repo/persistent" internal/usecase # 必须无输出
|
||||||
|
|
||||||
|
# controller 不可直接编排 derivatives 多源查询(G11)
|
||||||
|
grep -rn "FundingRepo\|OIRepo\|LSRepo\|TakerRepo" internal/controller # 必须无输出
|
||||||
|
|
||||||
# 全项目不可出现签名 / 私钥相关字段
|
# 全项目不可出现签名 / 私钥相关字段
|
||||||
grep -ri "apikey\|x-mbx-apikey\|hmac\|secret_key\|api_secret" --include="*.go" . # 必须无输出(不算注释/文档里的"不接入"说明)
|
grep -ri "apikey\|x-mbx-apikey\|hmac\|secret_key\|api_secret" --include="*.go" . # 必须无输出(不算注释/文档里的"不接入"说明)
|
||||||
```
|
```
|
||||||
|
|
||||||
任何 PR 都应该满足以上三条。
|
任何 PR 都应该满足以上四条。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
| 验证命令可跑 | strong | Makefile 全部命令在 README + AGENTS.md 双重列出 |
|
| 验证命令可跑 | strong | Makefile 全部命令在 README + AGENTS.md 双重列出 |
|
||||||
| 快速反馈环路 | strong | `go build ./...` < 2s,`go vet ./...` < 1s,单包测试支持 |
|
| 快速反馈环路 | strong | `go build ./...` < 2s,`go vet ./...` < 1s,单包测试支持 |
|
||||||
| 任务契约质量 | partial | 模板已写(`ai/task-templates.md`),但还没有真实任务用过 |
|
| 任务契约质量 | partial | 模板已写(`ai/task-templates.md`),但还没有真实任务用过 |
|
||||||
| 守卫规则清晰度 | strong | 10 条 G1-G10,每条都有可机械验证命令 |
|
| 守卫规则清晰度 | strong | 11 条 G1-G11,每条都有可机械验证命令 |
|
||||||
| 架构决策耐久度 | strong | ADR 0001 记录 9 条核心决策;其他 ADR 等触发 |
|
| 架构决策耐久度 | strong | ADR 0001 记录 9 条核心决策;其他 ADR 等触发 |
|
||||||
| Spec / test-plan | partial | 还没有 specs/,因为 v1 没有需要 spec 的任务;v2 新数据源时必填 |
|
| Spec / test-plan | partial | 还没有 specs/,因为 v1 没有需要 spec 的任务;v2 新数据源时必填 |
|
||||||
| 失败反馈环路 | partial | AGENTS.md §10 写了升级时机,但还没有 `ai/risk-guardrails.md` 改动史可参考 |
|
| 失败反馈环路 | partial | AGENTS.md §10 写了升级时机,但还没有 `ai/risk-guardrails.md` 改动史可参考 |
|
||||||
@@ -44,6 +44,7 @@
|
|||||||
**现状**:模板已写完,但没有 PR 用过这些契约。
|
**现状**:模板已写完,但没有 PR 用过这些契约。
|
||||||
**影响**:模板可能太严格或太松。
|
**影响**:模板可能太严格或太松。
|
||||||
**纠正时机**:完成第一个非平凡 PR(比如 Milestone 6 的技术指标)后回看,调整模板。
|
**纠正时机**:完成第一个非平凡 PR(比如 Milestone 6 的技术指标)后回看,调整模板。
|
||||||
|
**2026-05-24 更新**:`/derivatives` controller→usecase 重构(抽 `MarketQueryUsecase`、新增 G11)算一次轻量验证。发现 T6 "API 响应字节级一致" 假设过严——抽离 usecase 时合理地把 sub-object `error` 字段升级成顶层 `warnings` 数组,已在 T6 加"破坏性变体"分支。Milestone 6 真正落地时再做一次完整复评。
|
||||||
|
|
||||||
### W2. 还没有 work-status.md
|
### W2. 还没有 work-status.md
|
||||||
**现状**:目前是单 agent / 单会话工作,不需要 work-status 协调。
|
**现状**:目前是单 agent / 单会话工作,不需要 work-status 协调。
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ Clean Architecture 四层。**依赖方向单向:`controller → usecase → e
|
|||||||
- `DerivativesProvider`(funding/OI/多空比/taker volume 共 7 个方法)
|
- `DerivativesProvider`(funding/OI/多空比/taker volume 共 7 个方法)
|
||||||
- `KlineRepository` / `FundingRepository` / `OpenInterestRepository` / `LongShortRatioRepository` / `TakerVolumeRepository`
|
- `KlineRepository` / `FundingRepository` / `OpenInterestRepository` / `LongShortRatioRepository` / `TakerVolumeRepository`
|
||||||
- `market_context.go`:聚合 `/v1/market/context`。errgroup 并发拉 snapshot/funding/OI,DB K 线不足 200 根回源 Binance 补,异步写回。
|
- `market_context.go`:聚合 `/v1/market/context`。errgroup 并发拉 snapshot/funding/OI,DB K 线不足 200 根回源 Binance 补,异步写回。
|
||||||
|
- `market_query.go`:`/v1/market/derivatives` 后端。`GetDerivatives(symbol, period)` 并发拉 current funding/OI + 串行查 funding/OI/多空比历史,错误降级为 warnings 返回。
|
||||||
|
|
||||||
**约束**(grep 可验证):
|
**约束**(grep 可验证):
|
||||||
```bash
|
```bash
|
||||||
@@ -98,8 +99,9 @@ usecase 不可直接 import 任何具体实现。新增业务流程 → 在 `por
|
|||||||
**约束**:
|
**约束**:
|
||||||
```bash
|
```bash
|
||||||
grep -r "repo/webapi/binance\|repo/persistent" internal/controller # 必须无输出
|
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。
|
controller 只能依赖 usecase 和 entity,不能直接调 binance client 或 postgres repo。衍生品多源查询必须经 usecase(详见 `ai/risk-guardrails.md` G11)。`KlineRepo` 暂时允许直查 `/klines`,因为它现在是 thin query。
|
||||||
|
|
||||||
**扩展点**:新增路由 → 加 handler → 通过 `MarketDeps` 注入依赖(不要直接 import repo 包)。
|
**扩展点**:新增路由 → 加 handler → 通过 `MarketDeps` 注入依赖(不要直接 import repo 包)。
|
||||||
|
|
||||||
@@ -191,13 +193,19 @@ cron tick
|
|||||||
```
|
```
|
||||||
HTTP request
|
HTTP request
|
||||||
└→ internal/controller/restapi/v1/market_routes.go
|
└→ internal/controller/restapi/v1/market_routes.go
|
||||||
└→ usecase.MarketContext.Build
|
├→ /context → usecase.MarketContext.Build
|
||||||
├→ marketData.GetTicker24h ┐
|
│ ├→ marketData.GetTicker24h ┐
|
||||||
├→ derivatives.GetCurrent… ├ errgroup 并发
|
│ ├→ derivatives.GetCurrent… ├ errgroup 并发
|
||||||
├→ derivatives.GetCurrent… ┘
|
│ ├→ derivatives.GetCurrent… ┘
|
||||||
├→ klineRepo.FindRecent × 5 周期
|
│ ├→ klineRepo.FindRecent × 5 周期
|
||||||
│ └ DB 不足 → 回源 binance.GetKlines(异步写回)
|
│ │ └ DB 不足 → 回源 binance.GetKlines(异步写回)
|
||||||
└→ fundingRepo / oiRepo / lsRepo.FindRecent
|
│ └→ fundingRepo / oiRepo / lsRepo.FindRecent
|
||||||
|
├→ /derivatives → usecase.MarketQuery.GetDerivatives
|
||||||
|
│ ├→ derivatives.GetCurrentFunding ┐ errgroup
|
||||||
|
│ ├→ derivatives.GetCurrentOI ┘
|
||||||
|
│ └→ fundingRepo / oiRepo / lsRepo.FindRecent
|
||||||
|
├→ /klines → klineRepo.FindRecent(thin query,允许直查)
|
||||||
|
└→ /snapshot → marketData.GetTicker24h
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -177,6 +177,22 @@ grep -rn --include="*.go" "websocket\|fstream.binance" .
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## G11. Controller 不编排 derivatives 多源查询
|
||||||
|
|
||||||
|
**规则**:`internal/controller/**` 不得直接持有或调用 `FundingRepository` / `OpenInterestRepository` / `LongShortRatioRepository` / `TakerVolumeRepository`。这类衍生品历史数据的"查哪些表 + 多源拼装 + 错误降级 → warnings"必须在 `internal/usecase/` 完成,controller 只做参数解析、调用 usecase、返回 JSON。
|
||||||
|
|
||||||
|
**为什么**:曾经 `/derivatives` handler 一次性编排了 6 处查询、4 个静默吞错的 `_`、硬编码的 limit 和响应结构——HTTP 层在替业务层做决定。要给衍生品加 taker volume、缓存、降级策略、数据质量 warnings 时,应该只动 usecase,不该让 HTTP handler 跟着变厚。
|
||||||
|
|
||||||
|
**例外**:`KlineRepository` 暂时允许 controller 直查,因为 `/klines` 现在就是 thin query。一旦它要加缓存 / live fallback / interval 聚合,就同样要搬进 usecase。
|
||||||
|
|
||||||
|
**怎么验证**:
|
||||||
|
```bash
|
||||||
|
grep -rn "FundingRepo\|OIRepo\|LSRepo\|TakerRepo" internal/controller
|
||||||
|
# 期望:无输出
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 升级守护规则的时机
|
## 升级守护规则的时机
|
||||||
|
|
||||||
同一类错误第二次出现 → 写一条新规则进来。修改本文件 = 改动了项目契约,需要在 PR 描述里说明原因并 @ 维护者。
|
同一类错误第二次出现 → 写一条新规则进来。修改本文件 = 改动了项目契约,需要在 PR 描述里说明原因并 @ 维护者。
|
||||||
|
|||||||
@@ -159,14 +159,18 @@ acceptance:
|
|||||||
objective: <消除哪个边界违反 / 抽取哪段重复>
|
objective: <消除哪个边界违反 / 抽取哪段重复>
|
||||||
scope: <文件列表>
|
scope: <文件列表>
|
||||||
out-of-scope:
|
out-of-scope:
|
||||||
- 不改行为(API 响应字节级一致 / DB schema 不变)
|
- 行为变化(默认:API 响应字节级一致 / DB schema 不变)
|
||||||
constraints: G6
|
- 例外:如果重构本身是为了把不该在 controller 的"错误降级 / 响应组装"搬进 usecase,
|
||||||
|
可以一并修响应契约(如 sub-object 的 error 字段聚合为顶层 warnings)。
|
||||||
|
必须在 acceptance 显式标 "破坏性",并在 PR 描述列出旧 → 新字段映射。
|
||||||
|
constraints: G6 + G11(如果动 controller)
|
||||||
validation:
|
validation:
|
||||||
- go build ./... && go vet ./...
|
- go build ./... && go vet ./...
|
||||||
- 全部 grep 边界检查(AGENTS.md §6)
|
- 全部 grep 边界检查(AGENTS.md §6)
|
||||||
- make test
|
- make test
|
||||||
acceptance:
|
acceptance:
|
||||||
- diff 中不含行为变化(只是搬代码 / 重命名 / 抽接口)
|
- 默认:diff 中不含行为变化(只是搬代码 / 重命名 / 抽接口)
|
||||||
|
- 破坏性变体:列出响应字段变化,确认上游(Hermes)消费方已知或不受影响
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -58,6 +58,13 @@ func Run(cfg *config.Config, log *slog.Logger) error {
|
|||||||
log,
|
log,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
queryUC := usecase.NewMarketQueryUsecase(
|
||||||
|
binanceClient,
|
||||||
|
fundingRepo,
|
||||||
|
oiRepo,
|
||||||
|
lsRepo,
|
||||||
|
)
|
||||||
|
|
||||||
collector := worker.NewCollector(worker.Deps{
|
collector := worker.NewCollector(worker.Deps{
|
||||||
MarketData: binanceClient,
|
MarketData: binanceClient,
|
||||||
Derivatives: binanceClient,
|
Derivatives: binanceClient,
|
||||||
@@ -90,12 +97,9 @@ func Run(cfg *config.Config, log *slog.Logger) error {
|
|||||||
restapi.Register(fiberApp, restapi.Deps{
|
restapi.Register(fiberApp, restapi.Deps{
|
||||||
Logger: log,
|
Logger: log,
|
||||||
MarketContext: contextUC,
|
MarketContext: contextUC,
|
||||||
|
MarketQuery: queryUC,
|
||||||
MarketData: binanceClient,
|
MarketData: binanceClient,
|
||||||
Derivatives: binanceClient,
|
|
||||||
KlineRepo: klineRepo,
|
KlineRepo: klineRepo,
|
||||||
FundingRepo: fundingRepo,
|
|
||||||
OIRepo: oiRepo,
|
|
||||||
LSRepo: lsRepo,
|
|
||||||
})
|
})
|
||||||
|
|
||||||
listenErr := make(chan error, 1)
|
listenErr := make(chan error, 1)
|
||||||
|
|||||||
@@ -11,14 +11,11 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Deps struct {
|
type Deps struct {
|
||||||
Logger *slog.Logger
|
Logger *slog.Logger
|
||||||
MarketContext *usecase.MarketContextUsecase
|
MarketContext *usecase.MarketContextUsecase
|
||||||
MarketData usecase.MarketDataProvider
|
MarketQuery *usecase.MarketQueryUsecase
|
||||||
Derivatives usecase.DerivativesProvider
|
MarketData usecase.MarketDataProvider
|
||||||
KlineRepo usecase.KlineRepository
|
KlineRepo usecase.KlineRepository
|
||||||
FundingRepo usecase.FundingRepository
|
|
||||||
OIRepo usecase.OpenInterestRepository
|
|
||||||
LSRepo usecase.LongShortRatioRepository
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Register(app *fiber.App, deps Deps) {
|
func Register(app *fiber.App, deps Deps) {
|
||||||
@@ -29,11 +26,8 @@ func Register(app *fiber.App, deps Deps) {
|
|||||||
v1.RegisterHealth(api)
|
v1.RegisterHealth(api)
|
||||||
v1.RegisterMarket(api, v1.MarketDeps{
|
v1.RegisterMarket(api, v1.MarketDeps{
|
||||||
MarketContext: deps.MarketContext,
|
MarketContext: deps.MarketContext,
|
||||||
|
MarketQuery: deps.MarketQuery,
|
||||||
MarketData: deps.MarketData,
|
MarketData: deps.MarketData,
|
||||||
Derivatives: deps.Derivatives,
|
|
||||||
KlineRepo: deps.KlineRepo,
|
KlineRepo: deps.KlineRepo,
|
||||||
FundingRepo: deps.FundingRepo,
|
|
||||||
OIRepo: deps.OIRepo,
|
|
||||||
LSRepo: deps.LSRepo,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,18 +6,14 @@ import (
|
|||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
|
|
||||||
"cryptoHermes/internal/entity"
|
|
||||||
"cryptoHermes/internal/usecase"
|
"cryptoHermes/internal/usecase"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MarketDeps struct {
|
type MarketDeps struct {
|
||||||
MarketContext *usecase.MarketContextUsecase
|
MarketContext *usecase.MarketContextUsecase
|
||||||
|
MarketQuery *usecase.MarketQueryUsecase
|
||||||
MarketData usecase.MarketDataProvider
|
MarketData usecase.MarketDataProvider
|
||||||
Derivatives usecase.DerivativesProvider
|
|
||||||
KlineRepo usecase.KlineRepository
|
KlineRepo usecase.KlineRepository
|
||||||
FundingRepo usecase.FundingRepository
|
|
||||||
OIRepo usecase.OpenInterestRepository
|
|
||||||
LSRepo usecase.LongShortRatioRepository
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var allowedIntervals = map[string]bool{
|
var allowedIntervals = map[string]bool{
|
||||||
@@ -80,39 +76,18 @@ func RegisterMarket(r fiber.Router, d MarketDeps) {
|
|||||||
return fiber.NewError(fiber.StatusBadRequest, "symbol is required")
|
return fiber.NewError(fiber.StatusBadRequest, "symbol is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
fundCur, ferr := d.Derivatives.GetCurrentFunding(c.UserContext(), symbol)
|
bundle, warnings, err := d.MarketQuery.GetDerivatives(c.UserContext(), symbol, period)
|
||||||
oiCur, oerr := d.Derivatives.GetCurrentOpenInterest(c.UserContext(), symbol)
|
if err != nil {
|
||||||
|
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||||
fundHist, _ := d.FundingRepo.FindRecent(c.UserContext(), symbol, 100)
|
|
||||||
oiHist, _ := d.OIRepo.FindRecent(c.UserContext(), symbol, period, 200)
|
|
||||||
globalLS, _ := d.LSRepo.FindRecent(c.UserContext(), symbol, period, entity.RatioTypeGlobalAccount, 200)
|
|
||||||
topLS, _ := d.LSRepo.FindRecent(c.UserContext(), symbol, period, entity.RatioTypeTopTraderPosition, 200)
|
|
||||||
|
|
||||||
resp := fiber.Map{
|
|
||||||
"symbol": symbol,
|
|
||||||
"funding": fiber.Map{
|
|
||||||
"current": fundCur,
|
|
||||||
"history": fundHist,
|
|
||||||
"error": errString(ferr),
|
|
||||||
},
|
|
||||||
"openInterest": fiber.Map{
|
|
||||||
"current": oiCur,
|
|
||||||
"history": oiHist,
|
|
||||||
"error": errString(oerr),
|
|
||||||
},
|
|
||||||
"longShortRatio": fiber.Map{
|
|
||||||
"global": globalLS,
|
|
||||||
"topTraderPosition": topLS,
|
|
||||||
},
|
|
||||||
"takerBuySellVolume": []any{},
|
|
||||||
}
|
}
|
||||||
return c.JSON(resp)
|
|
||||||
|
return c.JSON(fiber.Map{
|
||||||
|
"symbol": symbol,
|
||||||
|
"funding": bundle.Funding,
|
||||||
|
"openInterest": bundle.OpenInterest,
|
||||||
|
"longShortRatio": bundle.LongShortRatio,
|
||||||
|
"takerBuySellVolume": bundle.TakerBuySellVolume,
|
||||||
|
"warnings": warnings,
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func errString(e error) string {
|
|
||||||
if e == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return e.Error()
|
|
||||||
}
|
|
||||||
|
|||||||
113
internal/usecase/market_query.go
Normal file
113
internal/usecase/market_query.go
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
package usecase
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"golang.org/x/sync/errgroup"
|
||||||
|
|
||||||
|
"cryptoHermes/internal/entity"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
derivativesFundingHistoryLen = 100
|
||||||
|
derivativesOIHistoryLen = 200
|
||||||
|
derivativesLongShortLen = 200
|
||||||
|
)
|
||||||
|
|
||||||
|
type MarketQueryUsecase struct {
|
||||||
|
derivatives DerivativesProvider
|
||||||
|
fundingRepo FundingRepository
|
||||||
|
oiRepo OpenInterestRepository
|
||||||
|
lsRepo LongShortRatioRepository
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMarketQueryUsecase(
|
||||||
|
derivatives DerivativesProvider,
|
||||||
|
fundingRepo FundingRepository,
|
||||||
|
oiRepo OpenInterestRepository,
|
||||||
|
lsRepo LongShortRatioRepository,
|
||||||
|
) *MarketQueryUsecase {
|
||||||
|
return &MarketQueryUsecase{
|
||||||
|
derivatives: derivatives,
|
||||||
|
fundingRepo: fundingRepo,
|
||||||
|
oiRepo: oiRepo,
|
||||||
|
lsRepo: lsRepo,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *MarketQueryUsecase) GetDerivatives(ctx context.Context, symbol, period string) (*entity.DerivativesBundle, []string, error) {
|
||||||
|
var (
|
||||||
|
currentFund *entity.FundingRate
|
||||||
|
currentOI *entity.OpenInterest
|
||||||
|
warnMu sync.Mutex
|
||||||
|
warnings []string
|
||||||
|
)
|
||||||
|
addWarn := func(w string) {
|
||||||
|
warnMu.Lock()
|
||||||
|
warnings = append(warnings, w)
|
||||||
|
warnMu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
g, gctx := errgroup.WithContext(ctx)
|
||||||
|
g.Go(func() error {
|
||||||
|
f, err := u.derivatives.GetCurrentFunding(gctx, symbol)
|
||||||
|
if err != nil {
|
||||||
|
addWarn("current funding fetch failed: " + err.Error())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
currentFund = f
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
g.Go(func() error {
|
||||||
|
oi, err := u.derivatives.GetCurrentOpenInterest(gctx, symbol)
|
||||||
|
if err != nil {
|
||||||
|
addWarn("current OI fetch failed: " + err.Error())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
currentOI = oi
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
_ = g.Wait()
|
||||||
|
|
||||||
|
fundingHist, err := u.fundingRepo.FindRecent(ctx, symbol, derivativesFundingHistoryLen)
|
||||||
|
if err != nil {
|
||||||
|
addWarn("funding history query failed: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
oiHist, err := u.oiRepo.FindRecent(ctx, symbol, period, derivativesOIHistoryLen)
|
||||||
|
if err != nil {
|
||||||
|
addWarn("OI history query failed: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
globalLS, err := u.lsRepo.FindRecent(ctx, symbol, period, entity.RatioTypeGlobalAccount, derivativesLongShortLen)
|
||||||
|
if err != nil {
|
||||||
|
addWarn("global long/short query failed: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
topLS, err := u.lsRepo.FindRecent(ctx, symbol, period, entity.RatioTypeTopTraderPosition, derivativesLongShortLen)
|
||||||
|
if err != nil {
|
||||||
|
addWarn("top trader position long/short query failed: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
bundle := &entity.DerivativesBundle{
|
||||||
|
Funding: entity.FundingBundle{
|
||||||
|
Current: currentFund,
|
||||||
|
History: fundingHist,
|
||||||
|
},
|
||||||
|
OpenInterest: entity.OpenInterestBundle{
|
||||||
|
Current: currentOI,
|
||||||
|
History: oiHist,
|
||||||
|
},
|
||||||
|
LongShortRatio: entity.LongShortBundle{
|
||||||
|
Global: globalLS,
|
||||||
|
TopTraderPosition: topLS,
|
||||||
|
},
|
||||||
|
TakerBuySellVolume: []entity.TakerBuySellVolume{},
|
||||||
|
}
|
||||||
|
|
||||||
|
if warnings == nil {
|
||||||
|
warnings = []string{}
|
||||||
|
}
|
||||||
|
return bundle, warnings, nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user