Derived metrics methodology

Schema 2026-07-21 · last updated 2026-07-21

Every snapshot includes a data.derived block. These are not new data — they are transparent arithmetic on the exact on-chain values already in the response. Each metric, its formula, and its edge cases are defined below so any caller can reproduce every number. Agents can fetch the same definitions as JSON at https://orcpin.dev/methodology.

Wallet-level metrics

Applies to: /v1/wallet-snapshot, /v1/defi-snapshot, /v1/batch-snapshot

Present in every snapshot under data.derived. Computed from account flags, the native balance, and the current gas price at the anchored block.

FieldFormulaNotes
wallet_typeWallet type is_contract ? "contract" : "eoa"enum: "eoa" | "contract" Based on whether the address has bytecode at the anchored block.
activity_tierActivity tier 0 → "new"; 1–9 → "low"; 10–99 → "active"; ≥100 → "power"enum: "new" | "low" | "active" | "power" Buckets on the outbound nonce only. A coarse activity heuristic — not an age, identity, or reputation score.
gas_runway.gas_price_weiGas price (wei) eth_gasPrice at request timewei (string) The whole gas_runway object is null if the gas-price read fails.
gas_runway.assumed_gas_unitsAssumed gas units constant 21000gas units Gas for a simple native ETH transfer. Contract calls cost more, so this is a best-case upper bound.
gas_runway.est_tx_cost_weiEstimated tx cost (wei) gas_price_wei × 21000wei (string) Cost of one simple transfer at the current gas price.
gas_runway.simple_transfers_affordableSimple transfers affordable floor(native_balance.wei ÷ est_tx_cost_wei)integer count How many simple transfers the ETH balance could pay for at the current gas price. Gas price varies block to block, so treat as an estimate.

Aave v3 metrics

Applies to: /v1/defi-snapshot

Present under data.derived.aave only when the address has an Aave v3 position (aave_v3.available && aave_v3.has_position); otherwise data.derived.aave is null. USD figures use Aave's base currency (8 decimals). Below, C = total_collateral, D = total_debt, HF = health_factor.

FieldFormulaNotes
net_equityNet equity C − DUSD (8 decimals) Position value net of debt.
unused_borrow_powerUnused borrow power available_borrows (pass-through)USD (8 decimals) The value Aave reports as still borrowable.
ltv_utilization_pctLTV utilization D == 0 → 0; else (D ÷ C) ÷ (loan_to_value_bps ÷ 10000) × 100percent (1 dp) null when C = 0 or loan_to_value_bps = 0 — Percent of the maximum borrow allowed by LTV that is currently used.
leverage_multiplierLeverage multiplier C ÷ (C − D)ratio (2 dp) null when equity (C − D) ≤ 0 — Equity multiplier of the position.
health_factor_bandHealth factor band no debt → "no_debt"; HF ≥ 2 → "safe"; 1.5 ≤ HF < 2 → "moderate"; 1.1 ≤ HF < 1.5 → "elevated"; HF < 1.1 → "critical"enum: "no_debt" | "safe" | "moderate" | "elevated" | "critical" Fixed thresholds on Aave's reported health factor. A label, not a recommendation.
collateral_drawdown_tolerance_pctCollateral drawdown tolerance (1 − 1 ÷ HF) × 100percent (1 dp) null when no outstanding debt — Percent the collateral value can fall before HF reaches 1 (Aave's liquidation point). Derived from Aave's own definition HF = (collateral × liquidation_threshold) ÷ debt: holding debt and the threshold constant, HF scales linearly with collateral value, so collateral can drop by (1 − 1/HF) before HF = 1. Assumes a uniform collateral price move with debt and threshold constant; it is a point-in-time estimate, not a prediction or advice.

x402 endpoint reliability

Applies to: /v1/endpoint-reliability, /v1/endpoint-reliability/batch

Unlike the snapshot metrics above, these facts are NOT computed from a single response — they aggregate Orcpin's own independent probe history for a target x402 endpoint over a rolling ~60-day window. Each probe is an unpaid request with no body (which returns the endpoint's 402 challenge at zero cost, before the endpoint does any work). We probe with GET first; if the endpoint answers with a status that indicates the wrong verb rather than a fault (404, 405, 501) we retry once with POST and record only that result — a large share of x402 endpoints are POST-only, and counting our own wrong verb against them would understate their reliability. A small, opt-in sample of probes additionally make a real PAID call to verify delivery. The subject is software delivery (did it respond, was the 402 well-formed, how fast) — NOT the financial quality or accuracy of any data the endpoint returns. Every value is a raw measured rate or count: there is no composite 'trust score' and no 'scam'/'safe' label. The caller applies its own thresholds. Below, P = total probes recorded.

