mirror of
https://github.com/JKorf/CryptoExchange.Net.git
synced 2026-10-04 02:11:11 +00:00
Updated to version 13.0.0
This commit is contained in:
@@ -1,40 +1,39 @@
|
||||
---
|
||||
name: cryptoexchange-net
|
||||
description: Use CryptoExchange.Net abstractions when generating C#/.NET code that needs to work across MULTIPLE cryptocurrency exchanges (Binance + Bybit + OKX + Kraken + Coinbase + ...) — for arbitrage, best-execution routing, multi-exchange portfolio dashboards, exchange-agnostic trading bots, or comparison tools. Triggers on requests mentioning multi-exchange, cross-exchange, arbitrage, exchange-agnostic, or unified crypto API in C#. Also triggers when the user is implementing a new exchange library following the CryptoExchange.Net pattern.
|
||||
description: Use CryptoExchange.Net Shared API V2 abstractions when generating C#/.NET code for multiple cryptocurrency exchanges, including arbitrage, routing, portfolio aggregation, exchange-agnostic bots, comparison tools, and new exchange-library implementations.
|
||||
---
|
||||
|
||||
# CryptoExchange.Net Skill
|
||||
|
||||
## When to use
|
||||
|
||||
CryptoExchange.Net is the **base library** powering 28+ exchange-specific libraries (Binance.Net, Bybit.Net, OKX.Net, Kraken.Net, Coinbase.Net, etc.). You don't install it directly — you install the exchange libraries, which depend on it.
|
||||
CryptoExchange.Net is the base library behind exchange-specific libraries such as Binance.Net, Bybit.Net, OKX.Net, Kraken.Net, and Coinbase.Net. Do not install it alone to call an exchange.
|
||||
|
||||
**Three usage modes:**
|
||||
Choose one of these approaches:
|
||||
|
||||
1. **You target ONE exchange** → use that exchange's library directly (e.g., Binance.Net), see its CLAUDE.md.
|
||||
2. **You target MULTIPLE exchanges** → install each library you need + use `CryptoExchange.Net.SharedApis` interfaces — write code once, runs against any exchange. **This is the main use case for this skill.**
|
||||
3. **You want ALL exchanges in one package** → install `CryptoClients.Net`, get `ExchangeRestClient` and `ExchangeSocketClient` with everything bundled.
|
||||
1. One exchange: install and use that exchange's library directly.
|
||||
2. Multiple exchanges: install the required exchange libraries and use `CryptoExchange.Net.SharedApis` V2 capabilities.
|
||||
3. All exchanges in one package: install `CryptoClients.Net` and use its combined clients and shared capability lookup.
|
||||
|
||||
For new cross-exchange code, use Shared API V2. V1 aggregate interfaces remain available through `.SharedClient` for incremental migration.
|
||||
|
||||
## Installation
|
||||
|
||||
For a multi-exchange project:
|
||||
|
||||
```bash
|
||||
dotnet add package Binance.Net
|
||||
dotnet add package JK.OKX.Net
|
||||
dotnet add package Bybit.Net
|
||||
# ... etc
|
||||
```
|
||||
|
||||
Or the bundle:
|
||||
Or install the bundle:
|
||||
|
||||
```bash
|
||||
dotnet add package CryptoClients.Net
|
||||
```
|
||||
|
||||
## Core Pattern: Shared Interfaces
|
||||
## Core pattern: fine-grained capabilities
|
||||
|
||||
Every exchange library exposes `.SharedClient` properties on its API surfaces. These implement the same interfaces from `CryptoExchange.Net.SharedApis`.
|
||||
Each exchange API surface exposes a typed `.SharedApi` aggregate. Assign it to the capability for the single operation being used:
|
||||
|
||||
```csharp
|
||||
using Binance.Net.Clients;
|
||||
@@ -42,155 +41,187 @@ using OKX.Net.Clients;
|
||||
using Bybit.Net.Clients;
|
||||
using CryptoExchange.Net.SharedApis;
|
||||
|
||||
// All three implement ISpotTickerRestClient
|
||||
ISpotTickerRestClient binance = new BinanceRestClient().SpotApi.SharedClient;
|
||||
ISpotTickerRestClient okx = new OKXRestClient().UnifiedApi.SharedClient;
|
||||
ISpotTickerRestClient bybit = new BybitRestClient().V5Api.SharedClient;
|
||||
IGetTickerRest binance = new BinanceRestClient().SpotApi.SharedApi;
|
||||
IGetTickerRest okx = new OKXRestClient().UnifiedApi.SharedApi;
|
||||
IGetTickerRest bybit = new BybitRestClient().V5Api.SharedApi;
|
||||
|
||||
// Single agnostic call — works against any of them
|
||||
var symbol = new SharedSymbol(TradingMode.Spot, "BTC", "USDT");
|
||||
var ticker = await binance.GetSpotTickerAsync(new GetTickerRequest(symbol));
|
||||
// ticker.Data.LastPrice, ticker.Data.HighPrice, etc. — same model regardless of exchange
|
||||
```
|
||||
var result = await binance.GetTickerAsync(new GetTickerRequest(symbol));
|
||||
|
||||
## Core Pattern: SharedSymbol
|
||||
|
||||
Different exchanges format symbols differently — Binance uses `BTCUSDT`, OKX uses `BTC-USDT`, others may have other formats. `SharedSymbol` normalizes this:
|
||||
|
||||
```csharp
|
||||
var btcusdt = new SharedSymbol(TradingMode.Spot, "BTC", "USDT");
|
||||
// Each exchange library translates SharedSymbol → its native format internally.
|
||||
|
||||
// For futures:
|
||||
var btcusdtPerp = new SharedSymbol(TradingMode.PerpetualLinear, "BTC", "USDT");
|
||||
```
|
||||
|
||||
For exchanges that use exotic asset names, see the AssetAliases configuration.
|
||||
|
||||
## Symbol Metadata and Asset Classification
|
||||
|
||||
Since CryptoExchange.Net 12.2.0, shared symbol responses describe both sides of a market with `BaseAssetType`, `BaseAssetSubType`, `QuoteAssetType`, and `QuoteAssetSubType`. `SharedAssetType` distinguishes `Crypto`, `Fiat`, and `TradFi`; `SharedAssetSubType` distinguishes `StableCoin`, `Equity`, and `Commodity`. `SharedSpotSymbol` and `SharedFuturesSymbol` also expose `DisplayName`.
|
||||
|
||||
The same fields on `GetSymbolsRequest` filter spot or futures symbol discovery:
|
||||
|
||||
```csharp
|
||||
var request = new GetSymbolsRequest(
|
||||
baseAssetType: SharedAssetType.Crypto,
|
||||
quoteAssetSubType: SharedAssetSubType.StableCoin);
|
||||
|
||||
var result = await symbolClient.GetSpotSymbolsAsync(request);
|
||||
```
|
||||
|
||||
After calling `GetSpotSymbolsAsync` or `GetFuturesSymbolsAsync`, use the client's `SpotSymbolCatalog` or `FuturesSymbolCatalog` to look up normalized asset and symbol metadata by name. The catalog is unavailable until the corresponding symbol request has populated the cache.
|
||||
|
||||
For exchange-library implementations, `LibraryHelpers.IsStableCoin`, `IsCommodity`, and `IsEquity` provide best-effort classification of known assets and accept exchange-specific additions. These helpers are heuristics, not an exhaustive source of truth.
|
||||
|
||||
## Shared Market-Data Quantities
|
||||
|
||||
Since CryptoExchange.Net 12.4.0, shared market-data models use `SharedOrderQuantity` so base-asset, quote-asset, and contract quantities remain explicit. Read `SharedSpotTicker.Volumes`, `SharedFuturesTicker.Volumes`, and `SharedKline.Volumes`; read `SharedTrade.Quantities`. The former scalar `Volume`, `QuoteVolume`, and `Quantity` members are obsolete.
|
||||
|
||||
## WebSocket Order Management
|
||||
|
||||
Since CryptoExchange.Net 12.5.0, exchanges can implement `ISpotOrderManagementSocketClient` and `IFuturesOrderManagementSocketClient` to place and cancel orders over WebSocket. These are command interfaces, not subscription interfaces: `Place*OrderAsync` and `Cancel*OrderAsync` return `QueryResult<SharedId>`. Check exchange support before using them.
|
||||
|
||||
## Available Shared Interfaces
|
||||
|
||||
**REST:**
|
||||
|
||||
- Market data: `ISpotTickerRestClient`, `IBookTickerRestClient`, `ISpotSymbolRestClient`, `IFuturesSymbolRestClient`, `IOrderBookRestClient`, `IRecentTradeRestClient`, `IKlineRestClient`
|
||||
- Orders: `ISpotOrderRestClient`, `IFuturesOrderRestClient`, `ISpotOrderClientIdRestClient`, `IFuturesOrderClientIdRestClient`, `ISpotTriggerOrderRestClient`, `IFuturesTriggerOrderRestClient`, `IFuturesTpSlRestClient`
|
||||
- Account: `IBalanceRestClient`, `IPositionRestClient`, `IFeeRestClient`, `ITransferRestClient`, `IDepositRestClient`, `IWithdrawalRestClient`
|
||||
|
||||
**WebSocket:**
|
||||
|
||||
- `ITickerSocketClient`, `IBookTickerSocketClient`
|
||||
- `IOrderBookSocketClient`, `ITradeSocketClient`, `IKlineSocketClient`
|
||||
- `IUserTradeSocketClient`, `ISpotOrderSocketClient`, `IFuturesOrderSocketClient`, `IPositionSocketClient`, `IBalanceSocketClient`
|
||||
- Order commands: `ISpotOrderManagementSocketClient`, `IFuturesOrderManagementSocketClient`
|
||||
|
||||
Each exchange documents which interfaces it implements (some exchanges don't support every operation).
|
||||
|
||||
## Core Pattern: Result Handling
|
||||
|
||||
Same as exchange-specific libraries: REST calls return `HttpResult<T>` and websocket subscription calls return `WebSocketResult<UpdateSubscription>`, both with `.Success`, `.Data`, and `.Error`. Always check `.Success` first.
|
||||
|
||||
```csharp
|
||||
var result = await sharedClient.GetSpotTickerAsync(new GetTickerRequest(symbol));
|
||||
if (!result.Success)
|
||||
{
|
||||
Console.WriteLine($"[{sharedClient.Exchange}] Error: {result.Error}");
|
||||
return;
|
||||
}
|
||||
Console.WriteLine($"[{sharedClient.Exchange}] {result.Data.LastPrice}");
|
||||
Console.WriteLine($"[{result.Exchange}] {result.Error}");
|
||||
else
|
||||
Console.WriteLine($"[{result.Exchange}] {result.Data!.LastPrice}");
|
||||
```
|
||||
|
||||
`.Exchange` property on every shared client tells you which exchange you're talking to — useful for logging.
|
||||
V2 interfaces describe operations, not broad feature groups. Examples include `IGetTickerRest`, `IGetOrderBookRest`, `IPlaceSpotOrderRest`, `ICancelFuturesOrderRest`, and `ISubscribeTradesSocket`. An exchange may implement one operation without implementing adjacent operations.
|
||||
|
||||
## Core Pattern: Multi-Exchange Aggregation
|
||||
## Shared symbols
|
||||
|
||||
Use `SharedSymbol`; never pass exchange-native symbol strings to shared requests:
|
||||
|
||||
```csharp
|
||||
var clients = new ISpotTickerRestClient[]
|
||||
{
|
||||
new BinanceRestClient().SpotApi.SharedClient,
|
||||
new OKXRestClient().UnifiedApi.SharedClient,
|
||||
new BybitRestClient().V5Api.SharedClient,
|
||||
};
|
||||
var spot = new SharedSymbol(TradingMode.Spot, "BTC", "USDT");
|
||||
var linearPerpetual = new SharedSymbol(
|
||||
TradingMode.PerpetualLinear,
|
||||
"BTC",
|
||||
"USDT");
|
||||
```
|
||||
|
||||
Each exchange library converts the shared symbol to its native format. For unusual exchange asset names, configure asset aliases.
|
||||
|
||||
## Known surface versus runtime selection
|
||||
|
||||
Use the typed `.SharedApi` surface when the exchange and API are known. This is the simplest and most discoverable approach:
|
||||
|
||||
```csharp
|
||||
IPlaceSpotOrderRest orders = restClient.SpotApi.SharedApi;
|
||||
```
|
||||
|
||||
For runtime selection, inject the exchange-wide `I[Exchange]SharedApiClient` registered by `services.Add[Exchange](...)`. Resolve a capability with the strongly typed `SharedCapabilities` catalog:
|
||||
|
||||
```csharp
|
||||
var match = sharedClient.GetCapability(
|
||||
SharedCapabilities.Orders.Futures.PlaceOrder.Rest,
|
||||
TradingMode.PerpetualLinear);
|
||||
|
||||
if (match is null)
|
||||
return; // This exchange/API/mode does not provide the operation.
|
||||
|
||||
var result = await match.Capability.PlaceFuturesOrderAsync(request);
|
||||
```
|
||||
|
||||
`GetCapability` returns one `SharedCapabilityResolution<T>` containing `Capability` and `Options`, or `null` if no supported implementation matches. `GetCapabilities` returns every match on that exchange-wide client. Always specify `TradingMode` when multiple spot, linear, inverse, or delivery surfaces could match.
|
||||
|
||||
`SharedCapabilities` references identify interface types; they do not guarantee that an exchange implements the operation and do not send a request.
|
||||
|
||||
## Transport selection and result types
|
||||
|
||||
Some commands have three interfaces:
|
||||
|
||||
- Transport-agnostic, such as `IPlaceSpotOrder`, returns `IExchangeCallResult<T>`.
|
||||
- REST-specific, such as `IPlaceSpotOrderRest`, returns `HttpResult<T>`.
|
||||
- socket-specific, such as `IPlaceSpotOrderSocket`, returns `QueryResult<T>`.
|
||||
|
||||
Socket subscription capabilities such as `ISubscribeTickerSocket` return `WebSocketResult<UpdateSubscription>`.
|
||||
|
||||
Use `.Rest` or `.Socket` on a capability reference when transport matters. Without a transport filter, exchange-wide lookup uses `PreferredTransport`, configured through the exchange's `SharedApi.PreferredTransport` option and normally defaulting to REST.
|
||||
|
||||
Always check `.Success` before `.Data`. Use `.Error` for failures and the result or capability `.Exchange` value for multi-exchange logging.
|
||||
|
||||
## Inspect parameter support
|
||||
|
||||
The presence of a capability does not mean every shared request property is accepted by every exchange. Inspect its `CapabilityOptions`:
|
||||
|
||||
- `RequestParameterRules`: whether each shared request field is `Required`, `Optional`, or `NotSupported`.
|
||||
- `ExchangeParameterRules`: required or optional exchange-specific values supplied through the request's `ExchangeParameters`.
|
||||
- `SupportedTradingModes`: the trading modes supported by this implementation.
|
||||
|
||||
```csharp
|
||||
var match = sharedClient.GetCapability(
|
||||
SharedCapabilities.Orders.Futures.PlaceOrder.Rest,
|
||||
TradingMode.PerpetualLinear);
|
||||
|
||||
var leverageRule = match?.Options.RequestParameterRules
|
||||
.FirstOrDefault(x => x.Name == nameof(PlaceFuturesOrderRequest.Leverage));
|
||||
```
|
||||
|
||||
Do not infer support from the request model alone. Handle a `null` resolution and exchange-specific parameter rules before issuing dynamic trading calls.
|
||||
|
||||
## Common capabilities
|
||||
|
||||
- Market data: `IGetTickerRest`, `IGetAllTickersRest`, `IGetOrderBookRest`, `IGetKlinesRest`, `IGetRecentTradesRest`; ticker, trade, kline, and order-book socket subscriptions.
|
||||
- Trading: fine-grained spot and futures place, edit, cancel, get, open-order, closed-order, and order-update capabilities.
|
||||
- Account: balances, positions, user trades, fees, deposits, withdrawals, and transfers.
|
||||
- Futures data: funding, open interest, leverage, mark price, and index price capabilities.
|
||||
|
||||
Check the typed exchange Shared API surface or use capability lookup instead of assuming universal support.
|
||||
|
||||
## Multi-exchange aggregation
|
||||
|
||||
Run independent exchange requests concurrently:
|
||||
|
||||
```csharp
|
||||
var clients = new IGetTickerRest[] { binance, okx, bybit };
|
||||
var symbol = new SharedSymbol(TradingMode.Spot, "BTC", "USDT");
|
||||
|
||||
// Fetch concurrently from all exchanges
|
||||
var tasks = clients.Select(c => c.GetSpotTickerAsync(new GetTickerRequest(symbol))).ToArray();
|
||||
var tasks = clients.Select(client =>
|
||||
client.GetTickerAsync(new GetTickerRequest(symbol)));
|
||||
var results = await Task.WhenAll(tasks);
|
||||
|
||||
for (int i = 0; i < clients.Length; i++)
|
||||
foreach (var result in results.Where(x => x.Success))
|
||||
Console.WriteLine($"{result.Exchange}: {result.Data!.LastPrice}");
|
||||
```
|
||||
|
||||
Reuse clients through dependency injection; do not instantiate them per request.
|
||||
|
||||
## Dependency injection
|
||||
|
||||
Each exchange library provides `services.Add[Exchange](...)`. Registration includes its native clients, V1 shared interfaces, V2 operation capabilities, and exchange-wide shared client.
|
||||
|
||||
Inject a capability directly only when the container has one intended implementation:
|
||||
|
||||
```csharp
|
||||
public sealed class TickerService(IGetTickerRest ticker)
|
||||
{
|
||||
if (results[i].Success)
|
||||
Console.WriteLine($"{clients[i].Exchange}: {results[i].Data!.LastPrice}");
|
||||
public Task<HttpResult<SharedTicker>> GetAsync(
|
||||
SharedSymbol symbol,
|
||||
CancellationToken ct = default)
|
||||
=> ticker.GetTickerAsync(new GetTickerRequest(symbol), ct);
|
||||
}
|
||||
```
|
||||
|
||||
## Per-Exchange Setup
|
||||
If multiple exchanges or multiple API surfaces register the same capability, inject the exchange-specific shared client and select its typed API property or call `GetCapability`. Plain single-service resolution does not express which implementation you want.
|
||||
|
||||
Each exchange library has its own credentials class and options. See each library's CLAUDE.md for specifics. The pattern is consistent: `XxxRestClient(options => { options.ApiCredentials = new XxxCredentials(...); })`.
|
||||
For the bundle, use `services.AddCryptoClients(...)`. CryptoClients.Net provides `IExchangeSharedApiClient` for capability lookup across exchanges.
|
||||
|
||||
## Dependency Injection
|
||||
## V1 migration
|
||||
|
||||
Each exchange library has its own `services.AddXxx(...)` extension. They all share the same option-builder pattern. Register only the ones you use:
|
||||
V1 `.SharedClient` facades and broad interfaces such as `ISpotTickerRestClient` remain available. Migrate one operation at a time:
|
||||
|
||||
```csharp
|
||||
services.AddBinance(restOpts => { /*...*/ }, socketOpts => { /*...*/ });
|
||||
services.AddOKX(restOpts => { /*...*/ }, socketOpts => { /*...*/ });
|
||||
// Inject IBinanceRestClient, IOKXRestClient, etc.
|
||||
// V1
|
||||
await restClient.SpotApi.SharedClient.GetSpotTickerAsync(request);
|
||||
|
||||
// V2
|
||||
await restClient.SpotApi.SharedApi.GetTickerAsync(request);
|
||||
```
|
||||
|
||||
For one-package access: `services.AddCryptoClients(...)` from `CryptoClients.Net`.
|
||||
Important semantic changes:
|
||||
|
||||
## Common Pitfalls — AVOID
|
||||
- V2 ticker methods are `GetTickerAsync` and `GetAllTickersAsync` and return `SharedTicker` for both spot and futures.
|
||||
- WebSocket order updates use `SharedSpotOrderUpdate` and `SharedFuturesOrderUpdate`; REST order retrieval keeps the ordinary order models.
|
||||
- `ICloseFullPosition` closes the complete position. Use an order capability for partial closes where supported.
|
||||
- Transport-agnostic operations return `IExchangeCallResult<T>`; select the REST or socket interface when code needs a transport-specific result.
|
||||
|
||||
- **Do NOT install `CryptoExchange.Net` and try to call exchange APIs directly** — it's a base abstraction; you need an exchange library.
|
||||
- **Do NOT try to use one exchange's models with another's client** — use the SharedApis types (`SharedSymbol`, `SharedSpotTicker`, `SharedSpotOrder`, etc.) for cross-exchange code.
|
||||
- **Do NOT block on async operations** — use `await` throughout. `Task.WhenAll` for parallelism across exchanges.
|
||||
- **Do NOT assume every exchange supports every operation** — check exchange docs or the library's implementation. Operations may return errors like "not supported on this exchange".
|
||||
- **Do NOT instantiate clients per-request** — reuse via DI.
|
||||
- **Do NOT iterate exchanges sequentially when concurrency is fine** — use `Task.WhenAll` for ~Nx speedup.
|
||||
See `docs/SHARED_API_V2_MIGRATION.md` for detailed mappings.
|
||||
|
||||
## Implementing a New Exchange Library
|
||||
## Common pitfalls
|
||||
|
||||
If you're building a NEW exchange wrapper following the CryptoExchange.Net pattern (rare but valuable):
|
||||
- Do not install `CryptoExchange.Net` alone and expect exchange endpoints.
|
||||
- Do not use `.SharedClient` for new V2 code; use `.SharedApi` and fine-grained capabilities.
|
||||
- Do not mix exchange-native request or response models into cross-exchange services.
|
||||
- Do not assume capability presence or request-parameter support; resolve and inspect it.
|
||||
- Do not rely on preferred transport when REST or socket semantics matter.
|
||||
- Do not block with `.Result` or `.Wait()`; use async calls throughout.
|
||||
- Do not query exchanges sequentially when requests are independent.
|
||||
|
||||
- Inherit from `RestApiClient` and `SocketApiClient` base classes
|
||||
- Define your own `XxxCredentials` extending `ApiCredentials` (or use `ApiCredentials` directly)
|
||||
- Implement `AuthenticationProvider` for the exchange's signing scheme
|
||||
- Implement the relevant `Shared*` interfaces on your API client classes for cross-exchange support
|
||||
- Follow the same `XxxRestOptions` / `XxxSocketOptions` pattern
|
||||
## Implementing a new exchange library
|
||||
|
||||
See existing libraries (Binance.Net, Bybit.Net) as reference implementations.
|
||||
- Derive API clients from `RestApiClient` and `SocketApiClient`.
|
||||
- Follow the exchange credentials and options patterns used by existing libraries.
|
||||
- Implement the relevant fine-grained V2 capability interfaces on typed Shared API classes.
|
||||
- Publish accurate `CapabilityOptions`, including supported trading modes and request/exchange parameter rules.
|
||||
- Register REST/socket Shared APIs and the exchange-wide shared client with the library's DI extension.
|
||||
- Retain V1 facades only where compatibility with existing consumers is required.
|
||||
|
||||
Use maintained exchange libraries such as Binance.Net and Bybit.Net as implementation references.
|
||||
|
||||
## Reference
|
||||
|
||||
- Source: https://github.com/JKorf/CryptoExchange.Net
|
||||
- Documentation: https://cryptoexchange.jkorf.dev/
|
||||
- SharedApis docs: https://cryptoexchange.jkorf.dev/CryptoExchange.Net/idocs_shared.html
|
||||
- Bundle (all exchanges): https://github.com/JKorf/CryptoClients.Net
|
||||
- Shared API migration: https://github.com/JKorf/CryptoExchange.Net/blob/master/docs/SHARED_API_V2_MIGRATION.md
|
||||
- Bundle: https://github.com/JKorf/CryptoClients.Net
|
||||
- Demo app: https://github.com/JKorf/CryptoManager.Net
|
||||
- Discord: https://discord.gg/MSpeEtSY8t
|
||||
|
||||
Reference in New Issue
Block a user