> ## 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 Go SDK

## Overview

The `PortfolioFetcher` retrieves your profile, open positions, and trading history from the Limitless Exchange API. It requires an authenticated `HttpClient`.

## Setup

```go theme={null}
import limitless "github.com/limitless-labs-group/limitless-exchange-go-sdk/limitless"

client := limitless.NewHttpClient() // loads LIMITLESS_API_KEY from env
portfolio := limitless.NewPortfolioFetcher(client)
```

<Note>
  `PortfolioFetcher` requires an authenticated client. Configure `LIMITLESS_API_KEY`, use `WithAPIKey`, or use `WithHMACCredentials` for partner/backend flows.
</Note>

## Current Profile

Use `GetCurrentProfile()` to fetch the authenticated caller's private profile via `GET /profiles/me`. This is the preferred helper when the client is already authenticated and you do not want to pass a wallet address.

```go theme={null}
ctx := context.Background()
profile, err := portfolio.GetCurrentProfile(ctx)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Profile ID: %d\n", profile.ID)
fmt.Printf("Account: %s\n", profile.Account)
if profile.Rank != nil {
    fmt.Printf("Fee rate: %d bps\n", profile.Rank.FeeRateBps)
}
```

## Fetching a Profile by Address

Use `GetProfile()` to retrieve a user profile by wallet address:

```go theme={null}
profile, err := portfolio.GetProfile(ctx, "0xYOUR_WALLET_ADDRESS")
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Username: %s\n", profile.Username)
fmt.Printf("Display name: %s\n", profile.DisplayName)
if profile.Rank != nil {
    fmt.Printf("Rank: %s (fee rate: %d bps)\n", profile.Rank.Name, profile.Rank.FeeRateBps)
}
```

### UserProfile Fields

| Field         | Type        | Description                       |
| ------------- | ----------- | --------------------------------- |
| `ID`          | `int`       | User ID                           |
| `Account`     | `string`    | Wallet address                    |
| `Username`    | `*string`   | Username (nil if unset)           |
| `DisplayName` | `*string`   | Display name (nil if unset)       |
| `Rank`        | `*UserRank` | User rank with fee rate           |
| `Points`      | `*float64`  | Accumulated points (nil if unset) |

## Fetching All Positions

Use `GetPositions()` to retrieve all your open positions:

```go theme={null}
positions, err := portfolio.GetPositions(ctx)
if err != nil {
    log.Fatal(err)
}

fmt.Printf("CLOB positions: %d\n", len(positions.CLOB))
fmt.Printf("AMM positions: %d\n", len(positions.AMM))
```

The response is a `PortfolioPositionsResponse` with the following fields:

| Field     | Type                | Description                                       |
| --------- | ------------------- | ------------------------------------------------- |
| `CLOB`    | `[]CLOBPosition`    | Positions on CLOB (order book) markets            |
| `AMM`     | `[]AMMPosition`     | Positions on AMM (automated market maker) markets |
| `Points`  | `*string`           | Accumulated points (nil if unset)                 |
| `Rewards` | `*PortfolioRewards` | Accumulated rewards (nil if unset)                |

## CLOB Positions

Use `GetCLOBPositions()` for CLOB-only positions, or iterate over `positions.CLOB`:

```go theme={null}
clobPositions, err := portfolio.GetCLOBPositions(ctx)
if err != nil {
    log.Fatal(err)
}

for _, pos := range clobPositions {
    fmt.Printf("%s — yes: %s, no: %s\n", pos.Market.Title, pos.TokensBalance.Yes, pos.TokensBalance.No)
}
```

### CLOBPosition Fields

| Field           | Type                  | Description                         |
| --------------- | --------------------- | ----------------------------------- |
| `Market`        | `PositionMarket`      | Market title, slug, and metadata    |
| `MakerAddress`  | `string`              | Your wallet address                 |
| `Positions`     | `CLOBPositionSides`   | Position details per side           |
| `TokensBalance` | `TokenBalance`        | Current token balance (per-outcome) |
| `LatestTrade`   | `LatestTrade`         | Most recent trade on this position  |
| `Orders`        | `*CLOBPositionOrders` | Open orders (nil if none)           |

## AMM Positions

Use `GetAMMPositions()` for AMM-only positions:

```go theme={null}
ammPositions, err := portfolio.GetAMMPositions(ctx)
if err != nil {
    log.Fatal(err)
}

for _, pos := range ammPositions {
    fmt.Printf("%s — outcome: %d, unrealized PnL: %s\n",
        pos.Market.Title, pos.OutcomeIndex, pos.UnrealizedPnl)
}
```

### AMMPosition Fields

| Field                | Type             | Description                      |
| -------------------- | ---------------- | -------------------------------- |
| `Market`             | `PositionMarket` | Market title, slug, and metadata |
| `Account`            | `string`         | Your wallet address              |
| `OutcomeIndex`       | `int`            | Outcome index                    |
| `CollateralAmount`   | `string`         | Collateral deposited             |
| `OutcomeTokenAmount` | `string`         | Outcome tokens held              |
| `AverageFillPrice`   | `string`         | Average entry price              |
| `RealizedPnl`        | `string`         | Realized profit and loss         |
| `UnrealizedPnl`      | `string`         | Unrealized profit and loss       |

## Trading History

Use `GetUserHistory()` to retrieve cursor-paginated trading history. The signature is `GetUserHistory(ctx, cursor string, limit int)` — pass an empty cursor for the first page, then `*history.NextCursor` for subsequent pages:

```go theme={null}
history, err := portfolio.GetUserHistory(ctx, "", 20) // first page, 20 items
if err != nil {
    log.Fatal(err)
}

fmt.Printf("Fetched %d trades\n", len(history.Data))
for _, entry := range history.Data {
    fmt.Printf("%+v\n", entry)
}

// Next page, if any
if history.NextCursor != nil {
    next, err := portfolio.GetUserHistory(ctx, *history.NextCursor, 20)
    if err != nil {
        log.Fatal(err)
    }
    _ = next
}
```

## Complete Example

```go theme={null}
package main

import (
    "context"
    "fmt"
    "log"

    limitless "github.com/limitless-labs-group/limitless-exchange-go-sdk/limitless"
)

func main() {
    client := limitless.NewHttpClient()
    portfolio := limitless.NewPortfolioFetcher(client)
    ctx := context.Background()

    // Fetch all positions
    positions, err := portfolio.GetPositions(ctx)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Printf("CLOB positions: %d\n", len(positions.CLOB))
    for _, pos := range positions.CLOB {
        fmt.Printf("  %s — yes: %s, no: %s\n", pos.Market.Title, pos.TokensBalance.Yes, pos.TokensBalance.No)
    }

    fmt.Printf("\nAMM positions: %d\n", len(positions.AMM))
    for _, pos := range positions.AMM {
        fmt.Printf("  %s — unrealized PnL: %s\n", pos.Market.Title, pos.UnrealizedPnl)
    }

    // Fetch trading history (cursor-based; empty cursor = first page)
    history, err := portfolio.GetUserHistory(ctx, "", 10)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("\nRecent trades: %d\n", len(history.Data))
}
```
