diff --git a/.cursor/rules/cryptoexchange-net.mdc b/.cursor/rules/cryptoexchange-net.mdc index 21ed33eb..b5848928 100644 --- a/.cursor/rules/cryptoexchange-net.mdc +++ b/.cursor/rules/cryptoexchange-net.mdc @@ -1,87 +1,92 @@ --- -description: Conventions for cross-exchange code using CryptoExchange.Net SharedApis abstractions. Apply when generating C# code that interacts with multiple cryptocurrency exchanges through a unified interface. +description: Conventions for cross-exchange C# code using CryptoExchange.Net Shared API V2 capabilities. globs: - "**/*.cs" - "**/*.csproj" alwaysApply: false --- -# CryptoExchange.Net Conventions +# CryptoExchange.Net conventions -This codebase uses **CryptoExchange.Net** abstractions for multi-exchange access. Each exchange has its own library (Binance.Net, Bybit.Net, OKX.Net, ...). Use `CryptoExchange.Net.SharedApis` for code that should work across exchanges. +CryptoExchange.Net is the base dependency for exchange-specific libraries. Install Binance.Net, Bybit.Net, JK.OKX.Net, or another exchange library; use `CryptoClients.Net` when the application needs the bundle. -## Multi-exchange pattern +## Use Shared API V2 + +For new cross-exchange code, use the fine-grained interfaces in `CryptoExchange.Net.SharedApis` and each API surface's `.SharedApi` property: ```csharp -using Binance.Net.Clients; -using OKX.Net.Clients; using CryptoExchange.Net.SharedApis; -ISpotTickerRestClient binance = new BinanceRestClient().SpotApi.SharedClient; -ISpotTickerRestClient okx = new OKXRestClient().UnifiedApi.SharedClient; +IGetTickerRest binance = new BinanceRestClient().SpotApi.SharedApi; +IGetTickerRest okx = new OKXRestClient().UnifiedApi.SharedApi; var symbol = new SharedSymbol(TradingMode.Spot, "BTC", "USDT"); - -var ticker = await binance.GetSpotTickerAsync(new GetTickerRequest(symbol)); -// ticker.Data.LastPrice — same model regardless of exchange +var result = await binance.GetTickerAsync(new GetTickerRequest(symbol)); ``` -## Symbol normalization +Use one capability per operation, such as `IGetTickerRest`, `IGetOrderBookRest`, `IPlaceSpotOrderRest`, or `ISubscribeTradesSocket`. Do not use a broad V1 interface for new code. `.SharedClient` remains only for incremental V1 migration. -`SharedSymbol(TradingMode.Spot, "BTC", "USDT")` is portable. Each library translates to its native format internally. Don't pass raw strings like `"BTCUSDT"` to shared methods. +## Capability discovery -## Symbol metadata and catalogs - -In 12.2.0, `SharedSpotSymbol` and `SharedFuturesSymbol` include `DisplayName` and base/quote asset classification through `SharedAssetType` (`Crypto`, `Fiat`, `TradFi`) and `SharedAssetSubType` (`StableCoin`, `Equity`, `Commodity`). Pass the matching base/quote filters to `GetSymbolsRequest` when discovery should return only a class of markets. - -After calling `GetSpotSymbolsAsync`, `ISpotSymbolRestClient.SpotSymbolCatalog` maps asset and symbol names to shared metadata. `IFuturesSymbolRestClient.FuturesSymbolCatalog` works the same way after `GetFuturesSymbolsAsync`. Treat either property as unavailable before its corresponding request has populated the cache. - -When implementing an exchange library, use `LibraryHelpers.IsStableCoin`, `IsCommodity`, and `IsEquity` only as best-effort classifiers and supply exchange-specific additions where needed. - -## Shared market-data quantities - -In 12.4.0, use `SharedOrderQuantity`-valued `Volumes` on shared spot/futures tickers and klines, and `Quantities` on shared trades. The scalar `Volume`, `QuoteVolume`, and `Quantity` members are obsolete. - -## WebSocket order commands - -In 12.5.0, `ISpotOrderManagementSocketClient` and `IFuturesOrderManagementSocketClient` optionally provide place/cancel order commands over WebSocket. Their methods return `QueryResult`, not `WebSocketResult`. Check whether the exchange implements the interface. - -## Result pattern - -REST methods return `HttpResult` and websocket subscription methods return `WebSocketResult`. Always check `.Success`. `.Exchange` property identifies which exchange responded — useful for logging. - -## Available shared interfaces - -- REST tickers/symbols/orderbook/klines/trades, orders (spot/futures, regular/trigger/TP-SL), balances, positions, fees, deposits/withdrawals, transfers -- WebSocket tickers, book tickers, order book, trades, klines, user data, and optional spot/futures order management - -Each exchange documents which it implements. Not every exchange supports every operation. - -## Multi-exchange aggregation - -Run requests across exchanges concurrently via `Task.WhenAll` — the library is async-safe and concurrent requests are the norm. +When the exchange and API surface are known, assign the typed `.SharedApi` to the required capability. When selection is dynamic, use an exchange-wide `I[Exchange]SharedApiClient` and a strongly typed reference: ```csharp -var clients = new ISpotTickerRestClient[] { binance, okx, bybit }; -var tasks = clients.Select(c => c.GetSpotTickerAsync(new GetTickerRequest(symbol))); +var match = sharedClient.GetCapability( + SharedCapabilities.Orders.Futures.PlaceOrder.Rest, + TradingMode.PerpetualLinear); + +if (match is not null) + await match.Capability.PlaceFuturesOrderAsync(request); +``` + +`GetCapability` returns one preferred match or `null`; `GetCapabilities` returns all matches. Specify `TradingMode` when multiple API surfaces may implement the same capability. A `SharedCapabilities` reference is a lookup key, not proof of exchange support. + +## Symbols and parameters + +Use `SharedSymbol` instead of native strings such as `BTCUSDT`. The exchange library performs formatting. + +Capability presence does not imply support for every request property. For dynamic code, inspect `match.Options.RequestParameterRules`, `ExchangeParameterRules`, and `SupportedTradingModes`. Supply exchange-specific values through the request's `ExchangeParameters`. + +## Transports and results + +- Transport-agnostic capabilities return `IExchangeCallResult`. +- `...Rest` capabilities return `HttpResult`. +- socket command capabilities return `QueryResult`. +- `ISubscribe...Socket` capabilities return `WebSocketResult`. + +Use `.Rest` or `.Socket` on capability references when the transport matters. Otherwise exchange-wide lookup honors `PreferredTransport`, normally REST. Always check `.Success` before `.Data` and include `.Exchange` in multi-exchange logs. + +## Concurrent aggregation + +```csharp +var clients = new IGetTickerRest[] { binance, okx, bybit }; +var tasks = clients.Select(x => + x.GetTickerAsync(new GetTickerRequest(symbol))); var results = await Task.WhenAll(tasks); ``` +Reuse clients through dependency injection and run independent exchange calls concurrently. + +## V2 semantics + +- `GetTickerAsync` and `GetAllTickersAsync` return `SharedTicker` for spot and futures. +- WebSocket order updates use `SharedSpotOrderUpdate` and `SharedFuturesOrderUpdate`. +- `ICloseFullPosition` closes the entire position; use an order capability for partial closes. +- Each exchange supports a subset of capabilities and parameter combinations. + ## Hard rules -- ❌ Never install `CryptoExchange.Net` alone and expect to call exchanges — it's a base library; you need exchange-specific packages -- ❌ Never mix exchange-specific models in cross-exchange code (use `SharedSymbol`, `SharedSpotTicker`, etc.) -- ❌ Never use `.Result` / `.Wait()` — async-only -- ❌ Never iterate sequentially when concurrency is fine — `Task.WhenAll` is your friend -- ❌ Never instantiate clients per-request — reuse via DI -- ✅ Always use `.SharedClient` for cross-exchange code -- ✅ Always check `.Success` before reading `.Data` -- ✅ Always log with `.Exchange` so multi-exchange logs are decipherable -- ✅ Always handle "not supported on this exchange" errors gracefully +- Never install CryptoExchange.Net alone and expect exchange endpoints. +- Never pass exchange-native models or symbols through shared services. +- Never assume a capability or request field is supported; resolve and inspect it. +- Never use `.Result` or `.Wait()`. +- Never instantiate exchange clients per request. +- Prefer `Task.WhenAll` for independent cross-exchange calls. +- Prefer `.SharedApi` and fine-grained V2 interfaces for new code. ## Reference -- `AGENTS.md` in repo root has fuller examples -- `llms.txt` for AI context -- `Examples/ai-friendly/` for compilable examples -- For single-exchange code, see that exchange's library (e.g., Binance.Net `AGENTS.md`) +- `AGENTS.md` for fuller examples +- `docs/ai-api-map.md` for the V2 interface map +- `docs/SHARED_API_V2_MIGRATION.md` for V1 migration details +- `llms-full.txt` for expanded AI context diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 865eb987..0b0ec86f 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,66 +1,70 @@ # Copilot Instructions for CryptoExchange.Net -This repository is **CryptoExchange.Net** — the base library powering 28+ cryptocurrency exchange wrappers in C#/.NET (Binance.Net, Bybit.Net, OKX.Net, Kraken.Net, Coinbase.Net, etc.). +CryptoExchange.Net is the base library behind exchange-specific C#/.NET clients such as Binance.Net, Bybit.Net, OKX.Net, Kraken.Net, and Coinbase.Net. -When generating code in this ecosystem, follow these conventions: +## Package choice -## You don't install CryptoExchange.Net directly +Do not install CryptoExchange.Net alone to call an exchange. Install the exchange-specific package, or use `CryptoClients.Net` for the full bundle. For single-exchange code, prefer that library's native client. For portable multi-exchange code, use `CryptoExchange.Net.SharedApis`. -Install the exchange-specific library you need (`Binance.Net`, `JK.OKX.Net`, `Bybit.Net`, ...) or `CryptoClients.Net` for the bundle. CryptoExchange.Net is pulled in as a dependency. +## Generate Shared API V2 code -## Multi-exchange code uses SharedApis - -For code that must work against multiple exchanges, use `CryptoExchange.Net.SharedApis` interfaces accessed via `.SharedClient` properties on each exchange's API surface: +Use fine-grained V2 capabilities through `.SharedApi`: ```csharp using CryptoExchange.Net.SharedApis; -ISpotTickerRestClient binance = new BinanceRestClient().SpotApi.SharedClient; -ISpotTickerRestClient okx = new OKXRestClient().UnifiedApi.SharedClient; +IGetTickerRest binance = new BinanceRestClient().SpotApi.SharedApi; +IGetTickerRest okx = new OKXRestClient().UnifiedApi.SharedApi; var symbol = new SharedSymbol(TradingMode.Spot, "BTC", "USDT"); -var ticker = await binance.GetSpotTickerAsync(new GetTickerRequest(symbol)); +var result = await binance.GetTickerAsync(new GetTickerRequest(symbol)); ``` -Same code works on every exchange that implements the interface. Use `Task.WhenAll` for concurrent multi-exchange calls. +Choose the interface for the operation: for example, `IGetTickerRest`, `IGetOrderBookRest`, `IPlaceSpotOrderRest`, `ICancelFuturesOrderRest`, or `ISubscribeTradesSocket`. V1 broad interfaces remain on `.SharedClient` for migration, but new code should use `.SharedApi`. -## Shared symbol metadata +Use `SharedSymbol`; do not hard-code exchange-native symbol formatting in shared code. -CryptoExchange.Net 12.2.0 classifies the base and quote sides of `SharedSpotSymbol` and `SharedFuturesSymbol` with `SharedAssetType` (`Crypto`, `Fiat`, `TradFi`) and optional `SharedAssetSubType` (`StableCoin`, `Equity`, `Commodity`). The models also expose `DisplayName`. Use the corresponding base/quote fields on `GetSymbolsRequest` to filter symbol discovery. +## Runtime capability selection -`ISpotSymbolRestClient.SpotSymbolCatalog` is populated by `GetSpotSymbolsAsync`; `IFuturesSymbolRestClient.FuturesSymbolCatalog` is populated by `GetFuturesSymbolsAsync`. Do not assume a catalog is available before that request. For exchange-library implementations, `LibraryHelpers.IsStableCoin`, `IsCommodity`, and `IsEquity` offer best-effort classification and can be extended with exchange-specific values. +When the API surface is known, assign its typed `.SharedApi` directly. When support or the API surface is selected at runtime, use the exchange-wide `I[Exchange]SharedApiClient`: -## Shared market-data quantities +```csharp +var match = sharedClient.GetCapability( + SharedCapabilities.Orders.Futures.PlaceOrder.Rest, + TradingMode.PerpetualLinear); -CryptoExchange.Net 12.4.0 uses `SharedOrderQuantity` for market-data quantities. Prefer `Volumes` on `SharedSpotTicker`, `SharedFuturesTicker`, and `SharedKline`, and `Quantities` on `SharedTrade`; the scalar `Volume`, `QuoteVolume`, and `Quantity` members are obsolete. +if (match is null) + return; -## WebSocket order commands +var result = await match.Capability.PlaceFuturesOrderAsync(request); +``` -CryptoExchange.Net 12.5.0 adds optional `ISpotOrderManagementSocketClient` and `IFuturesOrderManagementSocketClient` interfaces for placing and canceling orders over WebSocket. These command methods return `QueryResult` rather than a subscription result. Check exchange support before relying on either interface. +`GetCapability` returns one preferred `SharedCapabilityResolution` or `null`; `GetCapabilities` returns all matching implementations. Include `TradingMode` when an exchange can expose multiple futures surfaces. `SharedCapabilities` entries are lookup references, not guarantees of support. -## Single-exchange code uses the exchange's own client +Before constructing dynamic requests, inspect `match.Options.RequestParameterRules`, `ExchangeParameterRules`, and `SupportedTradingModes`. A capability may exist while a particular request field is unsupported. -For Binance-only code, use `BinanceRestClient` directly (see Binance.Net repo `AGENTS.md`). SharedApis is for portability — use it when you need that. +## Results and transports -## Result pattern +- Transport-agnostic operation: `IExchangeCallResult` +- REST capability: `HttpResult` +- WebSocket command capability: `QueryResult` +- WebSocket subscription capability: `WebSocketResult` -REST methods return `HttpResult` and websocket subscription methods return `WebSocketResult`. Check `.Success` before `.Data`. `.Error` has structured info. `.Exchange` on shared clients identifies which exchange responded. +Select `.Rest` or `.Socket` when transport-specific behavior matters. Otherwise exchange-wide selection uses `PreferredTransport`, normally REST. Always check `.Success` before `.Data`; use `.Error` and `.Exchange` for diagnostics. -## Available shared interfaces +## Current V2 semantics -REST: tickers, symbols, orderbook, klines, trades, orders (spot/futures, trigger, TP-SL), balances, positions, fees, deposits/withdrawals, transfers. -WebSocket: tickers, book tickers, orderbook, trades, klines, user data, and optional spot/futures order management. +- Ticker operations are `GetTickerAsync` and `GetAllTickersAsync`, returning `SharedTicker` for both spot and futures. +- Socket order streams use `SharedSpotOrderUpdate` and `SharedFuturesOrderUpdate`. +- `ICloseFullPosition` closes a complete position, not a partial quantity. +- Exchange support varies by operation, transport, trading mode, and request parameter. -Each exchange library implements a subset. Check exchange docs for support matrix. +## Engineering conventions -## Avoid +- Reuse clients through dependency injection. +- Use `await`; never use `.Result` or `.Wait()`. +- Use `Task.WhenAll` for independent requests across exchanges. +- Keep exchange-native models out of portable services. +- Do not infer feature support from a broad interface or request model. -- Installing `CryptoExchange.Net` alone and trying to call exchange APIs (need exchange-specific packages) -- Mixing exchange-native models in cross-exchange code (use Shared* types) -- Synchronous `.Result` / `.Wait()` (use `await`) -- Instantiating clients per-request (use DI, reuse instances) -- Sequential per-exchange calls when parallel is fine (`Task.WhenAll`) - -## Reference - -For detailed patterns see `AGENTS.md` and `llms.txt` in repo root, `examples/ai-friendly/` for compilable examples. +See `AGENTS.md`, `docs/ai-api-map.md`, and `docs/SHARED_API_V2_MIGRATION.md` for expanded guidance. diff --git a/AGENTS.md b/AGENTS.md index 97f49b78..096a5b7c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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`. 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` and websocket subscription calls return `WebSocketResult`, 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` 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`. +- REST-specific, such as `IPlaceSpotOrderRest`, returns `HttpResult`. +- socket-specific, such as `IPlaceSpotOrderSocket`, returns `QueryResult`. + +Socket subscription capabilities such as `ISubscribeTickerSocket` return `WebSocketResult`. + +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> 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`; 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 diff --git a/CryptoExchange.Net/CryptoExchange.Net.csproj b/CryptoExchange.Net/CryptoExchange.Net.csproj index 4f985559..1eac0cf1 100644 --- a/CryptoExchange.Net/CryptoExchange.Net.csproj +++ b/CryptoExchange.Net/CryptoExchange.Net.csproj @@ -6,9 +6,9 @@ CryptoExchange.Net JKorf CryptoExchange.Net is a base library which is used to implement different cryptocurrency (exchange) API's. It provides a standardized way of implementing different API's, which results in a very similar experience for users of the API implementations. - 12.5.1 - 12.5.1 - 12.5.1 + 13.0.0 + 13.0.0 + 13.0.0 false OKX;OKX.Net;Mexc;Mexc.Net;Kucoin;Kucoin.Net;Kraken;Kraken.Net;Huobi;Huobi.Net;CoinEx;CoinEx.Net;Bybit;Bybit.Net;Bitget;Bitget.Net;Bitfinex;Bitfinex.Net;Binance;Binance.Net;CryptoCurrency;CryptoCurrency Exchange;CryptoExchange.Net git diff --git a/README.md b/README.md index 24e780e5..2d8cfd5e 100644 --- a/README.md +++ b/README.md @@ -127,6 +127,41 @@ Various: * PlatformInfo now required support environment names in the constructor ## Release notes +* Version 13.0.0 - 23 Sep 2026 + * Shared APIs + * Added Shared API V2 with fine-grained capability interfaces for individual REST requests, WebSocket requests and subscriptions + * Added transport-agnostic capability interfaces with REST- and WebSocket-specific variants where applicable + * Added dynamic capability resolution support with optional transport preference option + * Added `RequestParameterRules` and `ExchangeParameterRules` properties on Shared API options making request parameter rules and support clearer + * Added new Shared API capabilities for ledger history, funding information and history, leverage tiers, transfers, mark prices and index prices + * Added new capabilities for placing and editing multiple spot and futures orders + * Added new capabilities for cancelling all open orders and all open symbol orders + * Added new incremental order book, mark price and index price subscriptions + * Added ReduceOnly parameter to PlaceFuturesTriggerOrderRequest + * Added new `SharedTicker` as the common V2 ticker model for spot and futures markets + * For additional futures ticker info like mark/index price and funding info separate interfaces are available in V2 + * Added `SharedSpotOrderUpdate` and `SharedFuturesOrderUpdate` models for WebSocket order updates + * Added `IExchangeCallResult` and `IExchangeCallResult` for transport-agnostic Shared API results + * Retained the V1 aggregate Shared API interfaces for backwards compatibility + * Renamed GetAssetsOptions to GetAllAssetsOptions + * Renamed GetWithdrawalsOptions to GetWithdrawalHistoryOptions + * Renamed GetDepositsOptions to GetDepositHistoryOptions + * GetFuturesTickerOptions and GetSpotTickerOptions have been replaced by GetTickerOptions + * Deprecated Subscribe request constructors using `params` for `SharedSymbol` parameter + * Rate limiting + * Added `RateLimitAdmission` for restricting requests to a configurable maximum rate limit utilization + * Added the `RateLimitAdmission` client option callback for assigning admission rules based on request definition and weight + * Added `WithRateLimitAdmissionAsync` for applying a rate limit admission rule to a specific REST, WebSocket or Shared API operation + * Added configurable safety margins to fixed, sliding and fixed-after-first rate limit windows + * Fixed decay rate limiter calculations and handling of partial decay progress + * Fixed fixed and sliding window boundary calculations + * Added automatic in-flight request coalescing for identical public REST GET requests + * Sending identical public GET requests on the same client will only send a single request to the server and use the same response + * Coalescing is enabled by default and can be disabled with the `RequestCoalescingEnabled` client option + * Added `DataTime`, `DataTimeLocal` and `SequenceNumber` propagation when converting `DataEvent` instances + * Fixed form data URL encoding on .NET Framework when parameter values contain special characters + * Fixed array converter not correctly handling decimal parsing for certain notations + * Version 12.5.1 - 01 Sep 2026 * Fixed KlineTracker reporting incorrect High/Low price on GetStats result * Fixed caching issue for auth requests diff --git a/llms.txt b/llms.txt index c7e3b2ce..0bebafb3 100644 --- a/llms.txt +++ b/llms.txt @@ -1,40 +1,37 @@ # CryptoExchange.Net -> Base C#/.NET library for cryptocurrency exchange API client implementations. Provides a standardized abstraction (REST, WebSocket, authentication, rate limiting, error handling, order book management, shared cross-exchange interfaces) that 28+ exchange-specific libraries are built on top of. +> Base C#/.NET library used by 28+ cryptocurrency exchange clients. It standardizes REST, WebSocket, authentication, rate limiting, results, and exchange-agnostic Shared APIs. -CryptoExchange.Net itself is not used directly — install one of the exchange-specific libraries (Binance.Net, Bybit.Net, OKX.Net, Kraken.Net, Coinbase.Net, etc.) or `CryptoClients.Net` to access all exchanges via a single bundle. The base library is what makes the entire ecosystem feel consistent: same `HttpResult` REST result pattern, same `WebSocketResult` websocket subscription pattern, same DI registration, same shared interfaces across all exchanges. Current version: 12.5.1. Targets netstandard2.0, netstandard2.1, net8.0, net9.0, net10.0. Native AOT supported. +CryptoExchange.Net is not an exchange client by itself. Install exchange-specific packages such as Binance.Net, Bybit.Net, JK.OKX.Net, Kraken.Net, or Coinbase.Net, or install `CryptoClients.Net` for the bundle. Current release: 13.0.0. Targets netstandard2.0, netstandard2.1, net8.0, net9.0, and net10.0; Native AOT is supported. -The standout feature for cross-exchange code is `CryptoExchange.Net.SharedApis` — a set of interfaces (`ISpotTickerRestClient`, `ISpotOrderRestClient`, `IBalanceRestClient`, etc.) implemented by every exchange library. Same call signature works against any exchange. +## Shared API V2 -Version 12.2.0 adds typed asset metadata to shared symbol discovery. `SharedSpotSymbol` and `SharedFuturesSymbol` expose `DisplayName` plus base/quote `SharedAssetType` and `SharedAssetSubType` values. `GetSymbolsRequest` can filter on those four type fields. After symbol discovery, `ISpotSymbolRestClient.SpotSymbolCatalog` and `IFuturesSymbolRestClient.FuturesSymbolCatalog` provide asset and symbol dictionaries; each catalog is available only after the corresponding `Get*SymbolsAsync` call. `LibraryHelpers.IsStableCoin`, `IsCommodity`, and `IsEquity` are best-effort helpers for exchange-library implementations. +For new cross-exchange code, use fine-grained capability interfaces from `CryptoExchange.Net.SharedApis` through each API surface's `.SharedApi` property. Examples: `IGetTickerRest`, `IGetOrderBookRest`, `IPlaceSpotOrderRest`, and `ISubscribeTradesSocket`. -Version 12.4.0 represents market-data quantities with `SharedOrderQuantity`: use `Volumes` on `SharedSpotTicker`, `SharedFuturesTicker`, and `SharedKline`, and `Quantities` on `SharedTrade`. The old scalar `Volume`, `QuoteVolume`, and `Quantity` members are obsolete. Exchange-library implementations must pass `SharedOrderQuantity` to these model constructors. +Use `SharedSymbol` to normalize symbols and `Task.WhenAll` for independent calls across exchanges. Use an exchange-wide `I[Exchange]SharedApiClient` plus `SharedCapabilities` and `GetCapability` when selecting operations dynamically. A resolution can be `null`; its `Options` describes supported trading modes and request/exchange parameter rules. -Version 12.5.0 adds optional shared WebSocket order commands through `ISpotOrderManagementSocketClient` and `IFuturesOrderManagementSocketClient`. Their place/cancel methods return `QueryResult`; they are commands rather than update subscriptions, and support is exchange-specific. +Transport-agnostic capabilities return `IExchangeCallResult`. REST capabilities return `HttpResult`, socket commands return `QueryResult`, and socket subscriptions return `WebSocketResult`. Always check `.Success` before `.Data`. + +V1 broad interfaces remain accessible through `.SharedClient` for incremental migration. Prefer `.SharedApi` for new code. V2 ticker calls use `GetTickerAsync`/`GetAllTickersAsync` and the common `SharedTicker` model. ## Documentation -- [README](https://github.com/JKorf/CryptoExchange.Net/blob/master/README.md): Overview, full ecosystem table (28+ exchange libraries), installation per exchange, complete release notes -- [Documentation Site](https://cryptoexchange.jkorf.dev/): Full documentation hub with sections per topic -- [SharedApis Documentation](https://cryptoexchange.jkorf.dev/CryptoExchange.Net/idocs_shared.html): Cross-exchange shared interface guide +- [README](https://github.com/JKorf/CryptoExchange.Net/blob/master/README.md): ecosystem overview, packages, and release notes +- [Shared API V2 migration](https://github.com/JKorf/CryptoExchange.Net/blob/master/docs/SHARED_API_V2_MIGRATION.md): V1-to-V2 mapping, capability selection, transports, and parameter discovery +- [Documentation site](https://cryptoexchange.jkorf.dev/): complete library documentation +- [Shared API documentation](https://cryptoexchange.jkorf.dev/CryptoExchange.Net/idocs_shared.html): cross-exchange API guide +- [AI API map](https://github.com/JKorf/CryptoExchange.Net/blob/master/docs/ai-api-map.md): concise V2 interface and selection map -## Examples +## AI context files -- [AI-friendly examples directory](https://github.com/JKorf/CryptoExchange.Net/tree/master/Examples/ai-friendly): Compact, fully runnable examples optimized for AI assistants -- [Shared Clients Quickstart](https://github.com/JKorf/CryptoExchange.Net/blob/master/Examples/ai-friendly/01-shared-clients-quickstart.cs): Same code calling multiple exchanges via SharedApis -- [Multi-Exchange Tickers](https://github.com/JKorf/CryptoExchange.Net/blob/master/Examples/ai-friendly/02-multi-exchange-tickers.cs): Aggregating ticker data across N exchanges concurrently -- [Cross-Exchange Arbitrage Skeleton](https://github.com/JKorf/CryptoExchange.Net/blob/master/Examples/ai-friendly/03-cross-exchange-arbitrage-skeleton.cs): Pattern for building a price difference scanner -- [Full Examples Repository](https://github.com/JKorf/CryptoExchange.Net/tree/master/Examples): ConsoleClient with multiple exchange exchanges, BlazorClient, SharedClients +- [AGENTS.md](https://github.com/JKorf/CryptoExchange.Net/blob/master/AGENTS.md): practical generation rules and examples +- [llms-full.txt](https://github.com/JKorf/CryptoExchange.Net/blob/master/llms-full.txt): expanded library and Shared API V2 context +- [.github/copilot-instructions.md](https://github.com/JKorf/CryptoExchange.Net/blob/master/.github/copilot-instructions.md): compact repository conventions +- [.cursor/rules/CryptoExchange-Net.mdc](https://github.com/JKorf/CryptoExchange.Net/blob/master/.cursor/rules/CryptoExchange-Net.mdc): Cursor rules for cross-exchange C# code -## Reference +## Related projects -- [Ecosystem libraries list](https://github.com/JKorf/CryptoExchange.Net#cryptoexchangenet-ecosystem): Aster, Binance, BingX, Bitfinex, Bitget, BitMart, BitMEX, Bitstamp, BloFin, Bybit, Coinbase, CoinEx, CoinW, CoinGecko, Crypto.com, DeepCoin, Gate.io, HTX, HyperLiquid, Kraken, Kucoin, Mexc, OKX, Pionex, Polymarket, Toobit, Upbit, Weex, WhiteBit, XT -- [CryptoClients.Net](https://github.com/JKorf/CryptoClients.Net): Single bundle package for all exchange libraries -- [CryptoManager.Net](https://github.com/JKorf/CryptoManager.Net): Full demo application using CryptoClients.Net -- [NuGet Package](https://www.nuget.org/packages/CryptoExchange.Net): Latest stable release on NuGet - -## Optional - -- [Discord Community](https://discord.gg/MSpeEtSY8t): Maintainer-supported Discord for ecosystem-wide discussion -- [GitHub Issues](https://github.com/JKorf/CryptoExchange.Net/issues): Bug reports and feature requests -- [GitHub Sponsors](https://github.com/sponsors/JKorf): Support the maintainer +- [CryptoClients.Net](https://github.com/JKorf/CryptoClients.Net): bundle and cross-exchange capability lookup +- [CryptoManager.Net](https://github.com/JKorf/CryptoManager.Net): full demo application +- [NuGet](https://www.nuget.org/packages/CryptoExchange.Net): package releases +- [Discord](https://discord.gg/MSpeEtSY8t): maintainer-supported community