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

# PNL & History

> Track profit/loss and view transaction history

## Overview

The SDK provides methods to track user financial activity:

* `getUserPnl` - Get profit/loss summary with optional time-series
* `getUserHistory` - Get unified transaction history (fills, settlements, deposits, withdrawals)

<Info>
  To avoid ambiguity, we denote the smallest possible multiple of USDC (0.000001 USDC) as one `uusdc`,
  which stands for µUSDC (micro-USDC), and denote the smallest possible multiple of a contract (0.01 contract)
  as one `ccontract` (centicontract).

  User-facing USDC balances are specified as fixed-point strings (e.g. `"1.2625"` for USDC). Contract quantities
  in the API and SDK are specified as integer `ccontracts` strings (e.g. `"1050"` for 10.50 contracts at precision 2).
</Info>

## Getting PNL

### `getUserPnl`

Get a comprehensive PNL summary for a user.

```typescript theme={null}
async getUserPnl(
  userId: string,
  params?: GetUserPnlParams
): Promise<GetUserPnlResponse>
```

#### Parameters

<ParamField path="userId" type="string" required>
  User's Ethereum address
</ParamField>

<ParamField path="params" type="object">
  Optional filtering parameters
</ParamField>

<Expandable title="params properties">
  <ParamField path="marketId" type="string">
    Filter to a specific market
  </ParamField>

  <ParamField path="startTime" type="number">
    Start timestamp (milliseconds)
  </ParamField>

  <ParamField path="endTime" type="number">
    End timestamp (milliseconds)
  </ParamField>

  <ParamField path="granularity" type="string">
    Time-series granularity: `"hour"`, `"day"`, or `"all"` (default, no time series)
  </ParamField>
</Expandable>

#### Response

```typescript theme={null}
{
  totalDeposits: string;      // Total deposits in µUSDC
  totalWithdrawals: string;   // Total withdrawals in µUSDC
  realizedPnl: string;        // Realized PNL in µUSDC
  unrealizedPnl: string;      // Unrealized PNL in µUSDC
  netPnl: string;             // Net PNL (realized + unrealized)
  totalFeesPaid: string;      // Total fees paid in µUSDC
  timeSeries?: {              // Only if granularity is hour/day
    timestamp: number;
    cumulativePnl: string;
  }[];
}
```

#### Examples

**Basic PNL summary:**

```typescript theme={null}
import { createBisonClient, uusdcToUsdc } from '@bison-markets/sdk-ts';

const client = createBisonClient({ 
  baseUrl: 'https://api.bison.markets' 
});

const pnl = await client.getUserPnl(
  '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'
);

// Display in dollars
console.log(`Net P&L: $${uusdcToUsdc(pnl.netPnl)}`);
console.log(`Realized: $${uusdcToUsdc(pnl.realizedPnl)}`);
console.log(`Unrealized: $${uusdcToUsdc(pnl.unrealizedPnl)}`);
console.log(`Fees Paid: $${uusdcToUsdc(pnl.totalFeesPaid)}`);
```

**PNL with daily time series (for charts):**

```typescript theme={null}
const pnl = await client.getUserPnl(
  '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
  { granularity: 'day' }
);

// Build chart data
const chartData = pnl.timeSeries?.map(point => ({
  date: new Date(point.timestamp),
  pnl: Number(point.cumulativePnl) / 1_000_000 // Convert to dollars
})) ?? [];
```

**PNL for a specific market:**

```typescript theme={null}
const marketPnl = await client.getUserPnl(
  '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
  { marketId: 'KXFEDDECISION-26JAN-T425' }
);

console.log(`Market P&L: $${uusdcToUsdc(marketPnl.realizedPnl)}`);
```

**PNL for a date range:**

```typescript theme={null}
const oneWeekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;

const weeklyPnl = await client.getUserPnl(
  '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
  { 
    startTime: oneWeekAgo,
    granularity: 'hour'
  }
);
```

## Getting Transaction History

### `getUserHistory`

Get a chronological list of all financial transactions.

```typescript theme={null}
async getUserHistory(
  userId: string,
  params?: GetUserHistoryParams
): Promise<GetUserHistoryResponse>
```

#### Parameters

<ParamField path="userId" type="string" required>
  User's Ethereum address
</ParamField>

<ParamField path="params" type="object">
  Optional filtering and pagination
</ParamField>

<Expandable title="params properties">
  <ParamField path="type" type="string">
    Filter by type: `"fill"`, `"settlement"`, `"deposit"`, or `"withdraw"`
  </ParamField>

  <ParamField path="marketId" type="string">
    Filter by market ID (only for fills and settlements)
  </ParamField>

  <ParamField path="startTime" type="number">
    Start timestamp (milliseconds)
  </ParamField>

  <ParamField path="endTime" type="number">
    End timestamp (milliseconds)
  </ParamField>

  <ParamField path="limit" type="number">
    Max records per page (default: 50, max: 200)
  </ParamField>

  <ParamField path="cursor" type="string">
    Pagination cursor from previous response
  </ParamField>
</Expandable>

#### Response

Returns an array of transaction records, each with a `type` discriminator:

```typescript theme={null}
{
  records: (FillRecord | SettlementRecord | DepositRecord | WithdrawRecord)[];
  pagination: {
    hasMore: boolean;
    nextCursor?: string;
  };
}
```

#### Examples

**Get all recent activity:**

```typescript theme={null}
const { records } = await client.getUserHistory(
  '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266'
);

records.forEach(record => {
  const date = new Date(record.timestamp).toLocaleDateString();
  
  switch (record.type) {
    case 'fill':
      console.log(
        `${date}: ${record.action} ${Number(record.ccontracts) / 100} ${record.side} @ $${Number(record.priceUusdc) / 1_000_000}`
      );
      break;
    case 'settlement':
      const won = record.payoutUusdc !== '0';
      console.log(`${date}: Settlement ${won ? 'WON' : 'LOST'} - $${Number(record.payoutUusdc) / 1_000_000}`);
      break;
    case 'deposit':
      console.log(`${date}: Deposited $${Number(record.amountUusdc) / 1_000_000}`);
      break;
    case 'withdraw':
      console.log(`${date}: Withdrew $${Number(record.amountUusdc) / 1_000_000} (${record.status})`);
      break;
  }
});
```

**Get only fills for a market:**

```typescript theme={null}
const { records } = await client.getUserHistory(
  '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
  { 
    type: 'fill',
    marketId: 'KXFEDDECISION-26JAN-T425'
  }
);
```

**Paginate through all history:**

```typescript theme={null}
let cursor: string | undefined;
const allRecords = [];

do {
  const result = await client.getUserHistory(
    '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
    { limit: 100, cursor }
  );
  
  allRecords.push(...result.records);
  cursor = result.pagination.nextCursor;
} while (cursor);

console.log(`Total transactions: ${allRecords.length}`);
```

## Error Handling

```typescript theme={null}
try {
  const pnl = await client.getUserPnl('0x...');
  console.log('Net PNL:', pnl.netPnl);
} catch (error) {
  if (error instanceof Error) {
    console.error('Failed to get PNL:', error.message);
  }
}
```

## Important Notes

* All monetary values are in µUSDC (1 USD = 1,000,000 µUSDC)
* When filtering by `marketId`, deposits and withdrawals are excluded from PNL calculations
* Transaction history is sorted newest-first by default
* Unrealized PNL is estimated based on position cost basis
* Time series data points represent cumulative PNL at each interval
