> ## Documentation Index
> Fetch the complete documentation index at: https://docs.limitless.exchange/llms.txt
> Use this file to discover all available pages before exploring further.

# Portfolio & Positions

> Track positions and history with the TypeScript SDK

## PortfolioFetcher Setup

`PortfolioFetcher` provides access to your profile, positions, trade history, and accumulated points. Authentication is required.

```typescript theme={null}
import { HttpClient, PortfolioFetcher } from '@limitless-exchange/sdk';

const httpClient = new HttpClient({
  baseURL: 'https://api.limitless.exchange',
  apiKey: process.env.LIMITLESS_API_KEY,
});

const portfolio = new PortfolioFetcher(httpClient);
```

## Current Profile

Call `getProfile()` without an address to fetch the authenticated caller's private profile via `GET /profiles/me`. This avoids passing or persisting the wallet address when the client is already authenticated.

```typescript theme={null}
const currentProfile = await portfolio.getProfile();

console.log(currentProfile.id); // numeric profile ID
console.log(currentProfile.account); // authenticated wallet address
console.log(currentProfile.rank?.feeRateBps); // fee rate used for signing
```

To keep the existing address-based lookup, pass an address:

```typescript theme={null}
const profileByAddress = await portfolio.getProfile('0xYOUR_WALLET_ADDRESS');
```

<Note>
  `getProfile()` without an address calls `GET /profiles/me`; `getProfile(address)` calls `GET /profiles/:account`. Both return the private authenticated profile shape and require authentication.
</Note>

## All Positions

Fetch all positions across CLOB and AMM markets in a single call:

```typescript theme={null}
const positions = await portfolio.getPositions();

console.log('CLOB positions:', positions.clob.length);
console.log('AMM positions:', positions.amm.length);
console.log('Accumulative points:', positions.accumulativePoints);
```

### Response Structure

```typescript theme={null}
interface PositionsResponse {
  clob: ClobPosition[];
  amm: AmmPosition[];
  accumulativePoints: number;
}
```

## CLOB Positions

Retrieve only your CLOB market positions:

```typescript theme={null}
const clobPositions = await portfolio.getCLOBPositions();

for (const position of clobPositions) {
  console.log(`Market: ${position.market.slug}`);
  console.log(`  YES — size: ${position.positions.yes.size}, PnL: ${position.positions.yes.unrealizedPnl}`);
  console.log(`  NO  — size: ${position.positions.no.size}, PnL: ${position.positions.no.unrealizedPnl}`);
}
```

### CLOB Position Structure

```typescript theme={null}
interface ClobPosition {
  market: {
    slug: string;
    title: string;
  };
  positions: {
    yes: {
      size: number;
      collateral: number;
      unrealizedPnl: number;
    };
    no: {
      size: number;
      collateral: number;
      unrealizedPnl: number;
    };
  };
}
```

| Field           | Description                                                      |
| --------------- | ---------------------------------------------------------------- |
| `size`          | Number of shares held                                            |
| `collateral`    | USDC value of collateral locked                                  |
| `unrealizedPnl` | Unrealized profit/loss in USDC based on current orderbook prices |

## AMM Positions

Retrieve only your AMM market positions:

```typescript theme={null}
const ammPositions = await portfolio.getAMMPositions();

for (const position of ammPositions) {
  console.log(`Market: ${position.market.slug}`);
  console.log(`  YES — size: ${position.positions.yes.size}`);
  console.log(`  NO  — size: ${position.positions.no.size}`);
}
```

## Trade History

Fetch paginated trade history:

```typescript theme={null}
const history = await portfolio.getUserHistory();

for (const entry of history.data) {
  console.log(entry.type, entry.market.slug, entry.amount, entry.timestamp);
}

// Next page: pass the returned cursor
if (history.nextCursor) {
  const page2 = await portfolio.getUserHistory(history.nextCursor, 20);
}
```

### Parameters

| Parameter | Type     | Default | Description                                                                       |
| --------- | -------- | ------- | --------------------------------------------------------------------------------- |
| `cursor`  | `string` | —       | Opaque cursor from the previous response's `nextCursor`. Omit for the first page. |
| `limit`   | `number` | `20`    | Number of entries per page                                                        |

## Combining Positions with Market Data

For a richer view, combine position data with live market information:

```typescript theme={null}
import { MarketFetcher } from '@limitless-exchange/sdk';

const marketFetcher = new MarketFetcher(httpClient);
const positions = await portfolio.getCLOBPositions();

for (const position of positions) {
  const market = await marketFetcher.getMarket(position.market.slug);
  const orderbook = await marketFetcher.getOrderBook(position.market.slug);

  const bestBid = orderbook.bids[0]?.price ?? 0;
  const bestAsk = orderbook.asks[0]?.price ?? 1;
  const midPrice = (bestBid + bestAsk) / 2;

  console.log(`${market.title}`);
  console.log(`  Mid price: ${midPrice.toFixed(4)}`);
  console.log(`  YES: ${position.positions.yes.size} shares, PnL: ${position.positions.yes.unrealizedPnl}`);
  console.log(`  NO:  ${position.positions.no.size} shares, PnL: ${position.positions.no.unrealizedPnl}`);
}
```

<Tip>
  For real-time PnL tracking, combine `PortfolioFetcher` with WebSocket orderbook updates rather than repeatedly polling `getOrderBook()`. See the [WebSocket Streaming](/developers/sdk/typescript/websocket) guide.
</Tip>

## Error Handling

Portfolio endpoints require a valid API key. If the key is missing or invalid, the SDK throws an `APIError` with status `401`.

```typescript theme={null}
import { APIError } from '@limitless-exchange/sdk';

try {
  const positions = await portfolio.getPositions();
} catch (error) {
  if (error instanceof APIError) {
    if (error.status === 401) {
      console.error('Authentication failed. Check your LIMITLESS_API_KEY.');
    } else {
      console.error(`API error ${error.status}: ${error.message}`);
    }
  } else {
    throw error;
  }
}
```

See the [Error Handling and Retry](/developers/sdk/typescript/error-handling) guide for retry strategies and common error codes.
