HL 分析指标方法论
本文档详细描述 /hl/* 下每一个量化指标的计算方式、所依赖的链上原语,以及各自的边界与局限。伪代码与线上服务端行为逐行对齐,不含任何尚未落地的设计。
版本:2026-04-21
引言
所有 HL 分析类接口都衍生自我们从 Hyperliquid 摄入的四条链上数据流:
- 账户权益快照(Account Value Snapshots,
snapshots_perp) —— 每个地址永续账户的按市值计价(mark-to-market)权益,由 Hyperliquid 节点每 5–10 分钟采样一次。 - 累计盈亏快照(Accumulated PnL Snapshots,
accum_pnls) —— 以地址和时间为键的已实现 + 未实现盈亏(realized + unrealized PnL)时间序列。 - 成交与已成交订单(
fills,filled_orders) —— 逐笔成交执行记录,每笔成交一行。 - 账本更新(
user_ledger_updates) —— 账户层级的所有余额变动事件:充值、提现、内部转账、金库(vault)资金流动。
本文档所述的每一个指标,都是以上四张表的确定性函数。我们不会注入任何私有的平滑处理、评分或基准叠加。如果你需要语义不同的指标(例如夏普比率(Sharpe)、索提诺比率(Sortino)、相对基准收益等),请参阅 自定义指标计算 一节,了解如何基于我们的原语自行推导。
约定
| 约定项 | 取值 |
|---|---|
| 时间 | 所有时间戳均以 Unix 毫秒(UTC)返回。在文档明确支持的位置,入参可使用 Unix 毫秒或 RFC 3339 两种格式。 |
| 计价货币 | 所有金额均为 USD 等值,按快照时刻 Hyperliquid 内部 mark price 换算。不做汇率换算。 |
| 地址格式 | 全小写、带 0x 前缀的 20 字节十六进制。服务端会统一归一化。 |
| 小数精度 | 计算采用任意精度 decimal(shopspring/decimal)。响应序列化时保留完整精度,客户端不应假设固定小数位数。 |
| 作用域 | scope=perp 为默认值,也是目前回撤与行为类指标唯一支持的作用域。现货余额不计入。 |
| 时间窗口语义 | days=N 表示 [now − N·24h, now]。窗口在请求到达时由服务端求值。 |
指标方法论
最大回撤(Max Drawdown) —— /hl/max-drawdown, /hl/batch-max-drawdown
用途。 在请求窗口内,对地址永续账户权益计算最大的峰值-谷值(peak-to-trough)跌幅,并对净资金流(net capital flows)做去污(decontamination)修正,使得提现不会被记为亏损,充值也不会把峰值抬升重置。
输入数据。
snapshots_perp.account_value—— 该地址在每个节点快照时刻的 mark-to-market 永续账户权益。user_ledger_updates—— 窗口内永续账户的净资金进出(充值、提现、现货↔永续划转、金库流动)。
算法(净资金流去污的峰值-谷值回撤)。
给定窗口内按时间排序的账户权益快照序列 s_0, s_1, …, s_n,我们向前遍历,维护候选的 (peak, trough) 对。对每一对,计算从 peak.time 到 trough.time 之间观察到的净资金流 netIn。修正后的有效峰值/谷值为:
if netIn > 0:
effectivePeak = peak.value + netIn
effectiveTrough = trough.value
elif netIn < 0:
effectivePeak = peak.value
effectiveTrough = trough.value + |netIn|
else:
effectivePeak, effectiveTrough = peak.value, trough.value
if effectiveTrough >= effectivePeak or effectivePeak == 0:
drawdown = 0
else:
drawdown = (effectivePeak − effectiveTrough) / effectivePeak
窗口内 drawdown 最大的那一对即为最终结果。
为什么要做去污。 若不做净资金流修正:一个用户亏损 5k 之后再充值 10k,会被错误地显示为"已经恢复"(因为原始权益上升);而一个提现 10k 的用户,会被错误地记为回撤了 10k。去污修正把净资金流视为外生因素,仅度量真实的交易盈亏。
参数。
days∈ {1, 7, 30, 60, 90}。HTTP 层强制限制在[1, 90]区间。scope = perp(隐式)。
响应结构。
{
"high": { "time": 1714000000000, "value": "123456.78" },
"low": { "time": 1714100000000, "value": "100000.00" },
"maxDrawdown": "0.19",
"netIn": "5000.00"
}
netIn 是 high.time 到 low.time 区间内的净资金流(不是整个请求窗口的)。
已知限制 —— 保留期截断(Retention Truncation)。 snapshots_perp 在存储层的保留期是 30 天。即使客户端请求 days=60 或 days=90,送入算法的快照序列也只回溯到 30 天前。因此返回的回撤实际上是 [now − min(30d, days), now] 区间内的真实回撤。详见 数据保留期与历史深度。
权益曲线(Portfolio / Equity Curve) —— /hl/portfolio/{address}/{window}
用途。 输出一段适合绘制权益曲线(equity curve)的按市值计价账户权益时间序列。
输入数据。 accum_pnls.perp_value(在该表同时填充了永续+现货的场景下,也以 TotalValue 字段暴露)。每一行是与 Hyperliquid 节点快照对齐的账户权益快照。
窗口与采样。
window | 回溯长度 | 采样方式 |
|---|---|---|
day | 最近 24 小时 | 全部快照(约 50–200 个点) |
week | 最近 7 天 | 全部快照(约 500–1000 个点) |
month | 最近 30 天 | 降采样为每 12 小时一个点(约 60 个点) |
allTime | 从 2025-12-06 15:00 UTC 起 | 每天 1 个点 |
2025-12-06T15:00 这个锚点是当前数据集的起始时间戳,硬编码在服务端;window=allTime 的请求不会返回早于该时间点的数据。
权益口径。 返回的 value 是 mark-to-market 权益,同时包含已累计到账户的已实现盈亏(realized PnL)与所有未平仓仓位的未实现盈亏(unrealized PnL)。我们不把序列拆分成已实现/未实现,也不拆分成充值/交易盈亏。如果你需要一条去除资金流干扰的 ROI 曲线,请参考 自定义指标计算,结合 /hl/ledger-updates/net-flow 进行二次加工。
响应结构。
{
"address": "0x…",
"window": "week",
"points": [ { "time": 1714000000000, "accountValue": "123456.78" } ]
}
已知限制 —— 保留期截断。 accum_pnls 的保留期是 90 天。尽管 window=allTime 名义上从 2025-12-06 开始,实际返回的最早一点不会早于 90 天前。这是有意为之的行为,将来会在 API 参考文档中补充说明。
净资金流(Net Flow) —— /hl/ledger-updates/net-flow/{address}, /hl/ledger-updates/batch-net-flow
用途。 在窗口内,地址净流入 Hyperliquid 永续与现货账户的 USD 金额。用于对收益率做去污(decontamination)处理,把盈亏和资金流区分开来。
输入数据。 user_ledger_updates,按地址与时间窗口过滤。
计入的事件类型。
- L1 充值(链上桥入)。
- L1 提现(桥出,记负)。
- 内部现货 ↔ 永续划转(在
netPerpIn与netSpotIn同时以相反符号计入,以保证总账对齐)。 - 金库(vault)的充值与提现。
不计入的事件类型。
spotTransfer(钱包到钱包的现货转账,未跨越 Hyperliquid 永续/现货边界)。subAccountTransfer(主账户与子账户之间的记账变动 —— 对母账户的整体资本并无影响)。
计算方式。 按类别对带符号的 USD 等值金额求和,返回形如:
{
"address": "0x…",
"netPerpIn": "12345.00",
"netSpotIn": "678.90"
}
参数。
days∈ {1, 7, 30, 60, 90, 0}。days=0表示"全部历史"。
已知限制 —— 保留期截断。 user_ledger_updates 的保留期是 90 天。实务上,days=0 与 days=90 返回相同的结果。我们不回填(backfill)保留期之前的事件。
交易者行为统计(Trader Behaviour) —— /hl/traders/{address}/addr-stat, /hl/traders/batch-behavior-metrics
用途。 以滚动窗口汇总地址的交易行为画像,返回一组行为统计指标。
输入数据。 预聚合的物化表 positions_dex_1d、positions_dex_7d、positions_dex_30d(每个地址一行,字段是对应窗口的聚合结果)。当 period=0(保留期内"全部历史")时,回落到对 fills 和 filled_orders 的区间扫描,受常量 behaviorMetricsMaxLookbackDays = 90 约束,最多回溯 90 天。
字段。
| 字段 | 口径 |
|---|---|
winRate | 窗口内 closedPositionsWithPnl>0 / totalClosedPositions。 |
maxDrawdown | 与上文最大回撤算法一致,在区间聚合表中预先算好。 |
totalPnl | 窗口内所有已平仓仓位的已实现盈亏求和,USD。 |
orderCount | 窗口内不同已成交订单的计数。 |
closedPositionCount | 窗口内开仓并完全平仓的仓位数。 |
avgPositionDurationSec | 已平仓仓位 (close_time − open_time) 的均值,单位秒。 |
profitLossRatio | mean(盈利平仓的盈利额) / mean(亏损平仓的亏损绝对值)。任一侧为空时返回 0。 |
参数。
period∈ {1, 7, 30, 0}。超出该集合的取值一律拒绝。period=0在服务端被截断为最多 90 天的回溯。
不提供的指标。 夏普比率(Sharpe)、索提诺比率(Sortino)、Calmar 比率、盈利因子(Profit Factor),以及相对基准的 alpha,均有意不纳入。这些指标依赖无风险利率、采样频率、基准等主观选择,我们更希望由客户端显式决定。自定义指标计算 一节会演示如何基于我们已经暴露的原语把它们拼出来。
数据保留期与历史深度
我们运行的是滚动的热数据集(rolling hot dataset),目前尚未维护冷归档。截至 2026-04-21,生效的保留期策略如下:
| 表 | 保留期 | 影响到的接口 |
|---|---|---|
fills | 90 天 | 行为指标、自定义成交查询 |
filled_orders | 90 天 | 行为指标 |
accum_pnls | 90 天 | 权益曲线 |
user_ledger_updates | 90 天 | 净资金流 |
positions_dex_{1,7,30}d | 按日滚动重算 | 行为指标 |
snapshots_perp | 30 天 | 最大回撤 |
snapshots_position | 30 天 | 仓位状态查询 |
trades | 30 天 | K 线、最新成交查询 |
fundings | 30 天 | 资金费率序列 |
completed-trades(仓位) | 90 天 | 历史平仓仓位 |
实务影响。 任何名义窗口超过底层表保留期的请求,都会被静默地在截断后的序列上求值。接口不会报错 —— 它会透明地做 clamp。这里把行为明确写入方法论,方便客户端与自有回填数据做对齐。
路线图。 冷归档(S3 上的 Parquet)在规划中,但尚未上线。在它落地之前,超过上述保留期的数据无法通过本 API 获取。
已知局限
-
超过 30 天的回撤窗口会被截断。 目前
/hl/max-drawdown的days=60与days=90实际返回的是 30 天回撤。响应结构暂未携带effectiveWindowDays字段,未来版本会补上。在此之前,请把days≥30统一理解为"30 天最大回撤"。 -
Portfolio 的
allTime窗口以 90 天保留期为上限,而非硬编码的 2025-12-06 锚点。 锚点定义了我们愿意返回的最早日期;保留期定义了我们实际拥有的最早日期。 -
行为指标的
period=0是 90 天近似。period=0下计算得到的首次成交时间、总订单数、加仓摘要等字段,都只反映最近 90 天。对于在该窗口之前就已经开始在 Hyperliquid 交易的地址,其"首次成交时间"会是保留期内最早的一笔成交,而不是真正的起点。 -
净资金流不包含保留期之外的充值。 若某地址的首次充值发生在查询时间点 90 天以前,它的
netPerpIn会比朴素的链上求和结果偏小。 -
不做子账户聚合。 每个地址独立查询。如果一个交易者使用多个地址,聚合逻辑由客户端自行处理。
-
不做滑点、手续费归一化。 盈亏数据直接来自 Hyperliquid 账本,已经包含支付的交易所手续费。我们不区分总盈亏(gross)与净盈亏(net)。
-
无实时性保证。 快照是最终一致的。Hyperliquid 节点到 API 的端到端时延通常在 10–30 秒;在高成交量时段因反压(back-pressure),可能延长到数分钟量级。
基于原语计算自定义指标
以下给出在客户端侧构建常见风险调整类指标的几种示例做法,完全只使用上文暴露的接口。
资金流去污的 ROI(Capital-Flow-Decontaminated ROI)
原始 ROI = equity[T]/equity[0] − 1 受充提资金影响,会失真。修正后的 ROI:
equity = /hl/portfolio/{addr}/{window}.points # time, accountValue
flows = /hl/ledger-updates/net-flow/{addr}?days=N # netPerpIn + netSpotIn
ROI_adj = (equity[T] − equity[0] − netTotalIn) / (equity[0] + max(0, netTotalIn))
若需要时间序列形式,可采用修正 Dietz(Modified Dietz)或时间加权收益率(TWR)方法,把资金流事件作为子区间边界来切分。
夏普比率(Sharpe Ratio)
选择一个采样区间 Δt(例如从 allTime portfolio 窗口中取日频),然后:
r_i = equity[t_i] / equity[t_i-1] − 1 # 单期收益
r̄ = mean(r_i)
σ = stddev(r_i)
Sharpe_annualised = (r̄ − r_f · Δt) / σ · sqrt(periodsPerYear)
r_f 是你自己选定的无风险利率;我们不强加任何默认值。
索提诺比率(Sortino Ratio)
与夏普同构,但用下行偏差(downside deviation)替代 σ:
σ_d = sqrt( mean( min(0, r_i − τ)^2 ) ) # τ 为目标收益,通常取 0
Sortino = (r̄ − τ) / σ_d · sqrt(periodsPerYear)
盈利因子(Profit Factor)
由行为指标出发,profitLossRatio × (winRate / (1 − winRate)) 在盈亏两侧交易平均规模符合返回均值的假设下,代数上恰好等于盈利因子 sum(wins)/sum(|losses|)。若要更严格的计算,请直接查询成交数据,自行计算:
PF = Σ positive_realised_pnl / |Σ negative_realised_pnl|
如对本文档有疑问、发现口径差异,或希望我们新增某个指标,请联系对接的商务/技术支持。