# C# SDK

`FathomCharts` handles authentication, the initial snapshot, resuming after a disconnect, duplicates, history pagination, exports and rate-limit retries for you. This page describes every option and method; the behaviour the four SDKs share is in [SDKs](https://fathomcharts.com/docs/sdk.md).

## Install

```bash title="terminal"
dotnet add package FathomCharts
```

- **.NET 8 or later**, and **.NET Standard 2.0**: the package also runs in .NET Framework 4.8 hosts, such as the add-ons of trading platforms.
- Its dependencies are `System.Text.Json` and a managed zstd decompressor (`ZstdSharp.Port`); on .NET Standard 2.0, `Microsoft.Bcl.AsyncInterfaces` too. Nothing native to install.

### Indicator types

```bash title="terminal"
dnx FathomCharts.Types https://api.fathomcharts.com/v1/indicators FathomChartsTypes.cs
```

`dnx` comes with the .NET 10 SDK. Otherwise, install the tool once (`dotnet tool install -g FathomCharts.Types`) and run `FathomCharts.Types https://api.fathomcharts.com/v1/indicators FathomChartsTypes.cs`. It takes the catalog’s URL or a file saved from `GET /v1/indicators`.

The file holds, in the namespace `FathomCharts.Indicators`, one record per indicator for its parameters (`BigTradesParams`) and one for its data (`BigTradesData`), with the catalog’s descriptions as XML doc comments; strings with a fixed set of values become enums, and `IndicatorIds` lists the indicator ids (`IndicatorIds.BigTrades`). A tuple, such as a footprint level `[price, bid, ask, unknown?]`, is a `double[]` whose positions its doc comment gives. Generate the file again when the catalog changes.

## Real time: FathomChartsStream

```csharp title="Program.cs"
using FathomCharts;
using FathomCharts.Indicators;

await using var stream = new FathomChartsStream(new StreamOptions
{
    Url = "wss://stream.fathomcharts.com/v1",
    ApiKey = Environment.GetEnvironmentVariable("FATHOM_CHARTS_API_KEY"),
    OnStateChange = state => Console.WriteLine($"connection {state}"),
});

var bigTrades = stream.Subscribe<BigTradesData>(new SubscribeOptions
{
    Instrument = "NQ.front",
    Indicator = IndicatorIds.BigTrades,
    Params = new BigTradesParams { Minimum = 30 },
    Mode = Mode.Confirmed,
});

await foreach (var e in bigTrades)
{
    if (e is Upsert<BigTradesData> upsert) Console.WriteLine($"{upsert.Cursor} {upsert.Data.Side} {upsert.Data.Volume}");
}
```

### Options

`StreamOptions`, durations as `TimeSpan`:

| Option             | Purpose                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Url`              | Required. The stream address: `wss://stream.fathomcharts.com/v1`.                                                                                                                                                                                                                                                                                                                                                                            |
| `ApiKey`           | API key, sent in the `Authorization: Bearer` header.                                                                                                                                                                                                                                                                                                                                                                                         |
| `StreamToken`      | Instead of `ApiKey`, in an application distributed to end users, which must not hold the key: a function (`CancellationToken` → `Task<string>`) returning a fresh single-use token that your backend gets from `POST /v1/stream-tokens` (`FathomChartsRest.StreamTokenAsync()`). It is called on every connection, reconnections included. Give exactly one of `ApiKey` and `StreamToken`, otherwise the constructor throws `CONFIGURATION`. |
| `WebSocketFactory` | Optional: opens the sockets (by default, a `ClientWebSocket` with the `Authorization` header), to set a proxy for example. A socket it returns as `new StreamSocket(socket, canPause: false)` takes the `MaxBuffered` path below.                                                                                                                                                                                                            |
| `Reconnect`        | Optional: `new ReconnectOptions { InitialDelay, MaxDelay, QuotaRetry, QuotaDelay }`: first reconnection delay (250 ms), backoff ceiling (30 s), how long a `4029` close code is retried (120 s), minimum delay between two attempts after a `4029` (5 s).                                                                                                                                                                                    |
| `HeartbeatTimeout` | Silence after which the connection is considered lost, then reopened. 15 s by default: the server sends an `hb` every 5 seconds.                                                                                                                                                                                                                                                                                                             |
| `HighWaterMark`    | Number of events waiting to be read, all subscriptions together, above which the SDK stops reading the socket and keeps only the latest version of each object in progress. While it waits, it sends `ping` messages so that the server keeps the connection. 10,000 by default.                                                                                                                                                             |
| `MaxBuffered`      | For a socket that cannot be paused: number of waiting events above which the SDK closes the connection (close code `4000`, reason `client buffer full`), then reopens it from the last cursor received once half of `HighWaterMark` has been read. Nothing waiting is lost. 4 × `HighWaterMark` by default.                                                                                                                                  |
| `Random`           | Optional, for tests: the source of the reconnection jitter, in \[0, 1).                                                                                                                                                                                                                                                                                                                                                                      |
| `OnStateChange`    | Called on every change of `ConnectionState`.                                                                                                                                                                                                                                                                                                                                                                                                 |
| `OnNotice`         | Called with each `Notice` from the server (`Kind`, `Id`, `EffectiveAt`, `EndsAt`, `Message`): a restart, a maintenance window announced or cancelled. See [Updates and maintenance](https://fathomcharts.com/docs/maintenance.md).                                                                                                                                                                                                           |

`OnStateChange` and `OnNotice` run on the stream’s threads: keep them short. `await using` (or `DisposeAsync()`, `Close()`) closes the stream. `stream.ConnectionState` is `Idle`, `Connecting`, `Open`, `Reconnecting` or `Closed`; `stream.Maintenance` lists the maintenance windows announced on the connection and not over, by start.

### Subscribe()

`stream.Subscribe<T>(options)` opens a subscription and returns a `Subscription<T>`, to read with `await foreach`. `SubscribeOptions` holds the fields of the [`subscribe`](https://fathomcharts.com/docs/websocket.md#subscribing) message: `Instrument`, `Indicator`, `Params` (a generated `<Name>Params`, or any object serialized to JSON), `Mode` (`Mode.Live` by default) and `From` (`From.Live` by default, `From.Cursor(cursor, engine)` or `From.Time(time)`). The SDK picks the `sub` name itself. `T` is the indicator’s data type (`BigTradesData`…); without it, `Subscribe(options)` gives the data as `JsonElement`.

The events are records deriving from `StreamEvent`: `Subscribed`, `Snapshot<T>`, `Upsert<T>`, `Remove`, `Status`, `Reset` and `Notice`, to test with `is` or `switch`. Their fields are those of [Events](https://fathomcharts.com/docs/sdk.md#events), in Pascal case (`TickSizeNanos`, `LagMs`). An `error` on the subscription ends the loop: `await foreach` throws a `FathomChartsException` carrying the received `Code`.

### Subscription

| Member                      | Purpose                                                                                                                                                                         |
| --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Cursor`                    | The cursor of the last event handed to you: your resume point. `null` until a cursor has arrived. It also moves forward with `hb` messages when no event is waiting to be read. |
| `Topic`                     | The `topic` of the latest `Subscribed`.                                                                                                                                         |
| `Engine`                    | The `engine` of the latest `Subscribed`: the computation your state comes from. Save it with `Cursor` to resume later.                                                          |
| `Id`                        | The `sub` name the SDK chose for this subscription (`s1`, `s2`…).                                                                                                               |
| `Request`                   | The options of `Subscribe()`, completed with the default values.                                                                                                                |
| `Close()`, `DisposeAsync()` | Stops the subscription: the SDK sends `unsubscribe`, and a pending loop ends.                                                                                                   |

Leaving the loop (`break`, `return` or an exception in its body) closes the subscription. Reconnection, resuming and close codes: see [Connection lifecycle](https://fathomcharts.com/docs/sdk.md#connection-lifecycle); to resume after your process restarts, see [Resume after a restart](https://fathomcharts.com/docs/sdk.md#resume-after-a-restart).

## History: FathomChartsRest

```csharp
using var rest = new FathomChartsRest(new RestOptions
{
    BaseUrl = "https://api.fathomcharts.com",
    ApiKey = Environment.GetEnvironmentVariable("FATHOM_CHARTS_API_KEY"),
});
```

| Option             | Purpose                                                                                                                                                                                        |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `BaseUrl`          | Required. The API address: `https://api.fathomcharts.com`.                                                                                                                                     |
| `ApiKey`           | Required. API key, sent in the `Authorization: Bearer` header.                                                                                                                                 |
| `HttpClient`       | Optional: your own `HttpClient` (proxy, handler…).                                                                                                                                             |
| `RateLimitRetries` | Number of retries of a request the server did not process, or of a read that failed (see [Rate limit and retries](https://fathomcharts.com/docs/sdk.md#rate-limit-and-retries)). 3 by default. |

### Methods

Queries are records with the fields of the API, as on the [History](https://fathomcharts.com/docs/history.md#make-a-query) page: `PageQuery` (`Instrument`, `Indicator`, `Params`, `From`, `To`, `Mode`, `Limit`, `Cursor`, `UntilCursor`, `Snapshot`) and `RangeQuery` for exports. Every method takes a `CancellationToken`: cancelling a call, or the wait for a retry, throws `ABORTED`.

| Method                              | Returns                                                                                                                                                                                                                          |
| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PageAsync<T>(query)`               | One page: `Instrument`, `TickSizeNanos`, `Snapshot`, `Items`, `Next`, `ComputeUnits`.                                                                                                                                            |
| `PagesAsync<T>(query)`              | The pages one at a time, following `Next`, as you read them (`await foreach`).                                                                                                                                                   |
| `HistoryAsync<T>(query)`            | The results one at a time, across pages: `Mutation<T>` (`Type` is `Upsert` or `Remove`, each with its `Cursor`). With `Snapshot = true`, a `HistorySnapshot<T>`, the state at `From`, comes first.                               |
| `EstimateAsync(query)`              | The cost [estimate](https://fathomcharts.com/docs/history.md#estimate-the-cost), charging nothing.                                                                                                                               |
| `ExportAsync(query)`                | One [export](https://fathomcharts.com/docs/exports.md) response: the zstd-compressed file as is, its content type, file name and `Token` (resumes the export).                                                                   |
| `ExportNdjsonAsync(query, options)` | The decompressed export, in chunks (`ReadOnlyMemory<byte>`) of whole lines, with automatic resume. `ExportOptions`: `MaxResumes` (5), `ResumeDelay` (1 s). See [Exports](https://fathomcharts.com/docs/exports.md#with-the-sdk). |
| `StreamTokenAsync()`                | A stream token: `Token`, `ExpiresAt`.                                                                                                                                                                                            |
| `UsageAsync()`                      | Your [usage](https://fathomcharts.com/docs/limits.md#track-your-usage) this month and your limits.                                                                                                                               |
| `InstrumentsAsync()`                | Every [instrument](https://fathomcharts.com/docs.md#instruments) served.                                                                                                                                                         |
| `StatusAsync()`                     | The state of the computation, of each instrument, and the maintenance windows announced.                                                                                                                                         |
| `OffersAsync()`                     | The plans and the limits of each combination.                                                                                                                                                                                    |
| `IndicatorsAsync()`                 | The indicator catalog.                                                                                                                                                                                                           |

## Errors

Every error the SDK throws, or ends a loop with, is a `FathomChartsException`. Its codes are listed in [Errors](https://fathomcharts.com/docs/sdk.md#errors) (`ErrorCodes`; the WebSocket close codes, `CloseCode`). `CONFIGURATION` also covers an invalid `Url` or `BaseUrl`, and data that does not fit the type `T`.

| Property         | Content                                                                                                              |
| ---------------- | -------------------------------------------------------------------------------------------------------------------- |
| `Code`           | The stable error code.                                                                                               |
| `Message`        | A human-readable explanation.                                                                                        |
| `Status`         | The HTTP status, over REST.                                                                                          |
| `CloseCode`      | The WebSocket close code, when the connection was closed.                                                            |
| `RetryAfter`     | The value of the `Retry-After` header, when the response has one.                                                    |
| `Problem`        | The full `problem+json` document of the response, with `Errors` when the API lists invalid fields; `null` otherwise. |
| `InnerException` | The original error, when there is one (the cancellation, the error of `HttpClient`…).                                |

## Cursors

```csharp
Cursors.Compare("20720.111416.0", "20720.111417.0"); // < 0
```