Coverage. Two things populate the measurement history. A scheduled sweep continuously re-probes a worklist drawn from the public CDP Bazaar catalog and ordered by real demand (unique payers over the last 30 days), so the endpoints agents actually pay for hold the deepest samples. Anything else is probed on demand: ask about an endpoint we hold no measurement for — through either the single or the batch route — and it is probed live before the response is built, then kept for subsequent callers. A first-ever lookup therefore returns a one-sample measurement carrying the 'low_sample' flag, never a blank. We make no claim to have pre-measured the whole catalog, and 'unmeasured' means exactly what it says: no probe history and no live probe reached it.

FieldFormulaNotes
reachable_rateReachable rate probes that returned any HTTP response ÷ Pratio 0–1 (3 dp), null when P = 0 A probe is 'reachable' if it got an HTTP response at all (no timeout or transport error). Says nothing about the status code.
http_success_rateHTTP success rate probes whose status was 2xx OR a well-formed 402 ÷ Pratio 0–1 (3 dp), null when P = 0 For an x402 endpoint a 402 is correct behaviour (it is demanding payment), so it counts as success. Measures whether the endpoint responded as expected — not whether returned data is correct.
valid_402_rateValid 402 rate probes whose 402 body was a well-formed x402 challenge ÷ Pratio 0–1 (3 dp), null when P = 0 A 402 is 'valid' when its body parses as an x402 challenge (has an `accepts` array or an `x402Version`). Distinguishes a real paywalled endpoint from a generic 402.
latency_ms.p50 / p95 / p99Latency percentiles percentiles over a fixed 7-bucket histogram with edges 100/250/500/1000/2500/5000 ms; the reported value is the upper edge of the bucket the percentile falls intomilliseconds (bucketed estimate), null when no timed probes Bucketed, so these are estimates, not exact percentiles — the response marks basis:'histogram'. Round-trip wall-clock time of the probe request.
last_statusLast status HTTP status code of the most recent probeHTTP status integer, null when unknown 402 is normal and healthy for a paid endpoint.
consecutive_failuresConsecutive failures count of probes since the last success; reset to 0 on any successinteger count
delivery_verifiedDelivery verification verified = (paid probes that returned a parseable response > 0); samples = paid probes attemptedobject { verified, at, samples }, null when no paid probe has run Present only when sampled PAID verification has been run for the endpoint (off by default). It is the only fact whose measurement involved spending. Confirms the endpoint actually returns a response after payment; it does not judge the returned data.
flagsFactual flags "unmeasured" when P = 0; "unprobeable_url" when the URL can't be safely probed; "low_sample" when 0 < P < 5; "unreachable" when 0 of ≥5 probes got any response; "consecutive_failures" when consecutive_failures ≥ 3; "last_probe_error" when last_status ≥ 500; "stale_measurement" when the last probe is older than 7 days; "delivery_failed" when every paid delivery attempt failedarray of enumerated string markers (may be empty) Enumerated factual markers, each with a fixed mechanical trigger above. Condition flags (unreachable / consecutive_failures / last_probe_error) are suppressed below 5 probes — a single transient bad sweep never flags an endpoint; "low_sample" is emitted instead and the raw rates still report what was seen. Never adjectives like 'scam' or 'unsafe', and never a recommendation — the caller decides what they mean for its use.

