1
0
mirror of https://github.com/JKorf/CryptoExchange.Net.git synced 2026-10-04 10:21:13 +00:00
Files
CryptoExchange.Net/AGENTS.md
T
2026-09-23 10:07:50 +02:00

10 KiB

name, description
name description
cryptoexchange-net 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 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.

Choose one of these approaches:

  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

dotnet add package Binance.Net
dotnet add package JK.OKX.Net
dotnet add package Bybit.Net

Or install the bundle:

dotnet add package CryptoClients.Net

Core pattern: fine-grained capabilities

Each exchange API surface exposes a typed .SharedApi aggregate. Assign it to the capability for the single operation being used:

using Binance.Net.Clients;
using OKX.Net.Clients;
using Bybit.Net.Clients;
using CryptoExchange.Net.SharedApis;

IGetTickerRest binance = new BinanceRestClient().SpotApi.SharedApi;
IGetTickerRest okx = new OKXRestClient().UnifiedApi.SharedApi;
IGetTickerRest bybit = new BybitRestClient().V5Api.SharedApi;

var symbol = new SharedSymbol(TradingMode.Spot, "BTC", "USDT");
var result = await binance.GetTickerAsync(new GetTickerRequest(symbol));

if (!result.Success)
    Console.WriteLine($"[{result.Exchange}] {result.Error}");
else
    Console.WriteLine($"[{result.Exchange}] {result.Data!.LastPrice}");

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.

Shared symbols

Use SharedSymbol; never pass exchange-native symbol strings to shared requests:

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:

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:

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.
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:

var clients = new IGetTickerRest[] { binance, okx, bybit };
var symbol = new SharedSymbol(TradingMode.Spot, "BTC", "USDT");

var tasks = clients.Select(client =>
    client.GetTickerAsync(new GetTickerRequest(symbol)));
var results = await Task.WhenAll(tasks);

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:

public sealed class TickerService(IGetTickerRest ticker)
{
    public Task<HttpResult<SharedTicker>> GetAsync(
        SharedSymbol symbol,
        CancellationToken ct = default)
        => ticker.GetTickerAsync(new GetTickerRequest(symbol), ct);
}

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.

For the bundle, use services.AddCryptoClients(...). CryptoClients.Net provides IExchangeSharedApiClient for capability lookup across exchanges.

V1 migration

V1 .SharedClient facades and broad interfaces such as ISpotTickerRestClient remain available. Migrate one operation at a time:

// V1
await restClient.SpotApi.SharedClient.GetSpotTickerAsync(request);

// V2
await restClient.SpotApi.SharedApi.GetTickerAsync(request);

Important semantic changes:

  • 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.

See docs/SHARED_API_V2_MIGRATION.md for detailed mappings.

Common pitfalls

  • 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.

Implementing a new exchange library

  • 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