> 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/ko/guides/portfolio.md).

# 포트폴리오 및 계정 상태

SDK와 CLI 전반에서 통합 계정 상태, 출금 가능 잔액, 수수료 일정, 확장된 포지션 정보, 포트폴리오 시계열을 다룹니다.

포트폴리오 엔드포인트는 계정에 대한 네 가지 질문에 답합니다. 지금 가치가 얼마인지, 무엇을 출금할 수 있는지, 수수료가 얼마인지, 시간에 따라 성과가 어땠는지입니다. 이들은 소수의 인증된 REST 엔드포인트와 포지션별로 확장된 리스크 필드로 구성됩니다. 모든 인터페이스(Rust, TypeScript, Python SDK와 CLI)는 [API 및 요청 한도](https://docs.nexus.xyz/exchange/apis-and-rates)에 문서화된 게이트웨이의 동일한 경로에 접근합니다.

포트폴리오 화면을 구축한다면, 무엇이든 렌더링하기 전에 [값을 안전하게 읽는 방법](#reading-these-values-safely)을 읽으십시오. 여러 필드가 의도적으로 null이 될 수 있고, 부호 규칙 하나는 뒤집기 쉬우며, 두 번 호출하는 단순한 구현은 프로덕션에서 경합 조건(race condition)에 부딪힙니다.

### 설치

```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/ko/readme.md)를 참조하십시오.

### 인증

이 페이지의 모든 경로는 계정 범위이며 HMAC API 키가 필요합니다. 공개 또는 인증 없는 버전은 없습니다. 요청에는 `X-API-Key`, `X-Timestamp`, `X-Signature`가 포함되며, 타임스탬프는 서버 시간과 30초 이내로 차이가 나야 합니다. SDK와 CLI가 서명을 대신 처리합니다. 실행 가능한 cURL을 포함한 전체 흐름은 [빠른 시작](https://docs.nexus.xyz/exchange/trading/quickstart)에 있습니다.

API 시크릿은 소스 코드와 셸 기록에 남기지 마십시오. 시크릿은 생성 시 한 번만 표시되며 나중에 다시 조회할 수 없습니다. 아래 예시는 시크릿을 환경 변수에서 읽습니다.

### 네트워크 선택

거래소는 현재 Nexus Testnet에서 운영되며, 메인넷이 뒤따를 예정입니다. 클라이언트를 생성할 때 네트워크를 선택하십시오. 각 인터페이스의 선택 방법과 API 키가 네트워크에 바인딩되는 방식은 [네트워크](/api-reference/ko/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`은** 계정에서 빠져나갈 수 있는 잔액으로, 엔진이 권위 있게 산출한 여유 증거금을 0 이상으로 제한한 값인 `max(0, available_margin)`입니다. 여유 증거금은 이미 각 포지션의 개시 증거금과 모든 거래 전 주문 예약분을 총자산에서 차감한 값이므로, 이것이 출금이 끌어 쓸 수 있는 금액입니다. `total_equity`도 아니고 `collateral`도 아닙니다. 손실 상태의 계정은 `"0"`으로 제한되며 절대 음수로 보고되지 않습니다. 이 값은 권위 있는 증거금 뷰에서 나오므로, 그 뷰를 사용할 수 없을 때 엔드포인트는 로컬에서 추정한 숫자를 반환하지 않고 **`502`를 반환하는 실패 시 차단(fail closed) 방식으로 동작합니다**.

### 수수료 일정

`GET /account/fees`는 거래소가 현재 계정에 부과하는 수수료를 보고합니다. 이는 향후 적용될 일정 요율이며, 과거 체결의 실현 평균이 아닙니다.

| 필드                     | 비고                                                                       |
| ---------------------- | ------------------------------------------------------------------------ |
| `maker_fee_bps`        | 대표 베이시스 포인트. 음수일 수 있으며, `schedule=unknown`일 때 0은 센티널 값입니다                |
| `taker_fee_bps`        | 대표 베이시스 포인트. `schedule=unknown`일 때 0은 센티널 값입니다                           |
| `tier`                 | 현재 항상 `base`이며, 아직 계정별 등급은 없습니다                                          |
| `schedule`             | `per_market`, `reference`, `unknown` 중 하나이며, 새 값이 추가될 수 있는 문자열로 취급하십시오   |
| `markets`              | 보존된 체결 버퍼에 있는 시장의 요율이며, `market_id` 순으로 정렬됩니다                            |
| `volume_30d`           | 최근 30일 롤링 거래 명목 가치, 10진수 문자열. 최선 노력(best-effort) 방식의 값이며, 아래 플래그를 참조하십시오 |
| `volume_30d_estimated` | `volume_30d`가 **과소 집계**되었을 수 있을 때 `true`(원천 체결 버퍼가 용량 한도에 도달함)           |
| `discounts`            | 적용 중인 할인. 현재 항상 비어 있습니다                                                  |

`schedule`이 `per_market`이면 반환된 `markets` 행을 권위 있는 요율로 사용하십시오. 최상위 쌍은 그 행들의 결정론적 최빈값 요약일 뿐입니다. 용량이 제한된 메모리 내 체결 버퍼는 초기화되거나 오래된 시장을 제거할 수 있으므로, 행이 없다고 해서 계정이 해당 시장에서 거래한 적이 없다는 증거는 아닙니다. `reference`는 보존된 버퍼에 일정이 미러링된 시장이 없으며, 최상위 쌍이 미러링된 모든 거래소 시장에 걸친 결정론적 최빈 요율이라는 뜻입니다. 두 최빈값 계산 모두 출현 횟수가 가장 많은 쌍이 선택되며, 동률이면 사전순으로 가장 작은 `(maker_fee_bps, taker_fee_bps)` 쌍으로 결정됩니다. `unknown`은 시장 파라미터를 사용할 수 없다는 뜻입니다. `markets`는 비어 있고 두 대표 bps 값은 무료 수수료 일정이 아니라 0 센티널 값입니다. 현재 계정별 등급이나 할인 프로그램은 존재하지 않습니다. `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` 사이여야 합니다. 이 범위 안에서는 결과를 좁히며, 거부되지 않고 해당 기간의 용량에 맞게 **상한 처리(clamp)됩니다**. 따라서 `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"`이고, 거래소가 보존하는 펀딩 이력의 범위 내로 제한됩니다. 이 부호를 뒤집으면 손익 화면에서 비용이 수입으로 바뀌므로, 이에 대한 테스트를 작성하십시오.

### 값을 안전하게 읽는 방법

**금액 값은 숫자가 아니라 10진수 문자열입니다.** `equity`, `pnl`, `volume`, `withdrawable`, `notional` 등은 손실 없이 표현되도록 문자열로 직렬화된 임의 정밀도 10진수입니다. 10진수 타입으로 파싱하십시오. 부동소수점(`parseFloat`, `float()`, `as f64`)을 거치면 문자열 인코딩이 막으려는 반올림 오차가 다시 생깁니다. 레버리지 필드(`leverage`, `max_leverage`)는 실제 JSON 숫자입니다.

**파생 필드에는 두 가지가 아니라 세 가지 상태가 있습니다.** 계산되는 다섯 개의 포지션 필드(`notional`, `initialMargin`, `roe`, `leverage`, `max_leverage`)는 각각 다음 중 하나일 수 있습니다.

1. **값**: 계산되었으며 권위 있는 값;
2. **`null`**: 보고되었지만 계산할 수 없으며, 짝이 되는 `<field>_error`가 사유를 알려 줌;
3. **없음**: 서버가 해당 필드보다 이전 버전임.

이 중 어느 것이든 `0`으로 뭉뚱그리면 데이터를 지어내는 것입니다. "보고되지 않음", "계산할 수 없음", "0"은 자신의 포지션 가치가 얼마인지 묻는 사용자에게 주는 서로 다른 세 가지 답이며, 그중 숫자는 하나뿐입니다. 누락된 경우는 명시적인 공백으로 렌더링하고(CLI는 `-`를 출력합니다), `<field>_error`가 있으면 함께 표시하십시오. `withdrawable`에도 같은 원칙이 적용됩니다. 이 필드는 스키마에서 선택 사항이므로 이전 배포에서는 생략될 수 있으며, 이를 `"0"`으로 기본 처리하면 서버가 값을 보고한 적이 없는데도 사용 가능한 금액이 없다고 알리게 됩니다.

이 다섯 개가 바로 짝이 되는 `<field>_error`를 가진 필드입니다. `funding_paid`는 여기에 포함되지 않습니다. 항상 존재하므로 분기할 `funding_paid_error`가 없습니다.

**두 번 호출하기보다 `/account/state`를 사용하십시오.** `/account/summary`와 `/positions`를 따로 가져오는 것은 거래가 진행 중인 계정에 대한 두 개의 독립된 요청입니다. 그 사이에 체결이 발생하면 포지션 목록과 맞지 않는 집계가 반환되며(`open_positions_count`는 3인데 배열에는 4개가 있음), 이는 실제 부하 상황에서는 언제든 일어납니다. 통합 엔드포인트는 두 부분을 하나의 일관된 읽기로 뒷받침합니다.

**실패 코드를 구분해서 처리하십시오.** `401`은 자격 증명 또는 시계 문제입니다. 키가 잘못되었다고 가정하기 전에 `X-Timestamp`가 서버 시간과 30초 이내인지 확인하십시오. `429`는 요청 한도 예산을 초과했다는 뜻입니다. [요청 한도](/api-reference/ko/guides/rate-limits.md)를 참조하고, 즉시 재시도하지 말고 백오프하십시오. 이 페이지의 세 경로(`/account/summary`, `/fills`, `/account/portfolio-history`)는 각각 해당 예산에서 1단위가 아닌 **5단위**를 소모하므로, 짧은 주기로 폴링하면 요청 횟수로 짐작하는 것보다 5배 빠르게 Pro 호출자의 초당 20회 허용량을 소진합니다. `/account/state`는 1단위를 소모하면서 요약과 포지션을 함께 반환하므로 둘 다 읽는 더 저렴한 방법입니다. `/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/ko/guides/rate-limits.md)
* [인터페이스 개요](/api-reference/ko/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/ko/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.
