> For the complete documentation index, see [llms.txt](https://docs.nexus.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.nexus.xyz/api-reference/zh-cn/guides/portfolio.md).

# 资产组合与账户状态

跨 SDK 和 CLI 的汇总账户状态、可提现余额、费率表、增强仓位字段以及资产组合时间序列。

资产组合端点回答关于账户的四个问题：它现在值多少、可以提现多少、被收取多少费用，以及它随时间的表现如何。它们是一小组需要认证的 REST 端点，外加增强的逐仓位风险字段。每个接口（Rust、TypeScript 和 Python SDK 以及 CLI）访问的都是网关上的同一组路由，详见 [API 与速率限制](https://docs.nexus.xyz/exchange/apis-and-rates)。

如果您正在构建资产组合视图，请在渲染任何内容之前先阅读[安全读取这些值](#reading-these-values-safely)。有几个字段有意设计为可空，有一个符号约定很容易弄反，而一个简单的两次调用实现在生产环境中会遇到竞态条件。

### 获取方式

```bash
npm install @nexus-xyz/exchange-ts    # TypeScript
cargo add nexus-exchange              # Rust
pip install nexus-exchange            # Python
```

CLI 通过 [`nexus-exchange-cli`](https://github.com/nexus-xyz/nexus-exchange-cli) 的发布版本分发。全部四个客户端请参见[接口概览](/api-reference/zh-cn/readme.md)。

### 身份验证

本页的每个路由都限定在账户范围内，并且需要 HMAC API 密钥。没有公开或无需认证的版本。请求需携带 `X-API-Key`、`X-Timestamp` 和 `X-Signature`，并且时间戳必须与服务器时间相差不超过30秒。SDK 和 CLI 会替您签名。完整流程以及可运行的 cURL 示例请参见[快速入门](https://docs.nexus.xyz/exchange/trading/quickstart)。

请不要把 API secret 写进源代码或留在 shell 历史中。它只在创建时显示一次，之后无法再次获取。下面的示例从环境变量中读取它。

### 选择网络

交易所目前运行在 Nexus Testnet 上，主网随后推出。请在构造客户端时选择网络。各接口如何选择网络以及 API 密钥如何绑定到网络，请参见[网络](/api-reference/zh-cn/guides/networks.md)；当前的基础 URL 请参见 [API 与速率限制](https://docs.nexus.xyz/exchange/apis-and-rates)。这些路由所需的 HMAC 密钥仅限于创建它的网络。

### 参考

| 方法  | 路径                                          | 认证   | 描述                                  |
| --- | ------------------------------------------- | ---- | ----------------------------------- |
| GET | `/account/state`                            | HMAC | 资产组合摘要**以及**所有未平仓仓位，来自同一次一致的读取      |
| GET | `/account/summary`                          | HMAC | 仅资产组合摘要，与 `/account/state` 中内嵌的对象相同 |
| GET | `/account/fees`                             | HMAC | 账户的实际费率表                            |
| GET | `/account/portfolio-history?window=&limit=` | HMAC | 权益、累计盈亏和累计成交额的时间序列                  |

各 SDK 的入口：

| 接口         | 汇总状态                    | 费率表                    | 时间序列                                               |
| ---------- | ----------------------- | ---------------------- | -------------------------------------------------- |
| Rust       | `fetch_account_state()` | `fetch_account_fees()` | `fetch_portfolio_history(window, limit)`           |
| Python     | `fetch_account_state()` | `fetch_account_fees()` | `fetch_portfolio_history(window, limit)`           |
| TypeScript | `getAccountState()`     | `getAccountFees()`     | `getPortfolioHistory({ window, limit })`           |
| CLI        | `nexus account state`   | `nexus account fees`   | `nexus account portfolio-history --window --limit` |

### 汇总账户状态

`GET /account/state` 返回资产组合汇总数据以及所有未平仓仓位，二者都来自服务器端的**同一次**读取。由于两部分来自同一个快照，`summary.open_positions_count` 始终等于 `positions` 的长度。

摘要包含 `collateral`、`total_equity`、`total_unrealized_pnl`、`total_realized_pnl_24h`、`total_volume_24h`、`open_positions_count`、`open_orders_count`、`margin_used`、`available_margin` 和 `withdrawable`。

**`withdrawable`** 是可以转出账户的余额：以引擎为准的可用保证金，下限为零，即 `max(0, available_margin)`。可用保证金已经从权益中扣除了每个仓位的初始保证金和每笔下单前的订单保证金占用，因此这就是提现可以动用的金额。它不是 `total_equity`，也不是 `collateral`。资不抵债的账户会被截断为 `"0"`，永远不会报告为负数。该值来自权威的保证金视图，因此当该视图不可用时，端点会**以 `502` 故障关闭**，而不是返回一个本地估算的数字。

### 费率表

`GET /account/fees` 报告交易所当前向该账户收取的费用。这是面向未来的费率表费率，而不是过去成交的实际平均费率。

| 字段                     | 说明                                             |
| ---------------------- | ---------------------------------------------- |
| `maker_fee_bps`        | 顶层费率，以基点表示。可以为负；当 `schedule=unknown` 时，零是哨兵值   |
| `taker_fee_bps`        | 顶层费率，以基点表示；当 `schedule=unknown` 时，零是哨兵值        |
| `tier`                 | 目前始终为 `base`；尚无按账户划分的等级                        |
| `schedule`             | `per_market`、`reference` 或 `unknown`；请按开放字符串处理 |
| `markets`              | 保留的成交缓冲区内各市场的费率；按 `market_id` 排序               |
| `volume_30d`           | 滚动30天的成交名义价值，十进制字符串。尽力而为，参见下面的标志               |
| `volume_30d_estimated` | 当 `volume_30d` 可能**少计**（源成交缓冲区已满）时为 `true`     |
| `discounts`            | 生效中的折扣。目前始终为空                                  |

当 `schedule` 为 `per_market` 时，请以返回的 `markets` 行作为权威费率。顶层的那一对费率只是它们确定性的众数摘要。有上限的内存成交缓冲区可能会重置或淘汰旧市场，因此某一行缺失并不能证明该账户从未交易过该市场。`reference` 表示保留的缓冲区中没有任何市场带有镜像的费率表，此时顶层的那一对费率是所有已镜像交易所市场中确定性的众数费率。两种众数计算都以出现次数最多的那一对为准，出现平局时取字典序最小的 `(maker_fee_bps, taker_fee_bps)` 组合。`unknown` 表示市场参数不可用。此时 `markets` 为空，两个顶层基点值都是零哨兵值，并不代表免手续费。目前不存在按账户划分的等级或折扣计划。请把 `schedule` 视为开放取值，也不要针对并不存在的折扣结构编写分支。

### 资产组合时间序列

`GET /account/portfolio-history` 返回某个窗口内的权益、累计交易盈亏和累计成交名义价值，并在服务器端降采样。数据点**按时间从旧到新**排列。

| `window` | 间隔  | 最大数据点数 | 跨度   |
| -------- | --- | ------ | ---- |
| `day`    | 5分钟 | 288    | 24小时 |
| `week`   | 1小时 | 168    | 7天   |
| `month`  | 6小时 | 120    | 30天  |
| `all`    | 1天  | 366    | 约1年  |

省略 `window` 时默认为 `day`。不在该集合中的值会以 `400`（`invalid_window`）被拒绝。如果该参数重复出现，则使用第一个值。`limit` 必须在 `1` 到 `366` 之间。在此范围内，它会缩小结果，并被**截断**到窗口的容量，而不是被拒绝，因此请求 `day` 的366个数据点会返回288个，而不是报错。超出该范围时，请求会以 `400` 被拒绝。

响应会回显实际提供的 `window` 和 `cadence_ms`。请读取回显的值，而不要假定就是您发送的值，这样您的图表坐标轴使用的才是实际提供的值。

每个数据点都包含 `timestamp_ms`、`equity`、`pnl` 和 `volume`。`pnl` 和 `volume` 是**截至该采样点的累计值**，而不是每个区间的值。如果要绘制每个区间的活动，请自行计算相邻数据点之差。

### 增强仓位字段

`/account/state`（以及 `/positions`）返回的仓位，除了 `symbol`、`side`、`size`、`entryPrice`、`unrealizedPnl` 和 `realizedPnl` 之外，还带有逐仓位的风险详情：

| 字段              | 含义                                       |
| --------------- | ---------------------------------------- |
| `notional`      | `abs(size) × mark price`                 |
| `initialMargin` | 按全仓保证金模型为该仓位占用的初始保证金                     |
| `roe`           | 初始保证金回报率：`unrealizedPnl / initialMargin` |
| `max_leverage`  | 该市场允许的最大杠杆，来自其风险参数                       |
| `leverage`      | 该账户在此仓位上的杠杆倍数                            |
| `funding_paid`  | 该仓位的累计资金费。符号约定见下文                        |

**这些名称采用 CCXT 的统一词汇**，因此 `ccxt.nexus()` 客户端可以直接读取这一结构。CCXT 中没有对应项的字段保留交易所自己的写法：`size`、`roe`、`max_leverage`、`funding_paid`。`GET /account` 不是这种结构。它由撮合引擎转发，返回的是一个范围更窄、使用引擎自有命名的对象。

服务器在低延迟读取路径上计算这些字段，而不是往返撮合引擎，从而保持端点的速度。代价是，当某个输入在该路径上不可用时，该字段为 `null`，并由配套的 `<field>_error` 给出机器可读的原因，而不是编造一个数字。

**`leverage` 目前始终为 `null`**，并且 `leverage_error` 被设为 `margin_state_not_mirrored`。推导它需要账户的杠杆设置或其分配的保证金，而这两者在读取路径上都不可用。不要根据 `initialMargin` 反推它。那个表达式会简化为 `1 / initial_margin_rate`，这是一个按市场设定的常数，而不是仓位的真实杠杆，因此对该市场中的每个仓位都是错误的。

**`funding_paid` 以支付为正。** 正值表示该仓位*支付*了资金费，负值表示它*收取*了资金费。该字段始终存在，在产生任何资金费之前为 `"0"`，并受交易所保留的资金费历史限制。把这个符号弄反，会在盈亏界面上把成本变成收入，所以请为它编写测试。

### 安全读取这些值

**金额是十进制字符串，而不是数字**。`equity`、`pnl`、`volume`、`withdrawable`、`notional` 等都是以字符串序列化的任意精度十进制数，从而保证无损。请使用十进制类型解析它们。如果经过浮点数（`parseFloat`、`float()`、`as f64`）转换，就会重新引入字符串编码本来要避免的舍入误差。杠杆字段（`leverage`、`max_leverage`）则是真正的 JSON 数字。

**派生字段有三种状态，而不是两种**。五个计算得出的仓位字段（`notional`、`initialMargin`、`roe`、`leverage` 和 `max_leverage`）中的每一个都可能是：

1. **一个值**：已计算且具有权威性；
2. **`null`**：已报告但无法计算，配套的 `<field>_error` 会说明原因；
3. **缺失**：服务器版本早于该字段。

把其中任何一种情况折算成 `0` 都是在捏造数据。当用户询问其仓位价值多少时，“未报告”、“无法计算”和“零”是三种不同的答案，而其中只有一种是数字。请把缺失的情况显示为明确的空缺（CLI 会打印 `-`），并在有 `<field>_error` 时将其展示出来。`withdrawable` 也是如此。它在 Schema 中是可选的，因此较旧的部署可能省略它；如果将其默认为 `"0"`，就等于告诉用户他们没有任何可用余额，而服务器实际上从未报告过该值。

恰好只有这五个字段带有配套的 `<field>_error`。`funding_paid` 不在其中。它始终存在，因此没有可供分支判断的 `funding_paid_error`。

**优先使用 `/account/state`，而不是两次调用。** 分别获取 `/account/summary` 和 `/positions`，是对一个活跃账户发出的两个独立请求。如果两次请求之间有一笔成交落地，返回的汇总数据就会与仓位列表不一致（`open_positions_count` 显示三个，数组里却有四个），而这在任何真实负载下都会发生。汇总端点用同一次一致的读取支撑这两部分。

**分别处理各个失败状态码**。`401` 是凭证或时钟问题。在认定密钥错误之前，请先检查 `X-Timestamp` 是否与服务器时间相差不超过30秒。`429` 表示您超出了速率预算；请参见[速率限制](/api-reference/zh-cn/guides/rate-limits.md)，并进行退避，而不是立即重试。本页有三个路由（`/account/summary`、`/fills` 和 `/account/portfolio-history`）每次消耗该预算的**五**个单位，而不是一个，所以在紧密循环中轮询它们，会以比请求次数所显示的快五倍的速度耗尽 Pro 调用方每秒20次的额度。`/account/state` 只消耗一个单位，并同时返回摘要和仓位，是读取两者更省的方式。`/account/state` 和 `/account/summary` 返回 `502`，表示权威的保证金视图无法访问，服务器拒绝猜测。请重试，并且不要回退到本地计算的 `withdrawable`。

### 示例

```bash
export NEXUS_API_KEY=nx_7f3a1b...          # the key ID is not secret

# Prompt for the secret instead of typing it inline — an `export
# NEXUS_API_SECRET=...` would leave it in your shell history.
read -rs NEXUS_API_SECRET && export NEXUS_API_SECRET

nexus account state
nexus account fees
nexus account portfolio-history --window week
```

```typescript
import { Client, Network } from "@nexus-xyz/exchange-ts";

const client = new Client({
  network: Network.Testnet,
  apiKey: process.env.NEXUS_API_KEY!,
  apiSecret: process.env.NEXUS_API_SECRET!,
});

// One coherent read: open_positions_count cannot disagree with positions.length.
const { summary, positions } = await client.getAccountState();

// Absent is not zero — say so rather than defaulting.
console.log(`withdrawable: ${summary.withdrawable ?? "<not reported>"}`);

for (const p of positions) {
  // null carries a reason in the companion field; absent carries nothing.
  const roe = p.roe ?? (p.roe_error ? `<${p.roe_error}>` : "<not reported>");
  // Paid-positive: a positive funding_paid means this position paid.
  console.log(`${p.symbol} ${p.side} ${p.size}  roe=${roe}  funding_paid=${p.funding_paid}`);
}

// The response echoes what was served — read it back, don't assume.
const history = await client.getPortfolioHistory({ window: "week" });
console.log(`${history.window} @ ${history.cadence_ms}ms, ${history.points.length} points`);
```

```json
{
  "summary": {
    "collateral": "25000.00",
    "total_equity": "25500.00",
    "total_unrealized_pnl": "500.00",
    "margin_used": "1075.00",
    "available_margin": "24425.00",
    "withdrawable": "24425.00",
    "open_positions_count": 1,
    "open_orders_count": 0
  },
  "positions": [
    {
      "symbol": "BTC-USDX-PERP",
      "side": "Long",
      "size": "0.25",
      "entryPrice": "84000.00",
      "unrealizedPnl": "500.00",
      "notional": "21500.00",
      "initialMargin": "1075.00",
      "roe": "0.4651",
      "max_leverage": 20,
      "leverage": null,
      "leverage_error": "margin_state_not_mirrored",
      "funding_paid": "3.21"
    }
  ]
}
```

上面的数字彼此一致。在标记价格为 `86000` 时，`notional` 为 `0.25 × 86000`，`unrealizedPnl` 为 `0.25 × (86000 − 84000)`，`initialMargin` 为 `notional × 1/max_leverage`，`roe` 为 `unrealizedPnl / initialMargin`，而 `withdrawable` 等于摘要中的 `total_equity − margin_used`，因为没有占用保证金的挂单。请注意最后一句中的两种写法：SUMMARY 对象上的 `margin_used` 是账户汇总值，保留其名称；仓位上的 `initialMargin` 则是逐仓位的要求。

可运行的端到端示例位于 SDK 仓库中：[`examples/portfolio.ts`](https://github.com/nexus-xyz/nexus-exchange-ts/blob/main/examples/portfolio.ts) 和 [`examples/portfolio.rs`](https://github.com/nexus-xyz/nexus-exchange-rs/blob/main/examples/portfolio.rs)。

### 相关内容

* [API 与速率限制](https://docs.nexus.xyz/exchange/apis-and-rates)
* [交易所 REST](https://docs.nexus.xyz/exchange/apis-and-rates/exchange-rest)
* [速率限制](/api-reference/zh-cn/guides/rate-limits.md)
* [接口概览](/api-reference/zh-cn/readme.md)
* [快速入门](https://docs.nexus.xyz/exchange/trading/quickstart)

> **状态**：测试网上的开发预览版。这些路由随 OpenAPI 规范 v0.7.2 发布，并在 v0.9.90 中仍为最新。在生产环境中请固定到某个规范版本，并在升级前查看各 SDK 的发布说明。`/account/fees` 目前没有按账户划分的等级或折扣计划，并且在其所需的保证金状态被镜像之前，`leverage` 报告为 `null`。测试网凭证和余额没有现实价值。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.nexus.xyz/api-reference/zh-cn/guides/portfolio.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
