Files
cryptoHermes/internal/repo/webapi/coinglass/mapper.go
dela 1b61541ff5
Some checks failed
ci / build + vet + guard + race (push) Has been cancelled
feat: 接入 CoinGlass 清算热力图隔离链路
2026-05-25 16:57:22 +08:00

82 lines
2.6 KiB
Go
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.
// Package coinglass — CoinGlass V2 私有 API 客户端实现。
// specai/specs/coinglass.md。
package coinglass
import (
"encoding/json"
"fmt"
"math"
"strconv"
"cryptoHermes/internal/entity"
)
// CGEnvelope 是所有 CoinGlass V2 endpoint 的统一外壳。
// 解密后的 plaintext JSON 形如:{"success":true,"code":"0","msg":"","data":{...}}
type CGEnvelope struct {
Success bool `json:"success"`
Code json.Number `json:"code"`
Msg string `json:"msg"`
Data json.RawMessage `json:"data"`
}
// MapLiqHeatMap 把解密后的 plaintext envelope 映射成 entity.CGLiqHeatMap。
//
// PR-1 阶段未拿到真实 schema dump先做最薄映射data 整体进 RawGrid
// 若顶层有 minPrice/maxPrice/priceMin/priceMax 字段则抽出(容忍命名漂移)。
// 真实 schema 经 spike dump 后回填到 spec §5mapper 同步加显式字段)。
//
// 数值边界ADR-0004 D3解 JSON number 默认 float64 是 transient
// 通过 formatFloat 转 string 进 entityentity 字段全 stringG12.4 兜底)。
func MapLiqHeatMap(symbol string, interval string, ts int64, plaintext []byte) (*entity.CGLiqHeatMap, error) {
var env CGEnvelope
if err := json.Unmarshal(plaintext, &env); err != nil {
return nil, fmt.Errorf("liq_heatmap envelope: %w", err)
}
if !env.Success {
return nil, fmt.Errorf("liq_heatmap business error code=%s msg=%s", env.Code, env.Msg)
}
out := &entity.CGLiqHeatMap{
Symbol: symbol,
Interval: interval,
Timestamp: ts,
RawGrid: append(json.RawMessage(nil), env.Data...),
}
var probe map[string]json.RawMessage
if err := json.Unmarshal(env.Data, &probe); err == nil {
out.PriceMin = pickFloatField(probe, "priceMin", "minPrice", "min")
out.PriceMax = pickFloatField(probe, "priceMax", "maxPrice", "max")
}
return out, nil
}
// pickFloatField 在 probe map 里按候选 key 顺序找第一个能解成 float64 的字段,
// 用 formatFloat 转回 string。找不到返回 ""。
func pickFloatField(probe map[string]json.RawMessage, keys ...string) string {
for _, k := range keys {
raw, ok := probe[k]
if !ok {
continue
}
var f float64
if err := json.Unmarshal(raw, &f); err == nil {
return formatFloat(f)
}
var s string
if err := json.Unmarshal(raw, &s); err == nil {
return s
}
}
return ""
}
// formatFloat 是 mapper 出口的唯一数值格式化点ADR-0002 / ADR-0004 D3
// NaN / Inf 统一映射成 "",下游消费方自行判空,避免 entity 出现非法字面量。
func formatFloat(f float64) string {
if math.IsNaN(f) || math.IsInf(f, 0) {
return ""
}
return strconv.FormatFloat(f, 'f', -1, 64)
}