Trade-log calculators

Applies to: /v1/holding-period, /v1/day-trade-count, /v1/settlement-dates, /v1/settlement-date

Unlike the chain metrics above, these are computed ONLY from the trade data the caller supplies in the request (a JSON body, or query params for the single-trade /v1/settlement-date GET) — nothing is fetched, and nothing is stored. Pure calendar arithmetic (UTC days) with the statutory threshold cited as a published fact; the response never states a verdict about the caller. All conventions below are deterministic: same inputs, same output, no server clock. Trading-day math (day-trade windows, T+1 settlement) uses a versioned, published NYSE holiday table echoed as calendarVersion in each response; dates outside its range are a 400, never a guess.

FieldFormulaNotes
lots[].daysHeldDays held asOf − acquireDate, in whole UTC calendar daysinteger days The holding period begins the day AFTER acquisition (IRS Pub 550), so the acquisition day itself counts 0.
lots[].longTermFromLong-term from acquireDate + 1 year + 1 day (UTC calendar)date (YYYY-MM-DD) First date on which a sale is long-term under IRC §1222 (held MORE than one year): a sale exactly on the one-year anniversary is short-term. Feb 29 acquisitions roll the anniversary to Mar 1 (the later, conservative boundary).
lots[].character / sell.allocations[].characterGain character (evaluation date ≥ longTermFrom) ? "long_term" : "short_term"enum: "short_term" | "long_term" A definitional label from the cited threshold — not a recommendation about whether or when to sell.
sell.allocations[]Sell allocation method "fifo": consume matching-symbol lots oldest acquireDate first; method "as_supplied": consume in the caller's array order (specific identification). The last lot consumed may be split.array of per-lot allocations Selling more shares than the supplied lots hold is a 400 error, never a partial answer.
sell.allocations[].realizedGainRealized gain per allocation proceeds − allocated basis, where proceeds = quantity × sell.price and allocated basis = lot.costBasis × (quantity ÷ lot.quantity); both rounded to centsUSD (2 dp) null when the lot has no costBasis, or the sell has no price — Cost basis is used exactly as supplied — wash-sale basis adjustments, corporate actions, and splits are not applied.
sell.totalsPer-character totals sum of allocation quantities and realizedGain per character (short_term / long_term)object per character null when realizedGain is null when ANY allocation in that character bucket lacks basis or price — a partial sum would misstate the total
window.tradingDays (day-trade-count)Rolling five-trading-day window the 5 most recent NYSE trading days at or before asOf, per the versioned holiday table (weekends and listed full-close holidays skipped)array of 5 dates, oldest first Anchors FINRA's 'five business day period' to real trading days. asOf on a weekend/holiday anchors at the prior trading day.
day_trade_countDay-trade count per (symbol, date) inside the window: min(buy executions, sell executions); summed across symbol-datesinteger count Matched same-day round trips by execution COUNT — quantities are not netted; brokers' counting can differ, and the convention is stated in every response. FINRA Rule 4210's pattern-day-trader definition is cited separately in threshold_citation; the response never applies it to the caller.
day_trade_ratioDay-trade ratio day_trade_count ÷ total_trades_in_window (3 dp)ratio 0–1 null when no supplied trades fall inside the window — Reported because Rule 4210's definition includes a >6% clause; the comparison remains the caller's.
trades[].settlementDate (settlement-dates)Settlement date the next NYSE trading day strictly after tradeDate (T+1), per the versioned holiday tabledate (YYYY-MM-DD) SEC Rule 15c6-1 (as amended, effective 2024-05-28) is cited separately in rule_citation. Assumes standard US equity settlement; other instruments can differ.
trades[].settledAsOfSettled as of asOf ≥ settlementDateboolean Settlement completes on the settlement date itself. A dates fact — never a violation determination.

Derived metrics are transparent arithmetic on the same on-chain values already in each response — not financial, legal, or investment advice, and not predictions. Read-only and factual. See /terms for acceptable use.