diff --git a/docs/endpointFunctionList.md b/docs/endpointFunctionList.md index a8db4f2..1c17038 100644 --- a/docs/endpointFunctionList.md +++ b/docs/endpointFunctionList.md @@ -52,66 +52,69 @@ This table includes all endpoints from the official Exchange API docs and corres | Function | AUTH | HTTP Method | Endpoint | | -------- | :------: | :------: | -------- | -| [getSystemStatus()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L141) | | GET | `0/public/SystemStatus` | -| [getAssetInfo()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L150) | | GET | `0/public/Assets` | -| [getAssetPairs()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L162) | | GET | `0/public/AssetPairs` | -| [getTicker()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L175) | | GET | `0/public/Ticker` | -| [getCandles()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L189) | | GET | `0/public/OHLC` | -| [getOrderBook()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L201) | | GET | `0/public/Depth` | -| [getRecentTrades()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L212) | | GET | `0/public/Trades` | -| [getRecentSpreads()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L223) | | GET | `0/public/Spread` | -| [getAccountBalance()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L240) | :closed_lock_with_key: | POST | `0/private/Balance` | -| [getExtendedBalance()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L252) | :closed_lock_with_key: | POST | `0/private/BalanceEx` | -| [getCreditLines()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L263) | :closed_lock_with_key: | POST | `0/private/CreditLines` | -| [getTradeBalance()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L274) | :closed_lock_with_key: | POST | `0/private/TradeBalance` | -| [getOpenOrders()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L285) | :closed_lock_with_key: | POST | `0/private/OpenOrders` | -| [getClosedOrders()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L297) | :closed_lock_with_key: | POST | `0/private/ClosedOrders` | -| [getOrders()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L308) | :closed_lock_with_key: | POST | `0/private/QueryOrders` | -| [getOrderAmends()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L320) | :closed_lock_with_key: | POST | `0/private/OrderAmends` | -| [getTradesHistory()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L332) | :closed_lock_with_key: | POST | `0/private/TradesHistory` | -| [getTrades()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L343) | :closed_lock_with_key: | POST | `0/private/QueryTrades` | -| [getOpenPositions()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L354) | :closed_lock_with_key: | POST | `0/private/OpenPositions` | -| [getLedgersInfo()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L365) | :closed_lock_with_key: | POST | `0/private/Ledgers` | -| [getLedgers()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L376) | :closed_lock_with_key: | POST | `0/private/QueryLedgers` | -| [getTradingVolume()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L388) | :closed_lock_with_key: | POST | `0/private/TradeVolume` | -| [requestLedgersExport()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L400) | :closed_lock_with_key: | POST | `0/private/AddExport` | -| [getLedgersExportStatus()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L411) | :closed_lock_with_key: | POST | `0/private/ExportStatus` | -| [getLedgersExport()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L422) | :closed_lock_with_key: | POST | `0/private/RetrieveExport` | -| [deleteLedgersExport()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L431) | :closed_lock_with_key: | POST | `0/private/RemoveExport` | -| [submitOrder()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L451) | :closed_lock_with_key: | POST | `0/private/AddOrder` | -| [amendOrder()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L465) | :closed_lock_with_key: | POST | `0/private/AmendOrder` | -| [cancelOrder()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L480) | :closed_lock_with_key: | POST | `0/private/CancelOrder` | -| [cancelAllOrders()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L496) | :closed_lock_with_key: | POST | `0/private/CancelAll` | -| [cancelAllOrdersAfter()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L512) | :closed_lock_with_key: | POST | `0/private/CancelAllOrdersAfter` | -| [getWebSocketsToken()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L529) | :closed_lock_with_key: | POST | `0/private/GetWebSocketsToken` | -| [submitBatchOrders()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L541) | :closed_lock_with_key: | POST | `0/private/AddOrderBatch` | -| [cancelBatchOrders()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L556) | :closed_lock_with_key: | POST | `0/private/CancelOrderBatch` | -| [getDepositMethods()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L580) | :closed_lock_with_key: | POST | `0/private/DepositMethods` | -| [getDepositAddresses()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L591) | :closed_lock_with_key: | POST | `0/private/DepositAddresses` | -| [getDepositsStatus()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L602) | :closed_lock_with_key: | POST | `0/private/DepositStatus` | -| [getWithdrawalMethods()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L613) | :closed_lock_with_key: | POST | `0/private/WithdrawMethods` | -| [getWithdrawalAddresses()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L624) | :closed_lock_with_key: | POST | `0/private/WithdrawAddresses` | -| [getWithdrawalInfo()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L635) | :closed_lock_with_key: | POST | `0/private/WithdrawInfo` | -| [submitWithdrawal()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L646) | :closed_lock_with_key: | POST | `0/private/Withdraw` | -| [getWithdrawalsStatus()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L659) | :closed_lock_with_key: | POST | `0/private/WithdrawStatus` | -| [cancelWithdrawal()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L670) | :closed_lock_with_key: | POST | `0/private/WithdrawCancel` | -| [submitTransferToFutures()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L683) | :closed_lock_with_key: | POST | `0/private/WalletTransfer` | -| [createSubaccount()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L703) | :closed_lock_with_key: | POST | `0/private/CreateSubaccount` | -| [submitSubaccountTransfer()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L716) | :closed_lock_with_key: | POST | `0/private/AccountTransfer` | -| [allocateEarnFunds()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L734) | :closed_lock_with_key: | POST | `0/private/Earn/Allocate` | -| [deallocateEarnFunds()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L747) | :closed_lock_with_key: | POST | `0/private/Earn/Deallocate` | -| [getEarnAllocationStatus()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L759) | :closed_lock_with_key: | POST | `0/private/Earn/AllocateStatus` | -| [getEarnDeallocationStatus()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L772) | :closed_lock_with_key: | POST | `0/private/Earn/DeallocateStatus` | -| [getEarnStrategies()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L788) | :closed_lock_with_key: | POST | `0/private/Earn/Strategies` | -| [getEarnAllocations()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L803) | :closed_lock_with_key: | POST | `0/private/Earn/Allocations` | -| [getPreTradeData()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L821) | | GET | `0/public/PreTrade` | -| [getPostTradeData()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L833) | | GET | `0/public/PostTrade` | -| [getOAuthAccessToken()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L851) | | POST | `oauth/token` | -| [getOAuthUserInfo()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L863) | :closed_lock_with_key: | GET | `oauth/userinfo` | -| [createOAuthFastApiKey()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L873) | :closed_lock_with_key: | POST | `oauth/fast-api-key` | -| [deleteOAuthFastApiKey()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L885) | :closed_lock_with_key: | DELETE | `oauth/fast-api-key` | -| [updateOAuthFastApiKey()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L899) | :closed_lock_with_key: | PUT | `oauth/fast-api-key` | -| [listOAuthFastApiKeys()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L911) | :closed_lock_with_key: | GET | `oauth/fast-api-keys` | +| [getSystemStatus()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L148) | | GET | `0/public/SystemStatus` | +| [getAssetInfo()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L157) | | GET | `0/public/Assets` | +| [getAssetPairs()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L169) | | GET | `0/public/AssetPairs` | +| [getTicker()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L182) | | GET | `0/public/Ticker` | +| [getCandles()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L196) | | GET | `0/public/OHLC` | +| [getOrderBook()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L208) | | GET | `0/public/Depth` | +| [getGroupedBook()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L219) | | GET | `0/public/GroupedBook` | +| [getLevel3OrderBook()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L230) | :closed_lock_with_key: | POST | `0/private/Level3` | +| [getRecentTrades()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L241) | | GET | `0/public/Trades` | +| [getRecentSpreads()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L252) | | GET | `0/public/Spread` | +| [getAccountBalance()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L269) | :closed_lock_with_key: | POST | `0/private/Balance` | +| [getApiKeyInfo()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L280) | :closed_lock_with_key: | POST | `0/private/GetApiKeyInfo` | +| [getExtendedBalance()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L292) | :closed_lock_with_key: | POST | `0/private/BalanceEx` | +| [getCreditLines()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L303) | :closed_lock_with_key: | POST | `0/private/CreditLines` | +| [getTradeBalance()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L314) | :closed_lock_with_key: | POST | `0/private/TradeBalance` | +| [getOpenOrders()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L325) | :closed_lock_with_key: | POST | `0/private/OpenOrders` | +| [getClosedOrders()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L337) | :closed_lock_with_key: | POST | `0/private/ClosedOrders` | +| [getOrders()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L348) | :closed_lock_with_key: | POST | `0/private/QueryOrders` | +| [getOrderAmends()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L360) | :closed_lock_with_key: | POST | `0/private/OrderAmends` | +| [getTradesHistory()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L372) | :closed_lock_with_key: | POST | `0/private/TradesHistory` | +| [getTrades()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L383) | :closed_lock_with_key: | POST | `0/private/QueryTrades` | +| [getOpenPositions()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L394) | :closed_lock_with_key: | POST | `0/private/OpenPositions` | +| [getLedgersInfo()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L405) | :closed_lock_with_key: | POST | `0/private/Ledgers` | +| [getLedgers()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L416) | :closed_lock_with_key: | POST | `0/private/QueryLedgers` | +| [getTradingVolume()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L428) | :closed_lock_with_key: | POST | `0/private/TradeVolume` | +| [requestLedgersExport()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L439) | :closed_lock_with_key: | POST | `0/private/AddExport` | +| [getLedgersExportStatus()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L450) | :closed_lock_with_key: | POST | `0/private/ExportStatus` | +| [getLedgersExport()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L461) | :closed_lock_with_key: | POST | `0/private/RetrieveExport` | +| [deleteLedgersExport()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L470) | :closed_lock_with_key: | POST | `0/private/RemoveExport` | +| [submitOrder()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L490) | :closed_lock_with_key: | POST | `0/private/AddOrder` | +| [amendOrder()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L504) | :closed_lock_with_key: | POST | `0/private/AmendOrder` | +| [cancelOrder()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L519) | :closed_lock_with_key: | POST | `0/private/CancelOrder` | +| [cancelAllOrders()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L535) | :closed_lock_with_key: | POST | `0/private/CancelAll` | +| [cancelAllOrdersAfter()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L551) | :closed_lock_with_key: | POST | `0/private/CancelAllOrdersAfter` | +| [getWebSocketsToken()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L568) | :closed_lock_with_key: | POST | `0/private/GetWebSocketsToken` | +| [submitBatchOrders()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L580) | :closed_lock_with_key: | POST | `0/private/AddOrderBatch` | +| [cancelBatchOrders()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L595) | :closed_lock_with_key: | POST | `0/private/CancelOrderBatch` | +| [getDepositMethods()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L619) | :closed_lock_with_key: | POST | `0/private/DepositMethods` | +| [getDepositAddresses()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L630) | :closed_lock_with_key: | POST | `0/private/DepositAddresses` | +| [getDepositsStatus()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L641) | :closed_lock_with_key: | POST | `0/private/DepositStatus` | +| [getWithdrawalMethods()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L652) | :closed_lock_with_key: | POST | `0/private/WithdrawMethods` | +| [getWithdrawalAddresses()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L663) | :closed_lock_with_key: | POST | `0/private/WithdrawAddresses` | +| [getWithdrawalInfo()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L674) | :closed_lock_with_key: | POST | `0/private/WithdrawInfo` | +| [submitWithdrawal()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L685) | :closed_lock_with_key: | POST | `0/private/Withdraw` | +| [getWithdrawalsStatus()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L698) | :closed_lock_with_key: | POST | `0/private/WithdrawStatus` | +| [cancelWithdrawal()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L709) | :closed_lock_with_key: | POST | `0/private/WithdrawCancel` | +| [submitTransferToFutures()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L722) | :closed_lock_with_key: | POST | `0/private/WalletTransfer` | +| [createSubaccount()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L742) | :closed_lock_with_key: | POST | `0/private/CreateSubaccount` | +| [submitSubaccountTransfer()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L755) | :closed_lock_with_key: | POST | `0/private/AccountTransfer` | +| [allocateEarnFunds()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L773) | :closed_lock_with_key: | POST | `0/private/Earn/Allocate` | +| [deallocateEarnFunds()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L786) | :closed_lock_with_key: | POST | `0/private/Earn/Deallocate` | +| [getEarnAllocationStatus()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L798) | :closed_lock_with_key: | POST | `0/private/Earn/AllocateStatus` | +| [getEarnDeallocationStatus()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L811) | :closed_lock_with_key: | POST | `0/private/Earn/DeallocateStatus` | +| [getEarnStrategies()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L827) | :closed_lock_with_key: | POST | `0/private/Earn/Strategies` | +| [getEarnAllocations()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L842) | :closed_lock_with_key: | POST | `0/private/Earn/Allocations` | +| [getPreTradeData()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L860) | | GET | `0/public/PreTrade` | +| [getPostTradeData()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L872) | | GET | `0/public/PostTrade` | +| [getOAuthAccessToken()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L890) | | POST | `oauth/token` | +| [getOAuthUserInfo()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L902) | :closed_lock_with_key: | GET | `oauth/userinfo` | +| [createOAuthFastApiKey()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L912) | :closed_lock_with_key: | POST | `oauth/fast-api-key` | +| [deleteOAuthFastApiKey()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L924) | :closed_lock_with_key: | DELETE | `oauth/fast-api-key` | +| [updateOAuthFastApiKey()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L938) | :closed_lock_with_key: | PUT | `oauth/fast-api-key` | +| [listOAuthFastApiKeys()](https://github.com/sieblyio/kraken-api/blob/main/src/SpotClient.ts#L950) | :closed_lock_with_key: | GET | `oauth/fast-api-keys` | # DerivativesClient.ts diff --git a/examples/apidoc/SpotClient/getApiKeyInfo.js b/examples/apidoc/SpotClient/getApiKeyInfo.js new file mode 100644 index 0000000..42ea5e3 --- /dev/null +++ b/examples/apidoc/SpotClient/getApiKeyInfo.js @@ -0,0 +1,22 @@ +import { SpotClient } from '@siebly/kraken-api'; +// or, if require is preferred: +// const { SpotClient } = require('@siebly/kraken-api'); + +// This example shows how to call this Kraken API endpoint with either node.js, javascript (js) or typescript (ts) with the npm module "@siebly/kraken-api" for Kraken exchange +// This Kraken API SDK is available on npm via "npm install @siebly/kraken-api" +// ENDPOINT: 0/private/GetApiKeyInfo +// METHOD: POST +// PUBLIC: NO + +const client = new SpotClient({ + apiKey: 'insert_api_key_here', + apiSecret: 'insert_api_secret_here', +}); + +client.getApiKeyInfo(params) + .then((response) => { + console.log(response); + }) + .catch((error) => { + console.error(error); + }); diff --git a/examples/apidoc/SpotClient/getGroupedBook.js b/examples/apidoc/SpotClient/getGroupedBook.js new file mode 100644 index 0000000..272e294 --- /dev/null +++ b/examples/apidoc/SpotClient/getGroupedBook.js @@ -0,0 +1,22 @@ +import { SpotClient } from '@siebly/kraken-api'; +// or, if require is preferred: +// const { SpotClient } = require('@siebly/kraken-api'); + +// This example shows how to call this Kraken API endpoint with either node.js, javascript (js) or typescript (ts) with the npm module "@siebly/kraken-api" for Kraken exchange +// This Kraken API SDK is available on npm via "npm install @siebly/kraken-api" +// ENDPOINT: 0/public/GroupedBook +// METHOD: GET +// PUBLIC: YES + +const client = new SpotClient({ + apiKey: 'insert_api_key_here', + apiSecret: 'insert_api_secret_here', +}); + +client.getGroupedBook(params) + .then((response) => { + console.log(response); + }) + .catch((error) => { + console.error(error); + }); diff --git a/examples/apidoc/SpotClient/getLevel3OrderBook.js b/examples/apidoc/SpotClient/getLevel3OrderBook.js new file mode 100644 index 0000000..ad8e7ae --- /dev/null +++ b/examples/apidoc/SpotClient/getLevel3OrderBook.js @@ -0,0 +1,22 @@ +import { SpotClient } from '@siebly/kraken-api'; +// or, if require is preferred: +// const { SpotClient } = require('@siebly/kraken-api'); + +// This example shows how to call this Kraken API endpoint with either node.js, javascript (js) or typescript (ts) with the npm module "@siebly/kraken-api" for Kraken exchange +// This Kraken API SDK is available on npm via "npm install @siebly/kraken-api" +// ENDPOINT: 0/private/Level3 +// METHOD: POST +// PUBLIC: NO + +const client = new SpotClient({ + apiKey: 'insert_api_key_here', + apiSecret: 'insert_api_secret_here', +}); + +client.getLevel3OrderBook(params) + .then((response) => { + console.log(response); + }) + .catch((error) => { + console.error(error); + }); diff --git a/llms.txt b/llms.txt index b77f689..45b8e27 100644 --- a/llms.txt +++ b/llms.txt @@ -1678,6 +1678,187 @@ export interface WsConnectionInfo { instanceServers: WsServerInfo[]; } +================ +File: src/types/response/wsapi.types.ts +================ +/** + * Websocket API v2 Spot Response Types + */ +⋮---- +export interface WSAPIAddSpotOrderResult { + order_id: string; + cl_ord_id?: string; + order_userref?: number; + warnings?: string[]; +} +⋮---- +export interface WSAPIAmendSpotOrderResult { + amend_id: string; + order_id?: string; + cl_ord_id?: string; + warnings?: string[]; +} +⋮---- +export interface WSAPICancelSpotOrderResult { + order_id: string; + cl_ord_id?: string; + warnings?: string[]; +} +⋮---- +export interface WSAPICancelAllSpotOrdersResult { + count: number; + warnings?: string[]; +} +⋮---- +export interface WSAPICancelAllSpotOrdersAfterResult { + currentTime: string; + triggerTime: string; + warnings?: string[]; +} +⋮---- +export interface WSAPIBatchAddSpotOrdersResult { + order_id: string; + cl_ord_id?: string; + order_userref?: number; + warnings?: string[]; +} +⋮---- +export interface WSAPIBatchCancelSpotOrdersResult { + count: number; + warnings?: string[]; +} +⋮---- +export interface WSAPIEditSpotOrderResult { + order_id: string; + original_order_id: string; + warnings?: string[]; +} + +================ +File: src/types/websockets/ws-api.ts +================ +import { WS_KEY_MAP, WSOperation } from '../../lib/websocket/websocket-util.js'; +import { + WSAPIAddSpotOrderParams, + WSAPIAmendSpotOrderParams, + WSAPIBatchAddSpotOrdersParams, + WSAPIBatchCancelSpotOrdersParams, + WSAPICancelAllSpotOrdersAfterParams, + WSAPICancelSpotOrderParams, + WSAPIEditSpotOrderParams, +} from '../request/wsapi.types.js'; +import { + WSAPIAddSpotOrderResult, + WSAPIAmendSpotOrderResult, + WSAPIBatchAddSpotOrdersResult, + WSAPIBatchCancelSpotOrdersResult, + WSAPICancelAllSpotOrdersAfterResult, + WSAPICancelAllSpotOrdersResult, + WSAPICancelSpotOrderResult, + WSAPIEditSpotOrderResult, +} from '../response/wsapi.types.js'; +⋮---- +export type Exact = { + // This part says: if there's any key that's not in T, it's an error + // This conflicts sometimes for some reason... + // [K: string]: never; +} & { + [K in keyof T]: T[K]; +}; +⋮---- +// This part says: if there's any key that's not in T, it's an error +// This conflicts sometimes for some reason... +// [K: string]: never; +⋮---- +export interface WsRequestOperation { + id: number; + type: WSOperation; + topic: TWSTopic; + privateChannel: boolean; + response: boolean; +} +⋮---- +export interface WSAPIAuthenticationRequestFromServer { + timestamp: number; + sessionId: string; +} +⋮---- +export interface WSAPIAuthenticationConfirmedFromServer { + pingInterval: number; + sessionId: string; + pingTimeout: number; + data: 'welcome'; +} +⋮---- +/** + * WS API commands (for sending requests via WS) + */ +⋮---- +export type WSAPIOperation = (typeof WS_API_Operations)[number]; +⋮---- +export interface WSAPIRequestOperationKrakenSpot< + TWSOperation extends WSAPIOperation = WSAPIOperation, + TWSParams extends object = any, +> { + method: TWSOperation; + params?: TWSParams; + req_id: number; +} +⋮---- +export interface WSAPIWsKeyTopicMap { + [WS_KEY_MAP.spotPrivateV2]: WSAPIOperation; + [WS_KEY_MAP.spotBetaPrivateV2]: WSAPIOperation; +} +⋮---- +export type WSAPIWsKey = keyof WSAPIWsKeyTopicMap; +⋮---- +export interface WSAPISpotResponse< + TResponseData extends object = object, + TWSAPIOperation = WSAPIOperation, +> { + wsKey: WSAPIWsKey; + error?: string; + method: TWSAPIOperation; + req_id: number; + success: boolean; + time_in: string; + time_out: string; + result: TResponseData; + request: any; +} +⋮---- +export interface WSAPITopicRequestParamMap { + [key: string]: unknown; + + add_order: WSAPIAddSpotOrderParams; + amend_order: WSAPIAmendSpotOrderParams; + cancel_order: WSAPICancelSpotOrderParams; + cancel_all: never; + cancel_all_orders_after: WSAPICancelAllSpotOrdersAfterParams; + batch_add: WSAPIBatchAddSpotOrdersParams; + batch_cancel: WSAPIBatchCancelSpotOrdersParams; + edit_order: WSAPIEditSpotOrderParams; +} +⋮---- +export interface WSAPITopicResponseMap { + [k: string]: unknown; + + add_order: WSAPISpotResponse; + amend_order: WSAPISpotResponse; + cancel_order: WSAPISpotResponse; + cancel_all: WSAPISpotResponse; + cancel_all_orders_after: WSAPISpotResponse< + WSAPICancelAllSpotOrdersAfterResult, + 'cancel_all_orders_after' + >; + batch_add: WSAPISpotResponse; + batch_cancel: WSAPISpotResponse< + WSAPIBatchCancelSpotOrdersResult, + 'batch_cancel' + >; + edit_order: WSAPISpotResponse; +} + ================ File: src/types/websockets/ws-events.ts ================ @@ -1696,62 +1877,292 @@ export interface MessageEventLike { export function isMessageEvent(msg: unknown): msg is MessageEventLike ================ -File: src/index.ts -================ - - -================ -File: .eslintrc.cjs -================ -// 'no-unused-vars': ['warn'], - -================ -File: .nvmrc -================ -v22.21.0 - -================ -File: .prettierrc +File: src/types/websockets/ws-subscriptions.ts ================ -{ - "tabWidth": 2, - "singleQuote": true +] as const; // Note: Admin topics (Status, Heartbeat & Ping are automatically used internally and can't be subscribed to manually). +⋮---- +export type WSSpotPublicTopic = (typeof WS_SPOT_PUBLIC_TOPICS)[number]; +⋮---- +export type WSSpotPrivateTopic = (typeof WS_SPOT_PRIVATE_TOPICS)[number]; +⋮---- +export type WSSpotTopic = WSSpotPublicTopic | WSSpotPrivateTopic; +⋮---- +export type WSDerivativesPublicTopic = + (typeof WS_DERIVATIVES_PUBLIC_TOPICS)[number]; +⋮---- +export type WSDerivativesPrivateTopic = + (typeof WS_DERIVATIVES_PRIVATE_TOPICS)[number]; +⋮---- +export type WSDerivativesTopic = + | WSDerivativesPublicTopic + | WSDerivativesPrivateTopic; +⋮---- +export type WSTopic = WSSpotTopic | WSDerivativesTopic; +⋮---- +export interface WSSpotInstrumentSubscribeParams { + execution_venue?: 'international' | 'bitnomial-exchange'; + snapshot?: boolean; +} +⋮---- +export interface WSSpotExecutionsSubscribeParams { + symbol?: string[]; + snap_trades?: boolean; + snapshot?: boolean; + rebased?: boolean; +} +⋮---- +export interface WSSpotBalancesSubscribeParams { + snapshot?: boolean; + rebased?: boolean; } ================ -File: LICENSE.md +File: src/index.ts ================ -Copyright 2025 Tiago Siebler - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================ -File: postBuild.sh -================ -#!/bin/bash -# -# Add package.json files to cjs/mjs subtrees -# - -cat >dist/cjs/package.json <dist/mjs/package.json <, + logger?: DefaultLogger, +) +⋮---- +public getWSClient(): WebsocketClient +⋮---- +/** + * Add a spot order + */ +submitSpotOrder( + params: Omit, + wsKey?: WSAPIWsKey, +): Promise> +⋮---- +/** + * Amend an existing order + */ +amendSpotOrder( + params: WSAPIAmendSpotOrderParams, + wsKey?: WSAPIWsKey, +): Promise> +⋮---- +/** + * Cancel one or more orders + */ +cancelSpotOrder( + params: WSAPICancelSpotOrderParams, + wsKey?: WSAPIWsKey, +): Promise> +⋮---- +/** + * Cancel all open orders + */ +cancelAllSpotOrders( + wsKey?: WSAPIWsKey, +): Promise> +⋮---- +/** + * Cancel all orders after a timeout (Dead Man's Switch) + */ +cancelAllSpotOrdersAfter( + params: WSAPICancelAllSpotOrdersAfterParams, + wsKey?: WSAPIWsKey, + ): Promise< + WSAPISpotResponse< + WSAPICancelAllSpotOrdersAfterResult, + 'cancel_all_orders_after' + > + > { + return this.wsClient.sendWSAPIRequest( + wsKey || WS_KEY_MAP.spotPrivateV2, + 'cancel_all_orders_after', + params, + ); +⋮---- +/** + * Add multiple orders in a single batch (2-15 orders) + */ +batchSubmitSpotOrders( + params: WSAPIBatchAddSpotOrdersParams, + wsKey?: WSAPIWsKey, +): Promise> +⋮---- +/** + * Cancel multiple orders in a single batch (2-50 orders) + */ +batchCancelSpotOrders( + params: WSAPIBatchCancelSpotOrdersParams, + wsKey?: WSAPIWsKey, + ): Promise< + WSAPISpotResponse + > { + return this.wsClient.sendWSAPIRequest( + wsKey || WS_KEY_MAP.spotPrivateV2, + 'batch_cancel', + params, + ); +⋮---- +/** + * Edit an existing order (legacy method, use amendSpotOrder instead) + * @deprecated Use amendSpotOrder for better performance and features + */ +editSpotOrder( + params: WSAPIEditSpotOrderParams, + wsKey?: WSAPIWsKey, +): Promise> +/** + * + * + * + * + * + * + * + * Private methods for handling some of the convenience/automation provided by the WS API Client + * + * + * + * + * + * + * + */ +⋮---- +public connectWSAPI(wsKey: WSAPIWsKey) +⋮---- +private setupDefaultEventListeners() +⋮---- +/** + * General event handlers for monitoring the WebsocketClient + */ +⋮---- +// Blind JSON.stringify can fail on circular references +⋮---- +// JSON.stringify({ ...data, target: 'WebSocket' }), + +================ +File: .eslintrc.cjs +================ +// 'no-unused-vars': ['warn'], + +================ +File: .nvmrc +================ +v22.21.0 + +================ +File: .prettierrc +================ +{ + "tabWidth": 2, + "singleQuote": true +} + +================ +File: LICENSE.md +================ +Copyright 2025 Tiago Siebler + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +================ +File: postBuild.sh +================ +#!/bin/bash +# +# Add package.json files to cjs/mjs subtrees +# + +cat >dist/cjs/package.json <dist/mjs/package.json <; - language?: string; // ISO 639-1 language code +import { + isMessageEvent, + MessageEventLike, +} from '../types/websockets/ws-events.js'; +import { + WebsocketClientOptions, + WSClientConfigurableOptions, + WsEventInternalSrc, +} from '../types/websockets/ws-general.js'; +import { WSTopic } from '../types/websockets/ws-subscriptions.js'; +import { checkWebCryptoAPISupported } from './webCryptoAPI.js'; +import { DefaultLogger } from './websocket/logger.js'; +import { + getNormalisedTopicRequests, + safeTerminateWs, + WSOperation, + WSTopicRequest, + WSTopicRequestOrStringTopic, +} from './websocket/websocket-util.js'; +import { WsStore } from './websocket/WsStore.js'; +import { + WSConnectedResult, + WsConnectionStateEnum, +} from './websocket/WsStore.types.js'; +⋮---- +type UseTheExceptionEventInstead = never; +⋮---- +interface WSClientEventMap { + /** Connection opened. If this connection was previously opened and reconnected, expect the reconnected event instead */ + open: (evt: { + wsKey: WsKey; + event: any; + wsUrl: string; + ws: WebSocket; + }) => void; + + /** Reconnecting a dropped connection */ + reconnecting: (evt: { wsKey: WsKey; event: any }) => void; + + /** Successfully reconnected a connection that dropped */ + reconnected: (evt: { + wsKey: WsKey; + event: any; + wsUrl: string; + ws: WebSocket; + }) => void; + + /** Connection closed */ + close: (evt: { wsKey: WsKey; event: any }) => void; + + /** Received reply to websocket command (e.g. after subscribing to topics) */ + response: (response: any & { wsKey: WsKey }) => void; + + /** Received data for topic */ + message: (response: any & { wsKey: WsKey }) => void; + + /** Exception from ws client OR custom listeners (e.g. if you throw inside your event handler) */ + exception: (response: any & { wsKey: WsKey }) => void; + + /** + * See for more information: https://github.com/tiagosiebler/bybit-api/issues/413 + * @deprecated Use the 'exception' event instead. The 'error' event had the unintended consequence of throwing an unhandled promise rejection. + */ + error: UseTheExceptionEventInstead; + + /** Confirmation that a connection successfully authenticated */ + authenticated: (event: { wsKey: WsKey; event: any }) => void; } ⋮---- -date_of_birth: string; // format: date (YYYY-MM-DD) +/** Connection opened. If this connection was previously opened and reconnected, expect the reconnected event instead */ ⋮---- -country: string; // CountryCode +/** Reconnecting a dropped connection */ ⋮---- -phone: string; // E.164 format -nationalities: string[]; // CountryCode[] +/** Successfully reconnected a connection that dropped */ ⋮---- -country_of_birth?: string; // CountryCode +/** Connection closed */ ⋮---- -issuing_country: string; // CountryCode +/** Received reply to websocket command (e.g. after subscribing to topics) */ ⋮---- -language?: string; // ISO 639-1 language code +/** Received data for topic */ +⋮---- +/** Exception from ws client OR custom listeners (e.g. if you throw inside your event handler) */ ⋮---- /** - * Update User request parameters - */ -export interface PartnerUpdateUserParams { - user: string; - tos_version_accepted?: number; - full_name?: { - first_name: string; - middle_name?: string; - last_name: string; - }; - date_of_birth?: string; // format: date (YYYY-MM-DD) - city_of_birth?: string; - country_of_birth?: string; // CountryCode - residence?: { - line1: string; - line2?: string; - city: string; - postal_code: string; - province?: string; - country: string; // CountryCode - }; - phone?: string; // E.164 format - nationalities?: string[]; // CountryCode[] - tax_ids?: Array<{ - id: string; - issuing_country: string; // CountryCode - }>; - occupation?: - | 'agriculture' - | 'business_management' - | 'computers_and_it' - | 'construction' - | 'education' - | 'finance' - | 'government' - | 'healthcare' - | 'hospitality' - | 'manufacturing' - | 'marketing' - | 'media' - | 'other' - | 'science' - | 'self_employed' - | 'student' - | 'transportation' - | 'unemployed'; - language?: string; // ISO 639-1 language code -} + * See for more information: https://github.com/tiagosiebler/bybit-api/issues/413 + * @deprecated Use the 'exception' event instead. The 'error' event had the unintended consequence of throwing an unhandled promise rejection. + */ ⋮---- -date_of_birth?: string; // format: date (YYYY-MM-DD) +/** Confirmation that a connection successfully authenticated */ ⋮---- -country_of_birth?: string; // CountryCode +export interface EmittableEvent< + TEventType extends + keyof WSClientEventMap = keyof WSClientEventMap, +> { + eventType: + | TEventType + | 'pong' + | 'connectionReady' // tied to "requireConnectionReadyConfirmation"; + | 'connectionReadyForAuth'; // tied to specific events we need to wait for, before we can begin post-connect auth + event: Parameters[TEventType]>[0]; + isWSAPIResponse?: boolean; +} ⋮---- -country: string; // CountryCode +| 'connectionReady' // tied to "requireConnectionReadyConfirmation"; +| 'connectionReadyForAuth'; // tied to specific events we need to wait for, before we can begin post-connect auth ⋮---- -phone?: string; // E.164 format -nationalities?: string[]; // CountryCode[] +// Type safety for on and emit handlers: https://stackoverflow.com/a/61609010/880837 +export interface BaseWebsocketClient< + TWSKey extends string, + TWSRequestEvent extends object, +> { + on>( + event: U, + listener: WSClientEventMap[U], + ): this; + + emit>( + event: U, + ...args: Parameters[U]> + ): boolean; +} ⋮---- -issuing_country: string; // CountryCode +on>( + event: U, + listener: WSClientEventMap[U], + ): this; ⋮---- -language?: string; // ISO 639-1 language code +emit>( + event: U, + ...args: Parameters[U]> + ): boolean; ⋮---- /** - * Submit Verification request parameters + * A midflight WS request event (e.g. subscribe to these topics). + * + * - requestKey: unique identifier for this request, if available. Can be anything as a string. + * - requestEvent: the raw request, as an object, that will be sent on the ws connection. This may contain multiple topics/requests in one object, if the exchange supports it. */ -export interface PartnerSubmitVerificationParams { - user: string; - type: 'identity_document'; - metadata: { - identity: { - full_name: { - first_name: string; - middle_name?: string; - last_name: string; - }; - date_of_birth: string; // format: date (YYYY-MM-DD) - }; - document_type: - | 'passport' - | 'drivers_license' - | 'id_card' - | 'residence_card' - | 'special_permanent_residence_card'; - document_number: string; - issuing_country: string; // CountryCode - nationality?: string; // CountryCode - }; - verifier: string; // Name of the verification provider - verified_at: string; // ISO 8601 datetime - verifier_response?: any; - external_verification_id?: string; - expiration_date?: string; // ISO 8601 date - front: any; // File binary for front side of document - back: any; // File binary for back side of document - verifier_response_file?: any; // File binary for verifier response +export interface MidflightWsRequestEvent { + requestKey: string | number; + requestEvent: TEvent; } ⋮---- -date_of_birth: string; // format: date (YYYY-MM-DD) -⋮---- -issuing_country: string; // CountryCode -nationality?: string; // CountryCode -⋮---- -verifier: string; // Name of the verification provider -verified_at: string; // ISO 8601 datetime -⋮---- -expiration_date?: string; // ISO 8601 date -front: any; // File binary for front side of document -back: any; // File binary for back side of document -verifier_response_file?: any; // File binary for verifier response -⋮---- /** - * List Assets request parameters + * Appends wsKey and isWSAPIResponse to all events. + * Some events are arrays, this handles that nested scenario too. */ -export interface PartnerListAssetsParams { - 'filter[user]'?: string; // IIBAN - 'filter[assets][]'?: string[]; // AssetName[], max 100 - 'filter[platform_statuses][]'?: Array< - | 'enabled' - | 'deposit_only' - | 'withdrawal_only' - | 'funding_temporarily_disabled' - | 'disabled' - >; - 'filter[tradable_only]'?: boolean; - sort?: - | 'trending' - | 'market_cap_rank' - | '-market_cap_rank' - | 'symbol' - | '-symbol' - | 'name' - | '-name' - | 'change_percent_1h' - | '-change_percent_1h' - | 'change_percent_24h' - | '-change_percent_24h' - | 'change_percent_7d' - | '-change_percent_7d' - | 'change_percent_30d' - | '-change_percent_30d' - | 'change_percent_1y' - | '-change_percent_1y' - | 'listing_date' - | '-listing_date'; - 'page[size]'?: number; // 1-100 - 'page[number]'?: number; // >= 1 - quote?: string; // AssetName, default USD - lang?: string; // ISO language code, default en -} -⋮---- -'filter[user]'?: string; // IIBAN -'filter[assets][]'?: string[]; // AssetName[], max 100 +function getFinalEmittable( + emittable: EmittableEvent | EmittableEvent[], + wsKey: any, + isWSAPIResponse?: boolean, +): any ⋮---- -'page[size]'?: number; // 1-100 -'page[number]'?: number; // >= 1 -quote?: string; // AssetName, default USD -lang?: string; // ISO language code, default en +// Some topics just emit an array. +// This is consistent with how it was before the WS API upgrade: ⋮---- -/** - * Get Asset request parameters - */ -export interface PartnerGetAssetParams { - asset: string; - quote?: string; // AssetName, default USD - lang?: string; // ISO language code, default en -} +// const { event, ...others } = emittable; +// return { +// ...others, +// event: event.map((subEvent) => +// getFinalEmittable(subEvent, wsKey, isWSAPIResponse), +// ), +// }; ⋮---- -quote?: string; // AssetName, default USD -lang?: string; // ISO language code, default en +// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging +export abstract class BaseWebsocketClient< +TWSKey extends string, ⋮---- -/** - * List Asset Rates request parameters - */ -export interface PartnerListAssetRatesParams { - asset: string; - quote?: string; // AssetName, default USD - start_time?: string; // RFC 3339 datetime - end_time?: string; // RFC 3339 datetime - interval?: string; // ISO 8601 duration (PT15M, PT60M, P1D, etc.) -} +constructor( + options?: WSClientConfigurableOptions & { wsLoggerCategory: string }, + logger?: DefaultLogger, +) ⋮---- -quote?: string; // AssetName, default USD -start_time?: string; // RFC 3339 datetime -end_time?: string; // RFC 3339 datetime -interval?: string; // ISO 8601 duration (PT15M, PT60M, P1D, etc.) +// Requires a confirmation "response" from the ws connection before assuming it is ready ⋮---- -/** - * Request Quote request parameters - */ -export interface PartnerRequestQuoteParams { - user: string; // IIBAN - type: 'receive' | 'spend'; // Type of quote - amount: { - asset_class?: 'currency'; - asset: string; // AssetName - amount: string; // decimal128 - }; - quote: { - asset: string; // AssetName - }; - fee_bps: string; // Basis points - spread_bps: string; // Basis points - quote_currency?: string; // AssetName -} +// Automatically auth after opening a connection? ⋮---- -user: string; // IIBAN -type: 'receive' | 'spend'; // Type of quote +// Automatically include auth/sign/token with every WS request. +// Automatically handled during getWsRequestEvents. ⋮---- -asset: string; // AssetName -amount: string; // decimal128 +// Automatically re-auth WS API, if we were auth'd before and get reconnected ⋮---- -asset: string; // AssetName +// Whether to use native heartbeats (depends on the exchange) ⋮---- -fee_bps: string; // Basis points -spread_bps: string; // Basis points -quote_currency?: string; // AssetName +// Check Web Crypto API support when credentials are provided and no custom sign function is used ⋮---- /** - * Get Quote request parameters - */ -export interface PartnerGetQuoteParams { - quote_id: string; - user: string; // IIBAN -} -⋮---- -user: string; // IIBAN + * Return true if this wsKey connection should automatically authenticate immediately after connecting + */ +protected abstract isAuthOnConnectWsKey(wsKey: TWSKey): boolean; ⋮---- -/** - * Execute Quote request parameters - */ -export interface PartnerExecuteQuoteParams { - quote_id: string; - user: string; // IIBAN -} +protected abstract isCustomReconnectionNeeded(wsKey: TWSKey): boolean; ⋮---- -user: string; // IIBAN +protected abstract triggerCustomReconnectionWorkflow( + wsKey: TWSKey, + ): Promise; ⋮---- -/** - * Get Portfolio Summary request parameters - */ -export interface PartnerGetPortfolioSummaryParams { - user: string; // IIBAN - quote?: string; // AssetName, default USD - 'include[current_day_pnl]'?: any; // Include the current day pnl -} +protected abstract sendPingEvent(wsKey: TWSKey, ws: WebSocket): void; ⋮---- -user: string; // IIBAN -quote?: string; // AssetName, default USD -'include[current_day_pnl]'?: any; // Include the current day pnl +protected abstract sendPongEvent(wsKey: TWSKey, ws: WebSocket): void; ⋮---- -/** - * Get Portfolio History request parameters - */ -export interface PartnerGetPortfolioHistoryParams { - user: string; // IIBAN - 'include[assets][]'?: string[]; // AssetName[] - 'include[total_balance]'?: boolean; - 'include[total_pnl]'?: boolean; - start_date?: string; // date format - end_date?: string; // date format - resolution?: number; // uint32, default 1 - quote?: string; // AssetName, default USD - cursor?: string; // Pagination cursor -} +protected abstract isWsPing(data: any): boolean; ⋮---- -user: string; // IIBAN -'include[assets][]'?: string[]; // AssetName[] +protected abstract isWsPong(data: any): boolean; ⋮---- -start_date?: string; // date format -end_date?: string; // date format -resolution?: number; // uint32, default 1 -quote?: string; // AssetName, default USD -cursor?: string; // Pagination cursor +protected abstract authPrivateConnectionsOnConnect(_wsKey: TWSKey): boolean; ⋮---- /** - * List Portfolio Details request parameters - */ -export interface PartnerListPortfolioDetailsParams { - user: string; // IIBAN - quote?: string; // AssetName, default USD -} + * Return the event sent to the server to trigger authentication. If the event requires waiting for another event first (e.g. a challenge), return 'waitForEvent' and the library will wait for that event before calling this method again. + * + * Usually only called once per connection, unless the connection drops/is reset. + */ +protected abstract getWsAuthRequestEvent( + wsKey: TWSKey, + eventToAuth?: object, + ): Promise; ⋮---- -user: string; // IIBAN -quote?: string; // AssetName, default USD +protected abstract isPrivateTopicRequest( + request: WSTopicRequest, + wsKey: TWSKey, + ): boolean; ⋮---- /** - * List Portfolio Transactions request parameters - */ -export interface PartnerListPortfolioTransactionsParams { - user: string; // IIBAN - cursor?: string; - types?: Array<'simple_order' | 'simple_order_failed' | 'earn_reward'>; - page_size?: number; // uint64 - assets?: string[]; // AssetName[], max 16 chars each - from_time?: string; // date-time - until_time?: string; // date-time - statuses?: Array< - 'no_status' | 'unspecified' | 'in_progress' | 'successful' | 'failed' - >; - ids?: string[]; - sorting?: 'descending' | 'ascending'; - ref_ids?: any[]; // Simplified - array of reference ID filter objects - quote?: string; // AssetName, max 16 chars -} + * Returns a list of string events that can be individually sent upstream to complete subscribing/unsubscribing/etc to these topics + */ +// protected abstract getWsOperationEventsForTopics( +// topics: WsTopicRequest[], +// wsKey: TWSKey, +// operation: WsOperation, +// ): Promise; ⋮---- -user: string; // IIBAN +protected abstract getPrivateWSKeys(): TWSKey[]; ⋮---- -page_size?: number; // uint64 -assets?: string[]; // AssetName[], max 16 chars each -from_time?: string; // date-time -until_time?: string; // date-time +protected abstract getWsUrl(wsKey: TWSKey): Promise; ⋮---- -ref_ids?: any[]; // Simplified - array of reference ID filter objects -quote?: string; // AssetName, max 16 chars +protected abstract getMaxTopicsPerSubscribeEvent( + wsKey: TWSKey, + ): number | null; ⋮---- /** - * Get Earn Summary request parameters - */ -export interface PartnerGetEarnSummaryParams { - user: string; // IIBAN - currency?: string; // max 16 chars -} -⋮---- -user: string; // IIBAN -currency?: string; // max 16 chars + * @returns one or more correctly structured request events for performing a operations over WS. This can vary per exchange spec. + */ +protected abstract getWsRequestEvents( + wsKey: TWSKey, + operation: WSOperation, + requests: WSTopicRequest[], + ): Promise[]>; ⋮---- /** - * List Earn Assets request parameters - */ -export interface PartnerListEarnAssetsParams { - assets?: string[]; // AssetName[], max 16 chars each - user?: string; // IIBAN, 14-42 chars - currency?: string; // max 16 chars, required if user is set -} -⋮---- -assets?: string[]; // AssetName[], max 16 chars each -user?: string; // IIBAN, 14-42 chars -currency?: string; // max 16 chars, required if user is set + * Abstraction called to sort ws events into emittable event types (response to a request, data update, etc) + */ +protected abstract resolveEmittableEvents( + wsKey: TWSKey, + event: MessageEventLike, + ): EmittableEvent[]; ⋮---- /** - * Toggle Auto-Earn request parameters - */ -export interface PartnerToggleAutoEarnParams { - user: string; // IIBAN - want_enabled: boolean; -} + * Request connection of all dependent (public & private) websockets, instead of waiting for automatic connection by library + */ +protected abstract connectAll(): Promise[]; ⋮---- -user: string; // IIBAN +protected isPrivateWsKey(wsKey: TWSKey): boolean ⋮---- -/** - * Withdraw Funds request parameters - */ -export interface PartnerWithdrawFundsParams { - asset: string; // AssetName, 3-16 chars - key: string; // Withdrawal key - amount: string; // decimal128 -} +/** Returns auto-incrementing request ID, used to track promise references for async requests */ +protected getNewRequestId(): number ⋮---- -asset: string; // AssetName, 3-16 chars -key: string; // Withdrawal key -amount: string; // decimal128 +protected abstract sendWSAPIRequest( + wsKey: TWSKey, + operation: string, + params?: any, + ): Promise; ⋮---- -/** - * List Funding Transactions request parameters - */ -export interface PartnerListFundingTransactionsParams { - type: 'withdrawal' | 'deposit'; - cursor?: string; - page_size?: number; // uint32, 1-500, default 25 -} +protected abstract sendWSAPIRequest( + wsKey: TWSKey, + channel: string, + params: any, + ): Promise; ⋮---- -page_size?: number; // uint32, 1-500, default 25 +public getTimeOffsetMs() +⋮---- +public setTimeOffsetMs(newOffset: number) ⋮---- /** - * List Settlement Reports request parameters - */ -export interface PartnerListSettlementReportsParams { - 'filter[start_date]'?: string; // RFC 3339 datetime - 'filter[end_date]'?: string; // RFC 3339 datetime - 'filter[report_type][]'?: Array<'trades' | 'transfers' | 'earn_rewards'>; - 'page[size]'?: number; // uint32, 1-100, default 20 - 'page[number]'?: number; // uint32, >= 1, default 1 -} + * Don't call directly! Use subscribe() instead! + * + * Subscribe to one or more topics on a WS connection (identified by WS Key). + * + * - Topics are automatically cached + * - Connections are automatically opened, if not yet connected + * - Authentication is automatically handled + * - Topics are automatically resubscribed to, if something happens to the connection, unless you call unsubsribeTopicsForWsKey(topics, key). + * + * @param wsTopicRequests array of topics to subscribe to + * @param wsKey ws key referring to the ws connection these topics should be subscribed on + */ +protected async subscribeTopicsForWsKey( + wsTopicRequests: WSTopicRequestOrStringTopic[], + wsKey: TWSKey, +) ⋮---- -'filter[start_date]'?: string; // RFC 3339 datetime -'filter[end_date]'?: string; // RFC 3339 datetime +// Store topics, so future automation (post-auth, post-reconnect) has everything needed to resubscribe automatically ⋮---- -'page[size]'?: number; // uint32, 1-100, default 20 -'page[number]'?: number; // uint32, >= 1, default 1 +// start connection process if it hasn't yet begun. Topics are automatically subscribed to on-connect ⋮---- -/** - * Get Settlement Report request parameters - */ -export interface PartnerGetSettlementReportParams { - id: string; -} +// Subscribe should happen automatically once connected, nothing to do here after topics are added to wsStore. ⋮---- /** - * Get Ramp Limits request parameters - */ -export interface PartnerGetRampLimitsParams { - in_asset: string; // max 16 chars - out_asset: string; // max 16 chars - funding_type: string; - withdrawal_method: string; -} + * Are we in the process of connection? Nothing to send yet. + */ ⋮---- -in_asset: string; // max 16 chars -out_asset: string; // max 16 chars +// We're connected. Check if auth is needed and if already authenticated ⋮---- /** - * Get Ramp Prospective Quote request parameters - */ -export interface PartnerGetRampProspectiveQuoteParams { - in_asset: string; // max 16 chars - in_amount: string; // decimal128 - out_asset: string; // max 16 chars - funding_type: string; - withdrawal_method: string; -} -⋮---- -in_asset: string; // max 16 chars -in_amount: string; // decimal128 -out_asset: string; // max 16 chars + * If not authenticated yet and auth is required, don't request topics yet. + * + * Auth should already automatically be in progress, so no action needed from here. Topics will automatically subscribe post-auth success. + */ ⋮---- -/** - * Embed Custom Orders - Create Custom Order request parameters - * Price-triggered custom orders. User in query, body has trigger, action, name. - */ -export interface PartnerCreateCustomOrderParams { - user: string; // IIBAN, 14-42 chars - trigger: { - type: 'price'; - base_asset: string; // <= 16 chars - quote_asset: string; // <= 16 chars - target_price: string; - condition: 'gte' | 'lte'; - }; - action: { - type: 'receive' | 'spend'; - amount: { - asset_class?: 'currency'; - asset: string; // <= 16 chars - amount: string; - }; - quote: { - asset: string; // <= 16 chars - fee_bps: string; // 1-5 digits - spread_bps: string; // 1-5 digits - }; - }; - name: string; -} +// Finally, request subscription to topics if the connection is healthy and ready ⋮---- -user: string; // IIBAN, 14-42 chars +protected async unsubscribeTopicsForWsKey( + wsTopicRequests: WSTopicRequestOrStringTopic[], + wsKey: TWSKey, +): Promise ⋮---- -base_asset: string; // <= 16 chars -quote_asset: string; // <= 16 chars +// Store topics, so future automation (post-auth, post-reconnect) has everything needed to resubscribe automatically ⋮---- -asset: string; // <= 16 chars +// If not connected, don't need to do anything. +// Removing the topic from the store is enough to stop it from being resubscribed to on reconnect. ⋮---- -asset: string; // <= 16 chars -fee_bps: string; // 1-5 digits -spread_bps: string; // 1-5 digits +// We're connected. Check if auth is needed and if already authenticated ⋮---- /** - * Embed Custom Orders - List Custom Orders request parameters - */ -export interface PartnerListCustomOrdersParams { - user: string; // IIBAN, 14-42 chars - statuses?: Array<'active' | 'cancelled' | 'completed'>; - cursor?: string; -} + * If not authenticated yet and auth is required, don't need to do anything. + * We don't subscribe to topics until auth is complete anyway. + */ ⋮---- -user: string; // IIBAN, 14-42 chars +// Finally, request subscription to topics if the connection is healthy and ready ⋮---- /** - * Embed Custom Orders - Get Custom Order request parameters - */ -export interface PartnerGetCustomOrderParams { - user: string; // IIBAN, 14-42 chars - order_id: string; -} + * Splits topic requests into two groups, public & private topic requests + */ +private sortTopicRequestsIntoPublicPrivate( + wsTopicRequests: WSTopicRequest[], + wsKey: TWSKey, +): ⋮---- -user: string; // IIBAN, 14-42 chars +/** Get the WsStore that tracks websockets & topics */ +public getWsStore(): WsStore> ⋮---- -/** - * Embed Custom Orders - Cancel Custom Order request parameters - */ -export interface PartnerCancelCustomOrderParams { - user: string; // IIBAN, 14-42 chars - id: string; // order id -} +public close(wsKey: TWSKey, force?: boolean) ⋮---- -user: string; // IIBAN, 14-42 chars -id: string; // order id +public closeAll(force?: boolean) +⋮---- +public isConnected(wsKey: TWSKey): boolean ⋮---- /** - * Embed Quotes (RFQ) - Get Quote Limits request parameters - */ -export interface PartnerGetQuoteLimitsParams { - user: string; // IIBAN, 14-42 chars - base_asset: string; // <= 16 chars - quote_asset: string; // <= 16 chars - type: 'receive' | 'spend'; - quote_currency?: string; // <= 16 chars -} + * Request connection to a specific websocket, instead of waiting for automatic connection. + */ +public async connect( + wsKey: TWSKey, + customUrl?: string | undefined, + throwOnError?: boolean, +): Promise ⋮---- -user: string; // IIBAN, 14-42 chars -base_asset: string; // <= 16 chars -quote_asset: string; // <= 16 chars +// Important: don't check for RECONNECTING here, or this clashes with reconnectWithDelay()! ⋮---- -quote_currency?: string; // <= 16 chars +private connectToWsUrl(url: string, wsKey: TWSKey): WebSocket ⋮---- -/** - * Embed Quotes (RFQ) - Request Prospective Quote request parameters - */ -export interface PartnerRequestProspectiveQuoteParams { - user: string; // IIBAN, 14-42 chars - action: { - type: 'receive' | 'spend'; - amount: { - asset_class?: 'currency'; - asset: string; // <= 16 chars - amount: string; - }; - quote: { - asset: string; // <= 16 chars - fee_bps: string; // 1-5 digits - spread_bps: string; // 1-5 digits - }; - }; - trigger?: { - type: 'price'; - base_asset: string; - quote_asset: string; - target_price: string; - condition: 'gte' | 'lte'; - }; - quote_currency?: string; // <= 16 chars -} +// ⋮---- -user: string; // IIBAN, 14-42 chars +private parseWsError(context: string, error: any, wsKey: TWSKey): boolean ⋮---- -asset: string; // <= 16 chars +// Allow retry by default (in some places that call this). Prevent deadloop in hard failure (401) ⋮---- -asset: string; // <= 16 chars -fee_bps: string; // 1-5 digits -spread_bps: string; // 1-5 digits +/** Get a signature, build the auth request and send it */ +private async sendAuthRequest( + wsKey: TWSKey, + eventToAuth?: object, +): Promise ⋮---- -quote_currency?: string; // <= 16 chars +// If not required, this won't return anything ⋮---- -/** - * Get Ramp Checkout URL request parameters - */ -export interface PartnerGetRampCheckoutUrlParams { - in_asset: string; // max 16 chars - in_amount: string; // decimal128 - out_asset: string; // max 16 chars - funding_type: string; - withdrawal_method: string; - country?: string; // max 2 chars, ISO 3166-1 alpha-2 - redirect_url?: string; // URI - network?: string; - external_user_id?: string; // max 36 chars - external_transaction_id?: string; // max 36 chars - external_metadata?: string; // max 1000 chars -} +// Short-circuit this for the next time it's called ⋮---- -in_asset: string; // max 16 chars -in_amount: string; // decimal128 -out_asset: string; // max 16 chars +private reconnectWithDelay(wsKey: TWSKey, connectionDelayMs: number) ⋮---- -country?: string; // max 2 chars, ISO 3166-1 alpha-2 -redirect_url?: string; // URI +// Some streams need a specialist reconnection workflow. +// E.g. the user data stream can't just be reconnected as is. +⋮---- +private ping(wsKey: TWSKey) ⋮---- -external_user_id?: string; // max 36 chars -external_transaction_id?: string; // max 36 chars -external_metadata?: string; // max 1000 chars - -================ -File: src/types/request/spot.types.ts -================ /** - * Market Data - */ + * Closes a connection, if it's even open. If open, this will trigger a reconnect asynchronously. + * If closed, trigger a reconnect immediately + */ +protected executeReconnectableClose(wsKey: TWSKey, reason: string) ⋮---- -export interface SpotGetAssetPairsParams { - pair?: string; - aclass_base?: 'currency' | 'tokenized_asset'; - info?: 'info' | 'leverage' | 'fees' | 'margin'; - country_code?: string; - execution_venue?: string; -} +private clearTimers(wsKey: TWSKey) ⋮---- -export interface SpotGetOHLCParams { - pair: string; - interval?: 1 | 5 | 15 | 30 | 60 | 240 | 1440 | 10080 | 21600; - since?: number; - asset_class?: 'tokenized_asset'; -} +// Send a ping at intervals +private clearPingTimer(wsKey: TWSKey) ⋮---- -export interface SpotGetOrderBookParams { - pair: string; - count?: number; - asset_class?: 'tokenized_asset'; -} +// Expect a pong within a time limit +private clearPongTimer(wsKey: TWSKey) ⋮---- -export interface SpotGetRecentTradesParams { - pair: string; - since?: string; - count?: number; - asset_class?: 'tokenized_asset'; -} +// this.logger.trace(`Cleared pong timeout for "${wsKey}"`); ⋮---- -export interface SpotGetRecentSpreadsParams { - pair: string; - since?: number; - asset_class?: 'tokenized_asset'; -} +// this.logger.trace(`No active pong timer for "${wsKey}"`); +⋮---- +private clearReconnectTimer(wsKey: TWSKey) ⋮---- /** - * Account Data - */ + * Returns a list of string events that can be individually sent upstream to complete subscribing/unsubscribing/etc to these topics + * + * If events are an object, these should be stringified (`return JSON.stringify(event);`) + * Each event returned by this will be sent one at a time + * + * Events are automatically split into smaller batches, by this method, if needed. + */ +protected async getWsOperationEventsForTopics( + topics: WSTopicRequest[], + wsKey: TWSKey, + operation: WSOperation, +): Promise[]> ⋮---- -export interface SpotGetOpenOrdersParams { - trades?: boolean; - userref?: number; - cl_ord_id?: string; - rebase_multiplier?: 'rebased' | 'base'; -} +// Events that are ready to send (usually stringified JSON) ⋮---- -export interface SpotGetClosedOrdersParams { - trades?: boolean; - userref?: number; - cl_ord_id?: string; - start?: number; - end?: number; - ofs?: number; - closetime?: 'open' | 'close' | 'both'; - consolidate_taker?: boolean; - without_count?: boolean; - rebase_multiplier?: 'rebased' | 'base'; -} +/** + * Simply builds and sends subscribe events for a list of topics for a ws key + * + * @private Use the `subscribe(topics)` or `subscribeTopicsForWsKey(topics, wsKey)` method to subscribe to topics. Send WS message to subscribe to topics. + */ +private async requestSubscribeTopics( + wsKey: TWSKey, + wsTopicRequests: WSTopicRequest[], +) ⋮---- -export interface SpotQueryOrdersParams { - trades?: boolean; - userref?: number; - txid: string; - consolidate_taker?: boolean; - rebase_multiplier?: 'rebased' | 'base'; -} +// Automatically splits requests into smaller batches, if needed ⋮---- -export interface SpotGetTradesHistoryParams { - type?: - | 'all' - | 'any position' - | 'closed position' - | 'closing position' - | 'no position'; - trades?: boolean; - start?: number; - end?: number; - ofs?: number; - consolidate_taker?: boolean; - ledgers?: boolean; - rebase_multiplier?: 'rebased' | 'base'; -} +`Subscribing to ${wsTopicRequests.length} "${wsKey}" topics in ${subscribeWsMessages.length} batches.`, // Events: "${JSON.stringify(topics)}" ⋮---- -export interface SpotQueryTradesParams { - txid: string; - trades?: boolean; - rebase_multiplier?: 'rebased' | 'base'; -} +// eslint-disable-next-line @typescript-eslint/no-unused-vars ⋮---- -export interface SpotGetOpenPositionsParams { - txid?: string; - docalcs?: boolean; - consolidation?: 'market'; - rebase_multiplier?: 'rebased' | 'base'; -} +/** + * Simply builds and sends unsubscribe events for a list of topics for a ws key + * + * @private Use the `unsubscribe(topics)` method to unsubscribe from topics. Send WS message to unsubscribe from topics. + */ +private async requestUnsubscribeTopics( + wsKey: TWSKey, + wsTopicRequests: WSTopicRequest[], +) ⋮---- -export interface SpotGetLedgersInfoParams { - asset?: string; - aclass?: string; - type?: - | 'all' - | 'trade' - | 'deposit' - | 'withdrawal' - | 'transfer' - | 'margin' - | 'adjustment' - | 'rollover' - | 'credit' - | 'settled' - | 'staking' - | 'dividend' - | 'sale' - | 'nft_rebate'; - start?: number; - end?: number; - ofs?: number; - without_count?: boolean; - rebase_multiplier?: 'rebased' | 'base'; -} +// eslint-disable-next-line @typescript-eslint/no-unused-vars ⋮---- -export interface SpotQueryLedgersParams { - id: string; - trades?: boolean; - rebase_multiplier?: 'rebased' | 'base'; -} +/** + * Try sending a string event on a WS connection (identified by the WS Key) + */ +public tryWsSend( + wsKey: TWSKey, + wsMessage: string, + throwExceptions?: boolean, +) ⋮---- -export interface SpotRequestExportReportParams { - report: 'trades' | 'ledgers'; - format?: 'CSV' | 'TSV'; - description: string; - fields?: string; - starttm?: number; - endtm?: number; -} +private async onWsOpen( + event: WebSocket.Event, + wsKey: TWSKey, + url: string, + ws: WebSocket, +) ⋮---- -/** - * Trading - */ +private resolveConnectionInProgressPromise(wsKey: TWSKey) ⋮---- -export interface SpotSubmitOrderParams { - userref?: number; - cl_ord_id?: string; - ordertype: - | 'market' - | 'limit' - | 'iceberg' - | 'stop-loss' - | 'take-profit' - | 'stop-loss-limit' - | 'take-profit-limit' - | 'trailing-stop' - | 'trailing-stop-limit' - | 'settle-position'; - type: 'buy' | 'sell'; - volume: string; - displayvol?: string; - pair: string; - asset_class?: 'tokenized_asset'; - price?: string; - price2?: string; - trigger?: 'index' | 'last'; - leverage?: string; - reduce_only?: boolean; - stptype?: 'cancel-newest' | 'cancel-oldest' | 'cancel-both'; - oflags?: string; - timeinforce?: 'GTC' | 'IOC' | 'GTD' | 'FOK'; - starttm?: string; - expiretm?: string; - 'close[ordertype]'?: string; - 'close[price]'?: string; - 'close[price2]'?: string; - deadline?: string; - validate?: boolean; -} +// Resolve & cleanup deferred "connection attempt in progress" promise ⋮---- -export interface SpotAmendOrderParams { - txid?: string; - cl_ord_id?: string; - order_qty?: string; - display_qty?: string; - limit_price?: string; - trigger_price?: string; - pair?: string; - post_only?: boolean; - deadline?: string; -} +/** + * Called automatically once a connection is ready. + * - Some exchanges are ready immediately after the connections open. + * - Some exchanges send an event to confirm the connection is ready for us. + * + * This method is called to act when the connection is ready. Use `requireConnectionReadyConfirmation` to control how this is called. + */ +private async onWsReadyForEvents(wsKey: TWSKey) ⋮---- -export interface SpotBatchOrderItem { - userref?: number; - cl_ord_id?: string; - ordertype: - | 'market' - | 'limit' - | 'iceberg' - | 'stop-loss' - | 'take-profit' - | 'stop-loss-limit' - | 'take-profit-limit' - | 'trailing-stop' - | 'trailing-stop-limit' - | 'settle-position'; - type: 'buy' | 'sell'; - volume: string; - displayvol?: string; - price?: string; - price2?: string; - trigger?: 'index' | 'last'; - leverage?: string; - reduce_only?: boolean; - stptype?: 'cancel-newest' | 'cancel-oldest' | 'cancel-both'; - oflags?: string; - timeinforce?: 'GTC' | 'IOC' | 'GTD' | 'FOK'; - starttm?: string; - expiretm?: string; - close?: { - ordertype?: string; - price?: string; - price2?: string; - }; -} +// Some websockets require an auth packet to be sent after opening the connection ⋮---- -export interface SpotSubmitOrderBatchParams { - orders: SpotBatchOrderItem[]; - pair: string; - asset_class?: 'tokenized_asset'; - broker?: string; - deadline?: string; - validate?: boolean; -} +// Reconnect to topics known before it connected +⋮---- +// Request sub to public topics, if any +⋮---- +// Request sub to private topics, if auth on connect isn't needed ⋮---- /** - * Funding - */ + * Handle subscription to private topics _after_ authentication successfully completes asynchronously. + * + * Only used for exchanges that require auth before sending private topic subscription requests + */ +private onWsAuthenticated( + wsKey: TWSKey, + event: { isWSAPI?: boolean; WSAPIAuthChannel?: string }, +) ⋮---- -export interface SpotGetDepositMethodsParams { - asset: string; - aclass?: 'currency' | 'tokenized_asset'; - rebase_multiplier?: 'rebased' | 'base'; -} +// Resolve & cleanup deferred "auth attempt in progress" promise ⋮---- -export interface SpotGetDepositAddressesParams { - asset: string; - aclass?: 'currency' | 'tokenized_asset'; - method: string; - new?: boolean; - amount?: string | number; -} +// Remove before continuing, in case there's more requests queued ⋮---- -export interface SpotGetDepositStatusParams { - asset?: string; - aclass?: 'currency' | 'tokenized_asset'; - method?: string; - start?: string; - end?: string; - cursor?: boolean | string; - limit?: number; - rebase_multiplier?: 'rebased' | 'base'; -} +private onWsPing( + event: any, + wsKey: TWSKey, + ws: WebSocket, + source: WsEventInternalSrc, +) ⋮---- -export interface SpotGetWithdrawalMethodsParams { - asset?: string; - aclass?: 'currency' | 'tokenized_asset'; - network?: string; - rebase_multiplier?: 'rebased' | 'base'; -} +private onWsPong(event: any, wsKey: TWSKey, source: WsEventInternalSrc) ⋮---- -export interface SpotGetWithdrawalAddressesParams { - asset?: string; - aclass?: 'currency' | 'tokenized_asset'; - method?: string; - key?: string; - verified?: boolean; -} +// Necessary when native heartbeats are used ⋮---- -export interface SpotGetWithdrawalInfoParams { - asset: string; - key: string; - amount: string; -} +private onWsMessage(event: unknown, wsKey: TWSKey, ws: WebSocket) ⋮---- -export interface SpotWithdrawFundsParams { - asset: string; - aclass?: 'currency' | 'tokenized_asset'; - key: string; - address?: string; - amount: string; - max_fee?: string; - rebase_multiplier?: 'rebased' | 'base'; -} +// console.log('onMessageRaw: ', (event as any).data); +// any message can clear the pong timer - wouldn't get a message if the ws wasn't working ⋮---- -export interface SpotGetWithdrawalsStatusParams { - asset?: string; - aclass?: 'currency' | 'tokenized_asset'; - method?: string; - start?: string; - end?: string; - cursor?: boolean | string; - limit?: number; - rebase_multiplier?: 'rebased' | 'base'; -} +// console.log(`raw event: `, { data, dataType, emittableEvents }); ⋮---- -export interface SpotWalletTransferParams { - asset: string; - from: 'Spot Wallet'; - to: 'Futures Wallet'; - amount: string; -} +// Not used for kraken. At least for spot, auth is included per req during subscribe ⋮---- -/** - * Subaccounts - */ +// Not used for kraken. At least for spot, auth is included per req during subscribe ⋮---- -export interface SpotAccountTransferParams { - asset: string; - asset_class?: 'currency' | 'tokenized_asset'; - amount: string; - from: string; - to: string; -} +// Other event types are automatically emitted here ⋮---- -/** - * Earn - */ +// this.logger.trace( +// `onWsMessage().emit(${emittable.eventType}).done()`, +// emittableFinalEvent, +// ); ⋮---- -export interface SpotListEarnStrategiesParams { - ascending?: boolean; - asset?: string; - cursor?: string; - limit?: number; - lock_type?: ('flex' | 'bonded' | 'timed' | 'instant')[]; -} +private onWsClose(event: unknown, wsKey: TWSKey) ⋮---- -export interface SpotListEarnAllocationsParams { - ascending?: boolean; - converted_asset?: string; - hide_zero_allocations?: boolean; -} +// unintentional close, attempt recovery ⋮---- -/** - * Transparency - */ +// clean up any pending promises for this connection ⋮---- -export interface SpotGetPostTradeDataParams { - symbol?: string; - from_ts?: string; - to_ts?: string; - count?: number; -} +// this.clearTopicsPendingSubscriptions(wsKey, true, 'WS Closed'); ⋮---- -/** - * OAuth - */ +// intentional close - clean up +// clean up any pending promises for this connection ⋮---- -export interface OauthGetAccessTokenParams { - grant_type: 'authorization_code' | 'refresh_token'; - code?: string; // Required if grant_type = authorization_code - redirect_uri?: string; // Required if grant_type = authorization_code - refresh_token?: string; // Required if grant_type = refresh_token -} +// This was an intentional close, delete all state for this connection, as if it never existed: ⋮---- -code?: string; // Required if grant_type = authorization_code -redirect_uri?: string; // Required if grant_type = authorization_code -refresh_token?: string; // Required if grant_type = refresh_token +private getWs(wsKey: TWSKey) ⋮---- -export interface OauthCreateFastApiKeyParams { - api_key_name: string; // max 32 chars - ip_allowlist: string[]; - nonce_window?: number; - permissions: { - export_data?: boolean; - funds_add?: boolean; - funds_earn?: boolean; - funds_query?: boolean; - funds_withdraw?: boolean; - ledger_query?: boolean; - trades_close?: boolean; - trades_modify?: boolean; - trades_query_closed?: boolean; - trades_query_open?: boolean; - }; - query_from?: number; - query_to?: number; - valid_until?: number; -} +private setWsState(wsKey: TWSKey, state: WsConnectionStateEnum) ⋮---- -api_key_name: string; // max 32 chars +/** + * Promise-driven method to assert that a ws has successfully connected (will await until connection is open) + */ +protected async assertIsConnected(wsKey: TWSKey): Promise ⋮---- -export interface OauthUpdateFastApiKeyParams { - new_api_key_name?: string; // max 32 chars - api_key_name: string; // max 32 chars - ip_allowlist: string[]; - nonce_window?: number; - permissions: { - export_data?: boolean; - funds_add?: boolean; - funds_earn?: boolean; - funds_query?: boolean; - funds_withdraw?: boolean; - ledger_query?: boolean; - trades_close?: boolean; - trades_modify?: boolean; - trades_query_closed?: boolean; - trades_query_open?: boolean; - }; - query_from?: number; - query_to?: number; - valid_until?: number; -} +// Already in progress? Await shared promise and retry ⋮---- -new_api_key_name?: string; // max 32 chars -api_key_name: string; // max 32 chars +// Start connection, it should automatically store/return a promise. +⋮---- +/** + * Promise-driven method to assert that a ws has been successfully authenticated (will await until auth is confirmed) + */ +public async assertIsAuthenticated(wsKey: TWSKey): Promise +⋮---- +// Already in progress? Await shared promise and retry +⋮---- +// Start authentication, it should automatically store/return a promise. ================ -File: src/types/response/derivatives.types.ts +File: src/types/request/partner.types.ts ================ +// Partner API request types +⋮---- /** - * Market Data + * Create User request parameters */ -⋮---- -export interface FuturesTradeHistoryItem { - price: number; - side?: string; // "buy" if taker is buyer, "sell" if taker is seller - size?: string; - time: string; - trade_id?: number; - type?: 'fill' | 'liquidation' | 'assignment' | 'termination' | 'block'; - uid?: string; - instrument_identification_type?: string; - isin?: string; - execution_venue?: string; - price_notation?: string; - price_currency?: string; - notional_amount?: number; - notional_currency?: string; - publication_time?: string; - publication_venue?: string; - transaction_identification_code?: string; - to_be_cleared?: boolean; +export interface PartnerCreateUserParams { + email: string; + external_id: string; + tos_version_accepted: number; + full_name: { + first_name: string; + middle_name?: string; + last_name: string; + }; + date_of_birth: string; // format: date (YYYY-MM-DD) + residence: { + line1: string; + line2?: string; + city: string; + postal_code: string; + province?: string; + country: string; // CountryCode + }; + phone: string; // E.164 format + nationalities: string[]; // CountryCode[] + occupation: + | 'agriculture' + | 'business_management' + | 'computers_and_it' + | 'construction' + | 'education' + | 'finance' + | 'government' + | 'healthcare' + | 'hospitality' + | 'manufacturing' + | 'marketing' + | 'media' + | 'other' + | 'science' + | 'self_employed' + | 'student' + | 'transportation' + | 'unemployed'; + city_of_birth?: string; + country_of_birth?: string; // CountryCode + tax_ids?: Array<{ + id: string; + issuing_country: string; // CountryCode + }>; + language?: string; // ISO 639-1 language code } ⋮---- -side?: string; // "buy" if taker is buyer, "sell" if taker is seller +date_of_birth: string; // format: date (YYYY-MM-DD) ⋮---- -export interface FuturesOrderBook { - asks: [number, number][]; // [price, size] - bids: [number, number][]; // [price, size] -} +country: string; // CountryCode ⋮---- -asks: [number, number][]; // [price, size] -bids: [number, number][]; // [price, size] +phone: string; // E.164 format +nationalities: string[]; // CountryCode[] ⋮---- -export interface TickerGreeks { - iv: number; // Implied volatility, -1.0 if impossible to calculate - delta: number; - gamma: number | null; - vega: number | null; - theta: number | null; - rho: number | null; -} +country_of_birth?: string; // CountryCode ⋮---- -iv: number; // Implied volatility, -1.0 if impossible to calculate +issuing_country: string; // CountryCode ⋮---- -export interface FuturesTicker { - symbol: string; - last?: number; - lastTime?: string; - lastSize?: number; - tag: 'perpetual' | 'month' | 'quarter' | 'semiannual'; - pair: string; - markPrice: number; - bid?: number; - bidSize?: number; - ask?: number; - askSize?: number; - vol24h: number; - volumeQuote: number; - openInterest: number; - open24h?: number; - high24h?: number; - low24h?: number; - extrinsicValue?: number; // Only for options - fundingRate?: number; // Only for perpetuals - fundingRatePrediction?: number; // Only for perpetuals - suspended: boolean; - indexPrice: number; - postOnly: boolean; - change24h: number; - greeks?: TickerGreeks; // Only for options - isUnderlyingMarketClosed?: boolean; // Only for tradfi markets +language?: string; // ISO 639-1 language code +⋮---- +/** + * Update User request parameters + */ +export interface PartnerUpdateUserParams { + user: string; + tos_version_accepted?: number; + full_name?: { + first_name: string; + middle_name?: string; + last_name: string; + }; + date_of_birth?: string; // format: date (YYYY-MM-DD) + city_of_birth?: string; + country_of_birth?: string; // CountryCode + residence?: { + line1: string; + line2?: string; + city: string; + postal_code: string; + province?: string; + country: string; // CountryCode + }; + phone?: string; // E.164 format + nationalities?: string[]; // CountryCode[] + tax_ids?: Array<{ + id: string; + issuing_country: string; // CountryCode + }>; + occupation?: + | 'agriculture' + | 'business_management' + | 'computers_and_it' + | 'construction' + | 'education' + | 'finance' + | 'government' + | 'healthcare' + | 'hospitality' + | 'manufacturing' + | 'marketing' + | 'media' + | 'other' + | 'science' + | 'self_employed' + | 'student' + | 'transportation' + | 'unemployed'; + language?: string; // ISO 639-1 language code } ⋮---- -extrinsicValue?: number; // Only for options -fundingRate?: number; // Only for perpetuals -fundingRatePrediction?: number; // Only for perpetuals +date_of_birth?: string; // format: date (YYYY-MM-DD) ⋮---- -greeks?: TickerGreeks; // Only for options -isUnderlyingMarketClosed?: boolean; // Only for tradfi markets +country_of_birth?: string; // CountryCode ⋮---- -/** - * Instrument Details - */ +country: string; // CountryCode ⋮---- -export interface FuturesMarginLevel { - contracts?: number | null; - numNonContractUnits?: number | null; - initialMargin: number; - maintenanceMargin: number; -} +phone?: string; // E.164 format +nationalities?: string[]; // CountryCode[] ⋮---- -export interface FuturesMarginSchedule { - retail: FuturesMarginLevel[]; - professional: FuturesMarginLevel[]; -} +issuing_country: string; // CountryCode ⋮---- -export interface FuturesInstrument { - symbol: string; - type: 'flexible_futures' | 'futures_inverse' | 'futures_vanilla'; - tradeable: boolean; - tradfi: boolean; - pair?: string; - base?: string; - quote?: string; - underlying?: string; - tickSize?: number; - contractSize?: number; - contractValueTradePrecision?: number; - impactMidSize?: number; - maxPositionSize?: number; - openingDate?: string; - lastTradingTime?: string; - category?: string; - fundingRateCoefficient?: number; - maxRelativeFundingRate?: number; - isin?: string; - marginSchedules?: Record; - retailMarginLevels?: FuturesMarginLevel[]; - marginLevels?: FuturesMarginLevel[]; - postOnly?: boolean; - /** @deprecated Effective 2026-06-22. Fee schedules are deprecated; use Spot GetTradeVolume instead. */ - feeScheduleUid?: string; - tags?: string[]; - underlyingFuture?: string; - mtf?: boolean; +language?: string; // ISO 639-1 language code +⋮---- +/** + * Submit Verification request parameters + */ +export interface PartnerSubmitVerificationParams { + user: string; + type: 'identity_document'; + metadata: { + identity: { + full_name: { + first_name: string; + middle_name?: string; + last_name: string; + }; + date_of_birth: string; // format: date (YYYY-MM-DD) + }; + document_type: + | 'passport' + | 'drivers_license' + | 'id_card' + | 'residence_card' + | 'special_permanent_residence_card'; + document_number: string; + issuing_country: string; // CountryCode + nationality?: string; // CountryCode + }; + verifier: string; // Name of the verification provider + verified_at: string; // ISO 8601 datetime + verifier_response?: any; + external_verification_id?: string; + expiration_date?: string; // ISO 8601 date + front: any; // File binary for front side of document + back: any; // File binary for back side of document + verifier_response_file?: any; // File binary for verifier response } ⋮---- -/** @deprecated Effective 2026-06-22. Fee schedules are deprecated; use Spot GetTradeVolume instead. */ +date_of_birth: string; // format: date (YYYY-MM-DD) ⋮---- -export interface FuturesInstrumentStatus { - tradeable: string; - experiencingDislocation: boolean; - priceDislocationDirection: 'ABOVE_UPPER_BOUND' | 'BELOW_LOWER_BOUND' | null; - experiencingExtremeVolatility: boolean; - extremeVolatilityInitialMarginMultiplier: number; -} +issuing_country: string; // CountryCode +nationality?: string; // CountryCode +⋮---- +verifier: string; // Name of the verification provider +verified_at: string; // ISO 8601 datetime +⋮---- +expiration_date?: string; // ISO 8601 date +front: any; // File binary for front side of document +back: any; // File binary for back side of document +verifier_response_file?: any; // File binary for verifier response ⋮---- /** - * Order Management + * List Assets request parameters */ -⋮---- -export interface FuturesOrderJson { - orderId: string; - cliOrdId?: string | null; - type: - | 'lmt' - | 'ioc' - | 'post' - | 'liquidation' - | 'assignment' - | 'stp' - | 'unwind' - | 'block' - | 'fok' - | 'unknown'; - symbol: string; - side: 'buy' | 'sell' | 'unknown'; - quantity: number; - filled: number; - limitPrice: number; - reduceOnly: boolean; - timestamp: string; - lastUpdateTimestamp: string; - reducedQuantity?: number | null; +export interface PartnerListAssetsParams { + 'filter[user]'?: string; // IIBAN + 'filter[assets][]'?: string[]; // AssetName[], max 100 + 'filter[platform_statuses][]'?: Array< + | 'enabled' + | 'deposit_only' + | 'withdrawal_only' + | 'funding_temporarily_disabled' + | 'disabled' + >; + 'filter[tradable_only]'?: boolean; + sort?: + | 'trending' + | 'market_cap_rank' + | '-market_cap_rank' + | 'symbol' + | '-symbol' + | 'name' + | '-name' + | 'change_percent_1h' + | '-change_percent_1h' + | 'change_percent_24h' + | '-change_percent_24h' + | 'change_percent_7d' + | '-change_percent_7d' + | 'change_percent_30d' + | '-change_percent_30d' + | 'change_percent_1y' + | '-change_percent_1y' + | 'listing_date' + | '-listing_date'; + 'page[size]'?: number; // 1-100 + 'page[number]'?: number; // >= 1 + quote?: string; // AssetName, default USD + lang?: string; // ISO language code, default en } ⋮---- -export interface FuturesOrderTriggerJson { - uid: string; - clientId: string | null; - type: - | 'lmt' - | 'ioc' - | 'post' - | 'liquidation' - | 'assignment' - | 'stp' - | 'unwind' - | 'fok' - | 'unknown'; - symbol: string; - side: 'buy' | 'sell' | 'unknown'; - quantity: number | null; - limitPrice: number | null; - triggerPrice: number | null; - triggerSide: 'trigger_above' | 'trigger_below' | 'unknown' | null; - triggerSignal: 'mark_price' | 'last_price' | 'spot_price' | 'unknown' | null; - reduceOnly: boolean; - timestamp: string; - lastUpdateTimestamp: string; - startTime: string | null; -} +'filter[user]'?: string; // IIBAN +'filter[assets][]'?: string[]; // AssetName[], max 100 ⋮---- -export interface FuturesPlaceEvent { - type: 'PLACE'; - order: FuturesOrderJson; -} +'page[size]'?: number; // 1-100 +'page[number]'?: number; // >= 1 +quote?: string; // AssetName, default USD +lang?: string; // ISO language code, default en ⋮---- -export interface FuturesCancelEvent { - type: 'CANCEL'; - uid: string; - order: FuturesOrderJson; +/** + * Get Asset request parameters + */ +export interface PartnerGetAssetParams { + asset: string; + quote?: string; // AssetName, default USD + lang?: string; // ISO language code, default en } ⋮---- -export interface FuturesEditEvent { - type: 'EDIT'; - old: FuturesOrderJson; - new: FuturesOrderJson & { reducedQuantity: number | null }; -} +quote?: string; // AssetName, default USD +lang?: string; // ISO language code, default en ⋮---- -export interface FuturesRejectEvent { - type: 'REJECT'; - uid: string; - order: FuturesOrderJson; - reason: 'POST_WOULD_EXECUTE' | 'IOC_WOULD_NOT_EXECUTE'; +/** + * List Asset Rates request parameters + */ +export interface PartnerListAssetRatesParams { + asset: string; + quote?: string; // AssetName, default USD + start_time?: string; // RFC 3339 datetime + end_time?: string; // RFC 3339 datetime + interval?: string; // ISO 8601 duration (PT15M, PT60M, P1D, etc.) } ⋮---- -export interface FuturesExecuteEvent { - type: 'EXECUTION'; - executionId: string; - price: number; - amount: number; - orderPriorEdit: FuturesOrderJson; - orderPriorExecution: FuturesOrderJson & { - takerReducedQuantity: number | null; +quote?: string; // AssetName, default USD +start_time?: string; // RFC 3339 datetime +end_time?: string; // RFC 3339 datetime +interval?: string; // ISO 8601 duration (PT15M, PT60M, P1D, etc.) +⋮---- +/** + * Request Quote request parameters + */ +export interface PartnerRequestQuoteParams { + user: string; // IIBAN + type: 'receive' | 'spend'; // Type of quote + amount: { + asset_class?: 'currency'; + asset: string; // AssetName + amount: string; // decimal128 + }; + quote: { + asset: string; // AssetName }; + fee_bps: string; // Basis points + spread_bps: string; // Basis points + quote_currency?: string; // AssetName } ⋮---- -export interface FuturesPlaceTriggerEvent { - type: 'PLACE'; - orderTrigger: FuturesOrderTriggerJson; -} +user: string; // IIBAN +type: 'receive' | 'spend'; // Type of quote ⋮---- -export interface FuturesCancelTriggerEvent { - type: 'CANCEL'; - uid: string; - orderTrigger: FuturesOrderTriggerJson; -} +asset: string; // AssetName +amount: string; // decimal128 ⋮---- -export interface FuturesRejectTriggerEvent { - type: 'REJECT'; - uid: string; - orderTrigger: FuturesOrderTriggerJson; - reason: - | 'MARKET_SUSPENDED' - | 'MARKET_NOT_FOUND' - | 'INVALID_PRICE' - | 'INVALID_QUANTITY' - | 'SMALL_ORDER_LIMIT_EXCEEDED' - | 'INSUFFICIENT_MARGIN' - | 'WOULD_CAUSE_LIQUIDATION' - | 'CLIENT_ORDER_ID_IN_USE' - | 'CLIENT_ORDER_ID_TOO_LONG' - | 'MAX_POSITION_EXCEEDED' - | 'PRICE_COLLAR' - | 'PRICE_DISLOCATION' - | 'EDIT_HAS_NO_EFFECT' - | 'ORDER_FOR_CANCELLATION_NOT_FOUND' - | 'ORDER_FOR_EDIT_NOT_FOUND' - | 'ORDER_CANNOT_HAVE_TRIGGER_PRICE' - | 'POST_WOULD_EXECUTE' - | 'IOC_WOULD_NOT_EXECUTE' - | 'WOULD_EXECUTE_SELF' - | 'WOULD_NOT_REDUCE_POSITION' - | 'REJECTED_AFTER_EXECUTION' - | 'MARKET_IS_POST_ONLY' - | 'ORDER_LIMIT_EXCEEDED' - | 'FIXED_LEVERAGE_TOO_HIGH' - | 'CANNOT_EDIT_TRIGGER_PRICE_OF_TRAILING_STOP' - | 'CANNOT_EDIT_LIMIT_PRICE_OF_TRAILING_STOP' - | 'TRAILING_STOP_ORDER_LIMIT_EXCEEDED' - | 'TRAILING_STOP_PERCENT_DEVIATION_EXCEEDS_MAX_DECIMAL_PLACES' - | 'TRAILING_STOP_QUOTE_DEVIATION_NOT_MULTIPLE_OF_TICK_SIZE' - | 'TRAILING_STOP_MAX_DEVIATION_TOO_LARGE' - | 'TRAILING_STOP_MAX_DEVIATION_TOO_SMALL' - | 'INSUFFICIENT_HEADROOM_AROUND_CURRENT_PRICE_TO_EDIT_TRAILING_STOP' - | 'NO_REFERENCE_PRICE_AVAILABLE_FOR_CALCULATING_TRAILING_STOP_TRIGGER_PRICE' - | 'INSUFFICIENT_CLOSING_MARGIN' - | 'LIMIT_PRICE_SET_AS_ABSOLUTE_AND_RELATIVE' - | 'LIMIT_PRICE_OFFSET_VALUE_INVALID' - | 'LIMIT_PRICE_OFFSET_UNIT_INVALID' - | 'LIMIT_PRICE_OFFSET_MUST_HAVE_VALUE_AND_UNIT' - | 'LIMIT_PRICE_OFFSET_QUOTE_CURRENCY_VALUE_MUST_BE_MULTIPLE_OF_TICK_SIZE' - | 'LIMIT_PRICE_OFFSET_PERCENT_VALUE_TOO_MANY_DECIMAL_PLACES' - | 'LIMIT_PRICE_OFFSET_TOO_HIGH' - | 'LIMIT_PRICE_OFFSET_TOO_LOW'; -} +asset: string; // AssetName ⋮---- -export type FuturesOrderEvent = - | FuturesPlaceEvent - | FuturesCancelEvent - | FuturesEditEvent - | FuturesRejectEvent - | FuturesExecuteEvent - | FuturesPlaceTriggerEvent - | FuturesCancelTriggerEvent - | FuturesRejectTriggerEvent; +fee_bps: string; // Basis points +spread_bps: string; // Basis points +quote_currency?: string; // AssetName ⋮---- -export interface FuturesBatchOrderStatus { - cliOrdId?: string; - dateTimeReceived?: string | null; - orderEvents: FuturesOrderEvent[]; - order_id?: string | null; - order_tag?: string | null; - status: - | 'placed' - | 'edited' - | 'cancelled' - | 'invalidOrderType' - | 'invalidSide' - | 'invalidSize' - | 'invalidPrice' - | 'insufficientAvailableFunds' - | 'selfFill' - | 'tooManySmallOrders' - | 'marketSuspended' - | 'marketInactive' - | 'clientOrderIdAlreadyExist' - | 'clientOrderIdTooLong' - | 'outsidePriceCollar' - | 'postWouldExecute' - | 'iocWouldNotExecute'; +/** + * Get Quote request parameters + */ +export interface PartnerGetQuoteParams { + quote_id: string; + user: string; // IIBAN } ⋮---- -export interface FuturesCancelledOrder { - cliOrdId?: string | null; - order_id: string; -} +user: string; // IIBAN ⋮---- -export interface FuturesCancelAllOrdersStatus { - cancelOnly: string; - cancelledOrders: FuturesCancelledOrder[]; - orderEvents: FuturesOrderEvent[]; - receivedTime: string; - status: 'noOrdersToCancel' | 'cancelled'; +/** + * Execute Quote request parameters + */ +export interface PartnerExecuteQuoteParams { + quote_id: string; + user: string; // IIBAN } ⋮---- -export interface FuturesDeadMansSwitchStatus { - currentTime: string; - triggerTime: string; -} +user: string; // IIBAN ⋮---- -export interface FuturesCancelOrderStatus { - cliOrdId?: string | null; - orderEvents?: FuturesOrderEvent[]; - order_id?: string; - receivedTime?: string; - status: 'cancelled' | 'filled' | 'notFound'; +/** + * Get Portfolio Summary request parameters + */ +export interface PartnerGetPortfolioSummaryParams { + user: string; // IIBAN + quote?: string; // AssetName, default USD + 'include[current_day_pnl]'?: any; // Include the current day pnl } ⋮---- -export interface FuturesEditOrderStatus { - orderId?: string | null; - cliOrdId?: string | null; - orderEvents: FuturesOrderEvent[]; - receivedTime?: string | null; - status: - | 'edited' - | 'invalidSize' - | 'invalidPrice' - | 'insufficientAvailableFunds' - | 'selfFill' - | 'tooManySmallOrders' - | 'outsidePriceCollar' - | 'postWouldExecute' - | 'wouldNotReducePosition' - | 'orderForEditNotFound' - | 'orderForEditNotAStop'; -} +user: string; // IIBAN +quote?: string; // AssetName, default USD +'include[current_day_pnl]'?: any; // Include the current day pnl ⋮---- -export interface FuturesOpenOrder { - order_id: string; - cliOrdId?: string; - status: 'untouched' | 'partiallyFilled'; - side: 'buy' | 'sell' | 'unknown'; - orderType: 'lmt' | 'stop' | 'take_profit' | 'unknown'; - symbol: string; - limitPrice?: number; - stopPrice?: number; - filledSize: number; - unfilledSize?: number; - reduceOnly: boolean; - triggerSignal?: 'mark' | 'last' | 'spot' | 'unknown'; - lastUpdateTime: string; - receivedTime: string; +/** + * Get Portfolio History request parameters + */ +export interface PartnerGetPortfolioHistoryParams { + user: string; // IIBAN + 'include[assets][]'?: string[]; // AssetName[] + 'include[total_balance]'?: boolean; + 'include[total_pnl]'?: boolean; + start_date?: string; // date format + end_date?: string; // date format + resolution?: number; // uint32, default 1 + quote?: string; // AssetName, default USD + cursor?: string; // Pagination cursor } ⋮---- -export interface FuturesSendOrderStatus { - cliOrdId?: string; - orderEvents?: FuturesOrderEvent[]; - order_id?: string; - receivedTime?: string; - status: - | 'placed' - | 'partiallyFilled' - | 'filled' - | 'cancelled' - | 'edited' - | 'marketSuspended' - | 'marketInactive' - | 'invalidPrice' - | 'invalidSize' - | 'tooManySmallOrders' - | 'insufficientAvailableFunds' - | 'wouldCauseLiquidation' - | 'clientOrderIdAlreadyExist' - | 'clientOrderIdTooBig' - | 'maxPositionViolation' - | 'outsidePriceCollar' - | 'wouldIncreasePriceDislocation' - | 'notFound' - | 'orderForEditNotAStop' - | 'orderForEditNotFound' - | 'postWouldExecute' - | 'iocWouldNotExecute' - | 'selfFill' - | 'wouldNotReducePosition' - | 'marketIsPostOnly' - | 'tooManyOrders' - | 'fixedLeverageTooHigh' - | 'clientOrderIdInvalid' - | 'cannotEditTriggerPriceOfTrailingStop' - | 'cannotEditLimitPriceOfTrailingStop' - | 'wouldProcessAfterSpecifiedTime'; +user: string; // IIBAN +'include[assets][]'?: string[]; // AssetName[] +⋮---- +start_date?: string; // date format +end_date?: string; // date format +resolution?: number; // uint32, default 1 +quote?: string; // AssetName, default USD +cursor?: string; // Pagination cursor +⋮---- +/** + * List Portfolio Details request parameters + */ +export interface PartnerListPortfolioDetailsParams { + user: string; // IIBAN + quote?: string; // AssetName, default USD } ⋮---- -export interface FuturesTriggerOptions { - triggerPrice: number; - triggerSide: 'TRIGGER_ABOVE' | 'TRIGGER_BELOW' | 'unknown'; - triggerSignal: 'MARK_PRICE' | 'LAST_PRICE' | 'SPOT_PRICE' | 'unknown'; - triggerTime: string | null; +user: string; // IIBAN +quote?: string; // AssetName, default USD +⋮---- +/** + * List Portfolio Transactions request parameters + */ +export interface PartnerListPortfolioTransactionsParams { + user: string; // IIBAN + cursor?: string; + types?: Array<'simple_order' | 'simple_order_failed' | 'earn_reward'>; + page_size?: number; // uint64 + assets?: string[]; // AssetName[], max 16 chars each + from_time?: string; // date-time + until_time?: string; // date-time + statuses?: Array< + 'no_status' | 'unspecified' | 'in_progress' | 'successful' | 'failed' + >; + ids?: string[]; + sorting?: 'descending' | 'ascending'; + ref_ids?: any[]; // Simplified - array of reference ID filter objects + quote?: string; // AssetName, max 16 chars } ⋮---- -export interface FuturesOrderStatusInfo { - order: { - type: 'TRIGGER_ORDER' | 'ORDER'; - orderId: string; - cliOrdId: string | null; - symbol: string; - side: string; - quantity: number | null; - filled: number | null; - limitPrice: number | null; - reduceOnly: boolean; - timestamp: string; - lastUpdateTimestamp: string; - priceTriggerOptions?: FuturesTriggerOptions; - }; - status: - | 'ENTERED_BOOK' - | 'FULLY_EXECUTED' - | 'REJECTED' - | 'CANCELLED' - | 'TRIGGER_PLACED' - | 'TRIGGER_ACTIVATION_FAILURE'; - updateReason: - | 'LOADING_MARKET' - | 'NEW_USER_ORDER' - | 'LIQUIDATION_ORDER' - | 'STOP_ORDER_TRIGGERED' - | 'LIMIT_FROM_STOP' - | 'PARTIAL_FILL' - | 'FULL_FILL' - | 'CANCELLED_BY_USER' - | 'CONTRACT_EXPIRED' - | 'NOT_ENOUGH_MARGIN' - | 'MARKET_INACTIVE' - | 'DEAD_MAN_SWITCH' - | 'CANCELLED_BY_ADMIN' - | 'POST_WOULD_EXECUTE_REASON' - | 'IOC_WOULD_NOT_EXECUTE_REASON' - | 'WOULD_EXECUTE_SELF_REASON' - | 'WOULD_NOT_REDUCE_POSITION' - | 'EDITED_BY_USER' - | 'ORDER_FOR_EDIT_NOT_FOUND_REASON' - | 'EXPIRED' - | 'TRAILING_STOP_PRICE_UPDATED' - | 'TRAILING_STOP_CANCELLED_AND_REPLACED_BY_ADMIN' - | 'unknown'; - error?: string; // OrderError type - reusing the same errors as FuturesRejectTriggerEvent -} +user: string; // IIBAN ⋮---- -error?: string; // OrderError type - reusing the same errors as FuturesRejectTriggerEvent +page_size?: number; // uint64 +assets?: string[]; // AssetName[], max 16 chars each +from_time?: string; // date-time +until_time?: string; // date-time +⋮---- +ref_ids?: any[]; // Simplified - array of reference ID filter objects +quote?: string; // AssetName, max 16 chars ⋮---- /** - * Multi-Collateral + * Get Earn Summary request parameters */ -⋮---- -export interface FuturesPnlPreference { - symbol: string; - pnlCurrency: string; +export interface PartnerGetEarnSummaryParams { + user: string; // IIBAN + currency?: string; // max 16 chars } ⋮---- -export interface FuturesLeveragePreference { - symbol: string; - maxLeverage: number; -} +user: string; // IIBAN +currency?: string; // max 16 chars ⋮---- /** - * Account Information + * List Earn Assets request parameters */ -⋮---- -export interface FuturesFlexCurrencySummary { - quantity: number; - value: number; - collateral: number; +export interface PartnerListEarnAssetsParams { + assets?: string[]; // AssetName[], max 16 chars each + user?: string; // IIBAN, 14-42 chars + currency?: string; // max 16 chars, required if user is set } ⋮---- -export interface FuturesPortfolioMarginBreakdown { - totalCrossAssetNettedMarketRisk: number; - totalMarketRisk: number; - totalScenarioPnls: number[]; - totalAbsoluteOptionPositionDeltaNotional: number; - netPortfolioDelta: number; - totalPremium: number; - isBuyOnly: boolean; - futuresMaintenanceMargin: number; -} +assets?: string[]; // AssetName[], max 16 chars each +user?: string; // IIBAN, 14-42 chars +currency?: string; // max 16 chars, required if user is set ⋮---- -export interface FuturesFlexAccount { - type: 'multiCollateralMarginAccount'; - currencies: Record; - available: number; - initialMargin: number; - initialMarginWithOrders: number; - maintenanceMargin: number; - balanceValue: number; - portfolioValue: number; - collateralValue: number; - pnl: number; - unrealizedFunding: number; - totalUnrealized: number; - totalUnrealizedAsMargin: number; - availableMargin: number; - marginEquity: number; - portfolioMarginBreakdown?: FuturesPortfolioMarginBreakdown; +/** + * Toggle Auto-Earn request parameters + */ +export interface PartnerToggleAutoEarnParams { + user: string; // IIBAN + want_enabled: boolean; } ⋮---- -export interface FuturesCashAccount { - type: 'cashAccount'; - balances: Record; -} +user: string; // IIBAN ⋮---- -export interface FuturesMarginAccount { - type: 'marginAccount'; - currency: string; - balances: Record; - auxiliary: { - usd: number; - pv: number; - pnl: number; - af: number; - funding: number; - }; - marginRequirements: { - im: number; - mm: number; - lt: number; - tt: number; - }; - triggerEstimates: { - im: number; - mm: number; - lt: number; - tt: number; - }; +/** + * Withdraw Funds request parameters + */ +export interface PartnerWithdrawFundsParams { + asset: string; // AssetName, 3-16 chars + key: string; // Withdrawal key + amount: string; // decimal128 } ⋮---- -export interface FuturesAccounts { - cash?: FuturesCashAccount; - flex?: FuturesFlexAccount; - [key: string]: - | FuturesMarginAccount - | FuturesCashAccount - | FuturesFlexAccount - | undefined; -} +asset: string; // AssetName, 3-16 chars +key: string; // Withdrawal key +amount: string; // decimal128 ⋮---- -export interface FuturesOpenPosition { - symbol: string; - side: 'long' | 'short'; - size: number; - price: number; - fillTime: string; - unrealizedFunding: number | null; - pnlCurrency?: string | null; // USD, EUR, GBP, USDC, USDT, BTC, ETH - maxFixedLeverage?: number | null; +/** + * List Funding Transactions request parameters + */ +export interface PartnerListFundingTransactionsParams { + type: 'withdrawal' | 'deposit'; + cursor?: string; + page_size?: number; // uint32, 1-500, default 25 } ⋮---- -pnlCurrency?: string | null; // USD, EUR, GBP, USDC, USDT, BTC, ETH +page_size?: number; // uint32, 1-500, default 25 ⋮---- -export interface FuturesUnwindQueuePosition { - symbol: string; - percentile: number; +/** + * List Settlement Reports request parameters + */ +export interface PartnerListSettlementReportsParams { + 'filter[start_date]'?: string; // RFC 3339 datetime + 'filter[end_date]'?: string; // RFC 3339 datetime + 'filter[report_type][]'?: Array<'trades' | 'transfers' | 'earn_rewards'>; + 'page[size]'?: number; // uint32, 1-100, default 20 + 'page[number]'?: number; // uint32, >= 1, default 1 } ⋮---- -export interface FuturesOptionsUserLimitsPerBaseCurrency { - maxTotalPositionSize: number; - maxTotalOpenOrdersSize: number; -} +'filter[start_date]'?: string; // RFC 3339 datetime +'filter[end_date]'?: string; // RFC 3339 datetime ⋮---- -export interface FuturesPortfolioMarginParameters { - crossAssetNettingFactor: number; - extremePriceShockMultiplier: number; - volShockMultiplicationFactor: number; - volShockExponentFactor: number; - optionExpiryTimeShockHours: number; - optionsInitialMarginFactor: number; - totalOptionOrdersConsideredInInitialMarginCalc: number; - priceShockLevels: number[]; - optionsUserLimits: { - maxNetPositionDelta: number; - limitsPerBaseCurrency: Record< - string, - FuturesOptionsUserLimitsPerBaseCurrency - >; - }; +'page[size]'?: number; // uint32, 1-100, default 20 +'page[number]'?: number; // uint32, >= 1, default 1 +⋮---- +/** + * Get Settlement Report request parameters + */ +export interface PartnerGetSettlementReportParams { + id: string; } ⋮---- -export interface FuturesOptionGreeks { - iv: number; // -1.0 if impossible to calculate - delta: number; - gamma: number | null; - vega: number | null; - theta: number | null; - rho: number | null; +/** + * Get Ramp Limits request parameters + */ +export interface PartnerGetRampLimitsParams { + in_asset: string; // max 16 chars + out_asset: string; // max 16 chars + funding_type: string; + withdrawal_method: string; } ⋮---- -iv: number; // -1.0 if impossible to calculate +in_asset: string; // max 16 chars +out_asset: string; // max 16 chars ⋮---- -export interface FuturesPortfolioSimulation { - maintenanceMargin: number; - initialMargin: number; - pnl: number; - portfolioMarginBreakdown: FuturesPortfolioMarginBreakdown; - greeks: Record; +/** + * Get Ramp Prospective Quote request parameters + */ +export interface PartnerGetRampProspectiveQuoteParams { + in_asset: string; // max 16 chars + in_amount: string; // decimal128 + out_asset: string; // max 16 chars + funding_type: string; + withdrawal_method: string; } ⋮---- +in_asset: string; // max 16 chars +in_amount: string; // decimal128 +out_asset: string; // max 16 chars +⋮---- /** - * Assignment Program + * Embed Custom Orders - Create Custom Order request parameters + * Price-triggered custom orders. User in query, body has trigger, action, name. */ -⋮---- -export interface FuturesAssignmentProgramParticipant { - contractType: string; - contract: string | null; - maxSize: number | null; - maxPosition: number | null; - acceptLong: boolean; - acceptShort: boolean; - timeFrame: 'all' | 'weekdays' | 'weekends'; - enabled: boolean; -} -⋮---- -export interface FuturesAssignmentProgram { - id: number; - participant: FuturesAssignmentProgramParticipant; - contractType: string; - contract: string | null; - maxSize: number | null; - maxPosition: number | null; - acceptLong: boolean; - acceptShort: boolean; - timeFrame: 'all' | 'weekdays' | 'weekends'; - enabled: boolean; +export interface PartnerCreateCustomOrderParams { + user: string; // IIBAN, 14-42 chars + trigger: { + type: 'price'; + base_asset: string; // <= 16 chars + quote_asset: string; // <= 16 chars + target_price: string; + condition: 'gte' | 'lte'; + }; + action: { + type: 'receive' | 'spend'; + amount: { + asset_class?: 'currency'; + asset: string; // <= 16 chars + amount: string; + }; + quote: { + asset: string; // <= 16 chars + fee_bps: string; // 1-5 digits + spread_bps: string; // 1-5 digits + }; + }; + name: string; } ⋮---- -export interface FuturesAssignmentProgramHistory { - deleted: boolean; - participant: FuturesAssignmentProgramParticipant; - contractType: string; - contract: string | null; - maxSize: number | null; - maxPosition: number | null; - acceptLong: boolean; - acceptShort: boolean; - timeFrame: 'all' | 'weekdays' | 'weekends'; - enabled: boolean; - timestamp: string; -} +user: string; // IIBAN, 14-42 chars ⋮---- -/** - * Fee Schedules - * - * @deprecated Effective 2026-06-22. Use Spot GetTradeVolume (SpotClient.getTradingVolume) instead. - */ +base_asset: string; // <= 16 chars +quote_asset: string; // <= 16 chars ⋮---- -export interface FuturesFeeTier { - makerFee: number; - takerFee: number; - usdVolume: number; -} +asset: string; // <= 16 chars ⋮---- -export interface FuturesFeeSchedule { - tiers: FuturesFeeTier[]; - name: string; - uid: string; -} +asset: string; // <= 16 chars +fee_bps: string; // 1-5 digits +spread_bps: string; // 1-5 digits ⋮---- /** - * General + * Embed Custom Orders - List Custom Orders request parameters */ -⋮---- -export interface FuturesNotification { - effectiveTime: string; - note: string; - priority: 'low' | 'medium' | 'high'; - type: - | 'new_feature' - | 'bug_fix' - | 'settlement' - | 'general' - | 'maintenance' - | 'market'; - expectedDowntimeMinutes?: number; +export interface PartnerListCustomOrdersParams { + user: string; // IIBAN, 14-42 chars + statuses?: Array<'active' | 'cancelled' | 'completed'>; + cursor?: string; } ⋮---- +user: string; // IIBAN, 14-42 chars +⋮---- /** - * Historical Data + * Embed Custom Orders - Get Custom Order request parameters */ -⋮---- -export interface FuturesFill { - cliOrdId?: string | null; - fillTime: string; - fillType: - | 'maker' - | 'taker' - | 'liquidation' - | 'assignor' - | 'assignee' - | 'takerAfterEdit' - | 'unwindBankrupt' - | 'unwindCounterparty'; - fill_id: string; +export interface PartnerGetCustomOrderParams { + user: string; // IIBAN, 14-42 chars order_id: string; - price: number; - side: 'buy' | 'sell' | 'unknown'; - size: number; - symbol: string; } ⋮---- +user: string; // IIBAN, 14-42 chars +⋮---- /** - * Historical Funding Rates + * Embed Custom Orders - Cancel Custom Order request parameters */ -⋮---- -export interface FuturesHistoricalFundingRate { - fundingRate: number; - relativeFundingRate: number; - timestamp: string; +export interface PartnerCancelCustomOrderParams { + user: string; // IIBAN, 14-42 chars + id: string; // order id } ⋮---- +user: string; // IIBAN, 14-42 chars +id: string; // order id +⋮---- /** - * Subaccounts + * Embed Quotes (RFQ) - Get Quote Limits request parameters */ -⋮---- -export interface FuturesHoldingAccount { - currency: string; - amount: number; +export interface PartnerGetQuoteLimitsParams { + user: string; // IIBAN, 14-42 chars + base_asset: string; // <= 16 chars + quote_asset: string; // <= 16 chars + type: 'receive' | 'spend'; + quote_currency?: string; // <= 16 chars } ⋮---- -export interface FuturesSingleCollateralAccount { - name: string; - availableMargin: number; -} +user: string; // IIBAN, 14-42 chars +base_asset: string; // <= 16 chars +quote_asset: string; // <= 16 chars ⋮---- -export interface FuturesSubaccountFlexCurrency { - currency: string; - quantity: number; - value: number; - collateral: number; - available: number; -} +quote_currency?: string; // <= 16 chars ⋮---- -export interface FuturesSubaccountFlexAccount { - currencies: FuturesSubaccountFlexCurrency[]; - initialMargin: number; - initialMarginWithOrders: number; - maintenanceMargin: number; - balanceValue: number; - portfolioValue: number; - collateralValue: number; - pnl: number; - unrealizedFunding: number; - totalUnrealized: number; - totalUnrealizedAsMargin: number; - availableMargin: number; - marginEquity: number; - portfolioMarginBreakdown?: FuturesPortfolioMarginBreakdown; +/** + * Embed Quotes (RFQ) - Request Prospective Quote request parameters + */ +export interface PartnerRequestProspectiveQuoteParams { + user: string; // IIBAN, 14-42 chars + action: { + type: 'receive' | 'spend'; + amount: { + asset_class?: 'currency'; + asset: string; // <= 16 chars + amount: string; + }; + quote: { + asset: string; // <= 16 chars + fee_bps: string; // 1-5 digits + spread_bps: string; // 1-5 digits + }; + }; + trigger?: { + type: 'price'; + base_asset: string; + quote_asset: string; + target_price: string; + condition: 'gte' | 'lte'; + }; + quote_currency?: string; // <= 16 chars } ⋮---- -export interface FuturesSubaccount { - accountUid: string; - email: string; - fullName: string | null; - holdingAccounts: FuturesHoldingAccount[]; - futuresAccounts: FuturesSingleCollateralAccount[]; - flexAccount: FuturesSubaccountFlexAccount; -} +user: string; // IIBAN, 14-42 chars ⋮---- -export interface FuturesSubaccountsInfo { - masterAccountUid: string; - subaccounts: FuturesSubaccount[]; -} +asset: string; // <= 16 chars +⋮---- +asset: string; // <= 16 chars +fee_bps: string; // 1-5 digits +spread_bps: string; // 1-5 digits +⋮---- +quote_currency?: string; // <= 16 chars ⋮---- /** - * RFQs + * Get Ramp Checkout URL request parameters */ -⋮---- -export interface FuturesRfqLeg { - symbol: string; - size: number; - markPrice: number; +export interface PartnerGetRampCheckoutUrlParams { + in_asset: string; // max 16 chars + in_amount: string; // decimal128 + out_asset: string; // max 16 chars + funding_type: string; + withdrawal_method: string; + country?: string; // max 2 chars, ISO 3166-1 alpha-2 + redirect_url?: string; // URI + network?: string; + external_user_id?: string; // max 36 chars + external_transaction_id?: string; // max 36 chars + external_metadata?: string; // max 1000 chars } ⋮---- -export interface FuturesRfq { - rfqUid: string; - expiry: string; - markPrice: number; - legs: FuturesRfqLeg[]; -} +in_asset: string; // max 16 chars +in_amount: string; // decimal128 +out_asset: string; // max 16 chars ⋮---- -export interface FuturesOpenOffer { - uid: string; - rfqUid: string; - placementDate: string; - lastUpdateDate: string; - bid?: string; - ask?: string; -} +country?: string; // max 2 chars, ISO 3166-1 alpha-2 +redirect_url?: string; // URI ⋮---- +external_user_id?: string; // max 36 chars +external_transaction_id?: string; // max 36 chars +external_metadata?: string; // max 1000 chars + +================ +File: src/types/request/spot.types.ts +================ /** - * Account History + * Market Data */ ⋮---- -export interface FuturesHistoryResponse { - accountUid: string; - len: number; - serverTime: string; - elements: T[]; - continuationToken?: string; +export interface SpotGetAssetPairsParams { + pair?: string; + aclass_base?: 'currency' | 'tokenized_asset'; + info?: 'info' | 'leverage' | 'fees' | 'margin'; + country_code?: string; + execution_venue?: string; } ⋮---- -export interface FuturesHistoryEventElement { - uid: string; - timestamp: number; - event: T; +export interface SpotGetOHLCParams { + pair: string; + interval?: 1 | 5 | 15 | 30 | 60 | 240 | 1440 | 10080 | 21600; + since?: number; + asset_class?: 'tokenized_asset'; } ⋮---- -// Complex nested structures with multiple oneOf variants - keeping generic for flexibility -export type FuturesHistoryExecutionEvent = FuturesHistoryEventElement; -export type FuturesHistoryOrderEvent = FuturesHistoryEventElement; -export type FuturesHistoryTriggerEvent = FuturesHistoryEventElement; +export interface SpotGetOrderBookParams { + pair: string; + count?: number; + asset_class?: 'tokenized_asset'; +} ⋮---- -export interface FuturesPositionUpdateEvent { - accountUid: string; - tradeable: string; - oldPosition: string; - oldAverageEntryPrice: string | null; - newPosition: string; - newAverageEntryPrice: string; - fillTime?: number | null; - fee?: string; - feeCurrency?: string; - realizedPnL?: string; - positionChange: - | 'open' - | 'close' - | 'increase' - | 'decrease' - | 'reverse' - | 'noChange' - | 'unknown'; - executionUid?: string; - executionPrice?: string; - executionSize?: string; - tradeType?: - | 'userExecution' - | 'liquidation' - | 'assignment' - | 'unwind' - | 'unknown'; - fundingRealizationTime?: number; - realizedFunding?: string; - settlementPrice?: string; - timestamp: number; - updateReason: 'trade' | 'fundingRealisation' | 'settlement' | 'unknown'; +export interface SpotGetGroupedBookParams { + pair: string; + depth?: 10 | 25 | 100 | 250 | 1000; + grouping?: 1 | 5 | 10 | 25 | 50 | 100 | 250 | 500 | 1000; } ⋮---- -export interface FuturesAccountLogEntry { +export interface SpotGetLevel3Params { + pair: string; + depth?: 0 | 10 | 25 | 100 | 250 | 1000; +} +⋮---- +export interface SpotTradeVolumePairInput { asset: string; - booking_uid: string; - collateral: string | null; - contract: string | null; - date: string; // RFC 3339 formatted date-time - execution: string | null; - fee: number | null; - funding_rate: number | null; - id: number; - info: string; - margin_account: string; - mark_price: number | null; - new_average_entry_price: number | null; - new_balance: number; - old_average_entry_price: number | null; - old_balance: number; - realized_funding: number | null; - realized_pnl: number | null; - trade_price: number | null; - conversion_spread_percentage?: number | null; - liquidation_fee?: number | null; - exchange_rate?: number; - conversion_fee?: number; - exchange_rate_from?: string; + aclass: + | 'currency' + | 'forex' + | 'equity' + | 'equity_pair' + | 'nft' + | 'derivatives' + | 'tokenized_asset' + | 'futures_contract'; +} +⋮---- +export interface SpotGetTradingVolumeParams { + pair?: string | SpotTradeVolumePairInput[]; + fee_schedule?: boolean; + rebase_multiplier?: 'rebased' | 'base'; } ⋮---- -date: string; // RFC 3339 formatted date-time +export interface SpotGetRecentTradesParams { + pair: string; + since?: string; + count?: number; + asset_class?: 'tokenized_asset'; +} ⋮---- -export interface FuturesAccountLog { - accountUid: string; - logs: FuturesAccountLogEntry[]; +export interface SpotGetRecentSpreadsParams { + pair: string; + since?: number; + asset_class?: 'tokenized_asset'; } ⋮---- /** - * Market History + * Account Data */ ⋮---- -export interface FuturesMarketHistoryResponse { - len: number; - elements: T[]; - continuationToken?: string; +export interface SpotGetApiKeyInfoParams { + otp?: string; } ⋮---- -export interface FuturesMarketHistoryEventElement { - uid: string; - timestamp: number; - event: T; +export interface SpotGetOpenOrdersParams { + trades?: boolean; + userref?: number; + cl_ord_id?: string; + rebase_multiplier?: 'rebased' | 'base'; } ⋮---- -// Complex nested structures - keeping generic for flexibility -export type FuturesPublicExecutionEvent = FuturesMarketHistoryEventElement; -export type FuturesPublicOrderEvent = FuturesMarketHistoryEventElement; +export interface SpotGetClosedOrdersParams { + trades?: boolean; + userref?: number; + cl_ord_id?: string; + start?: number; + end?: number; + ofs?: number; + closetime?: 'open' | 'close' | 'both'; + consolidate_taker?: boolean; + without_count?: boolean; + rebase_multiplier?: 'rebased' | 'base'; +} ⋮---- -export interface FuturesPublicMarkPriceEvent { - uid: string; - timestamp: number; - event: { - price: string; - }; +export interface SpotQueryOrdersParams { + trades?: boolean; + userref?: number; + txid: string; + consolidate_taker?: boolean; + rebase_multiplier?: 'rebased' | 'base'; } ⋮---- -/** - * Charts - Candles - */ +export interface SpotGetTradesHistoryParams { + type?: + | 'all' + | 'any position' + | 'closed position' + | 'closing position' + | 'no position'; + trades?: boolean; + start?: number; + end?: number; + ofs?: number; + consolidate_taker?: boolean; + ledgers?: boolean; + rebase_multiplier?: 'rebased' | 'base'; +} ⋮---- -export type FuturesTickType = 'spot' | 'mark' | 'trade'; -export type FuturesResolution = - | '1m' - | '5m' - | '15m' - | '30m' - | '1h' - | '4h' - | '12h' - | '1d' - | '1w'; +export interface SpotQueryTradesParams { + txid: string; + trades?: boolean; + rebase_multiplier?: 'rebased' | 'base'; +} ⋮---- -export interface FuturesCandle { - time: number; // Epoch in ms - high: string; - low: string; - open: string; - close: string; - volume: number; +export interface SpotGetOpenPositionsParams { + txid?: string; + docalcs?: boolean; + consolidation?: 'market'; + rebase_multiplier?: 'rebased' | 'base'; } ⋮---- -time: number; // Epoch in ms +export interface SpotGetLedgersInfoParams { + asset?: string; + aclass?: string; + type?: + | 'all' + | 'trade' + | 'deposit' + | 'withdrawal' + | 'transfer' + | 'margin' + | 'adjustment' + | 'rollover' + | 'credit' + | 'settled' + | 'staking' + | 'dividend' + | 'sale' + | 'nft_rebate'; + start?: number; + end?: number; + ofs?: number; + without_count?: boolean; + rebase_multiplier?: 'rebased' | 'base'; +} ⋮---- -export interface FuturesCandles { - candles: FuturesCandle[]; - more_candles: boolean; +export interface SpotQueryLedgersParams { + id: string; + trades?: boolean; + rebase_multiplier?: 'rebased' | 'base'; +} +⋮---- +export interface SpotRequestExportReportParams { + report: 'trades' | 'ledgers'; + format?: 'CSV' | 'TSV'; + description: string; + fields?: string; + starttm?: number; + endtm?: number; } ⋮---- /** - * Charts - Analytics + * Trading */ ⋮---- -export type FuturesAnalyticsType = - | 'open-interest' - | 'aggressor-differential' - | 'trade-volume' - | 'trade-count' - | 'liquidation-volume' - | 'rolling-volatility' - | 'long-short-ratio' - | 'long-short-info' - | 'cvd' - | 'top-traders' - | 'orderbook' - | 'spreads' - | 'liquidity' - | 'slippage' - | 'future-basis'; +export interface SpotSubmitOrderParams { + userref?: number; + cl_ord_id?: string; + ordertype: + | 'market' + | 'limit' + | 'iceberg' + | 'stop-loss' + | 'take-profit' + | 'stop-loss-limit' + | 'take-profit-limit' + | 'trailing-stop' + | 'trailing-stop-limit' + | 'settle-position'; + type: 'buy' | 'sell'; + volume: string; + displayvol?: string; + pair: string; + asset_class?: 'tokenized_asset'; + price?: string; + price2?: string; + trigger?: 'index' | 'last'; + leverage?: string; + reduce_only?: boolean; + stptype?: 'cancel-newest' | 'cancel-oldest' | 'cancel-both'; + oflags?: string; + timeinforce?: 'GTC' | 'IOC' | 'GTD' | 'FOK'; + starttm?: string; + expiretm?: string; + 'close[ordertype]'?: string; + 'close[price]'?: string; + 'close[price2]'?: string; + deadline?: string; + validate?: boolean; +} ⋮---- -export interface FuturesAnalyticsError { - severity: string; - error_class: string; - type: string; - msg: string; - value?: string; - field?: string; +export interface SpotAmendOrderParams { + txid?: string; + cl_ord_id?: string; + order_qty?: string; + display_qty?: string; + limit_price?: string; + trigger_price?: string; + pair?: string; + post_only?: boolean; + deadline?: string; } ⋮---- -export interface FuturesAnalyticsResponse { - result: { - timestamp: number[]; - more: boolean; - data: any; // Complex oneOf structure with multiple types - keeping generic +export interface SpotBatchOrderItem { + userref?: number; + cl_ord_id?: string; + ordertype: + | 'market' + | 'limit' + | 'iceberg' + | 'stop-loss' + | 'take-profit' + | 'stop-loss-limit' + | 'take-profit-limit' + | 'trailing-stop' + | 'trailing-stop-limit' + | 'settle-position'; + type: 'buy' | 'sell'; + volume: string; + displayvol?: string; + price?: string; + price2?: string; + trigger?: 'index' | 'last'; + leverage?: string; + reduce_only?: boolean; + stptype?: 'cancel-newest' | 'cancel-oldest' | 'cancel-both'; + oflags?: string; + timeinforce?: 'GTC' | 'IOC' | 'GTD' | 'FOK'; + starttm?: string; + expiretm?: string; + close?: { + ordertype?: string; + price?: string; + price2?: string; }; - errors: FuturesAnalyticsError[]; } ⋮---- -data: any; // Complex oneOf structure with multiple types - keeping generic +export interface SpotSubmitOrderBatchParams { + orders: SpotBatchOrderItem[]; + pair: string; + asset_class?: 'tokenized_asset'; + broker?: string; + deadline?: string; + validate?: boolean; +} ⋮---- /** - * Auth - API Keys + * Funding */ ⋮---- -export type FuturesApiKeyV3AccessLevel = - | 'NO_ACCESS' - | 'READ_ONLY' - | 'FULL_ACCESS'; +export interface SpotGetDepositMethodsParams { + asset: string; + aclass?: 'currency' | 'tokenized_asset'; + rebase_multiplier?: 'rebased' | 'base'; +} ⋮---- -export interface FuturesApiKeyV3Check { - apiKey: string; // base64 - accountUid: string; // uuid - iiban: string; // Account IIBAN (format: ^AA[A-Z0-9]{2} [A-Z0-9]{4} [A-Z0-9]{4} [A-Z0-9]{4}$) - createdAt: string; // RFC 3339 date-time - permissions: { - general: FuturesApiKeyV3AccessLevel; - transfer: FuturesApiKeyV3AccessLevel; - }; - allowedCidrBlock: string | null; // CIDR format (e.g., 192.168.0.0/16) +export interface SpotGetDepositAddressesParams { + asset: string; + aclass?: 'currency' | 'tokenized_asset'; + method: string; + new?: boolean; + amount?: string | number; } ⋮---- -apiKey: string; // base64 -accountUid: string; // uuid -iiban: string; // Account IIBAN (format: ^AA[A-Z0-9]{2} [A-Z0-9]{4} [A-Z0-9]{4} [A-Z0-9]{4}$) -createdAt: string; // RFC 3339 date-time +export interface SpotGetDepositStatusParams { + asset?: string; + aclass?: 'currency' | 'tokenized_asset'; + method?: string; + start?: string; + end?: string; + cursor?: boolean | string; + limit?: number; + rebase_multiplier?: 'rebased' | 'base'; +} ⋮---- -allowedCidrBlock: string | null; // CIDR format (e.g., 192.168.0.0/16) +export interface SpotGetWithdrawalMethodsParams { + asset?: string; + aclass?: 'currency' | 'tokenized_asset'; + network?: string; + rebase_multiplier?: 'rebased' | 'base'; +} ⋮---- -/** - * Stats - Market Share - */ +export interface SpotGetWithdrawalAddressesParams { + asset?: string; + aclass?: 'currency' | 'tokenized_asset'; + method?: string; + key?: string; + verified?: boolean; +} ⋮---- -export interface FuturesMarketShareContract { - marketShare: string; - volume: string; - usdRebateCredited: string; +export interface SpotGetWithdrawalInfoParams { + asset: string; + key: string; + amount: string; } ⋮---- -export interface FuturesMarketShare { - contracts: Record; +export interface SpotWithdrawFundsParams { + asset: string; + aclass?: 'currency' | 'tokenized_asset'; + key: string; + address?: string; + amount: string; + max_fee?: string; + rebase_multiplier?: 'rebased' | 'base'; } ⋮---- -// trading settings +export interface SpotGetWithdrawalsStatusParams { + asset?: string; + aclass?: 'currency' | 'tokenized_asset'; + method?: string; + start?: string; + end?: string; + cursor?: boolean | string; + limit?: number; + rebase_multiplier?: 'rebased' | 'base'; +} ⋮---- -export type FuturesSelfTradeStrategy = - | 'REJECT_TAKER' - | 'CANCEL_MAKER_SELF' - | 'CANCEL_MAKER_CHILD' - | 'CANCEL_MAKER_ANY'; - -================ -File: src/types/response/partner.types.ts -================ -// Partner API response types +export interface SpotWalletTransferParams { + asset: string; + from: 'Spot Wallet'; + to: 'Futures Wallet'; + amount: string; +} ⋮---- /** - * Create User response + * Subaccounts */ -export interface PartnerCreateUserResponse { - result: { - user: { - iiban: string; // Internet International Bank Account Number (IIBAN), 14-42 characters - }; - }; -} ⋮---- -iiban: string; // Internet International Bank Account Number (IIBAN), 14-42 characters +export interface SpotAccountTransferParams { + asset: string; + asset_class?: 'currency' | 'tokenized_asset'; + amount: string; + from: string; + to: string; +} ⋮---- /** - * Get User response + * Earn */ -export interface PartnerGetUserResponse { - result?: { - user: string; // Kraken-assigned account id, 14-42 characters - external_id?: string; // Optional external ID for the user set by the partner - user_type: 'individual' | 'corporate'; // Type of the user - status: { - state: string; // e.g., "ok" - required_actions?: any[]; // Simplified - array of required action objects - }; - created_at: string; // ISO 8601 datetime - }; -} ⋮---- -user: string; // Kraken-assigned account id, 14-42 characters -external_id?: string; // Optional external ID for the user set by the partner -user_type: 'individual' | 'corporate'; // Type of the user +export interface SpotListEarnStrategiesParams { + ascending?: boolean; + asset?: string; + cursor?: string; + limit?: number; + lock_type?: ('flex' | 'bonded' | 'timed' | 'instant')[]; +} ⋮---- -state: string; // e.g., "ok" -required_actions?: any[]; // Simplified - array of required action objects -⋮---- -created_at: string; // ISO 8601 datetime +export interface SpotListEarnAllocationsParams { + ascending?: boolean; + converted_asset?: string; + hide_zero_allocations?: boolean; +} ⋮---- /** - * Update User response + * Transparency */ -export interface PartnerUpdateUserResponse { - result?: 'success'; +⋮---- +export interface SpotGetPostTradeDataParams { + symbol?: string; + from_ts?: string; + to_ts?: string; + count?: number; } ⋮---- /** - * Submit Verification response + * OAuth */ -export interface PartnerSubmitVerificationResponse { - result?: { - verification_id: string; - }; +⋮---- +export interface OauthGetAccessTokenParams { + grant_type: 'authorization_code' | 'refresh_token'; + code?: string; // Required if grant_type = authorization_code + redirect_uri?: string; // Required if grant_type = authorization_code + refresh_token?: string; // Required if grant_type = refresh_token } ⋮---- -/** - * List Assets response - */ -export interface PartnerListAssetsResponse { - result: { - assets: any[]; // Simplified - array of asset objects - links: any; // Pagination links - meta: { - total_items?: number; - total_pages?: number; - page_size?: number; - page_number?: number; - }; +code?: string; // Required if grant_type = authorization_code +redirect_uri?: string; // Required if grant_type = authorization_code +refresh_token?: string; // Required if grant_type = refresh_token +⋮---- +export interface OauthCreateFastApiKeyParams { + api_key_name: string; // max 32 chars + ip_allowlist: string[]; + nonce_window?: number; + permissions: { + export_data?: boolean; + funds_add?: boolean; + funds_earn?: boolean; + funds_query?: boolean; + funds_withdraw?: boolean; + ledger_query?: boolean; + trades_close?: boolean; + trades_modify?: boolean; + trades_query_closed?: boolean; + trades_query_open?: boolean; }; + query_from?: number; + query_to?: number; + valid_until?: number; } ⋮---- -assets: any[]; // Simplified - array of asset objects -links: any; // Pagination links +api_key_name: string; // max 32 chars ⋮---- -/** - * Get Asset response - */ -export interface PartnerGetAssetResponse { - result: any; // Simplified - asset details object +export interface OauthUpdateFastApiKeyParams { + new_api_key_name?: string; // max 32 chars + api_key_name: string; // max 32 chars + ip_allowlist: string[]; + nonce_window?: number; + permissions: { + export_data?: boolean; + funds_add?: boolean; + funds_earn?: boolean; + funds_query?: boolean; + funds_withdraw?: boolean; + ledger_query?: boolean; + trades_close?: boolean; + trades_modify?: boolean; + trades_query_closed?: boolean; + trades_query_open?: boolean; + }; + query_from?: number; + query_to?: number; + valid_until?: number; } ⋮---- -result: any; // Simplified - asset details object -⋮---- +new_api_key_name?: string; // max 32 chars +api_key_name: string; // max 32 chars + +================ +File: src/types/response/derivatives.types.ts +================ /** - * List Asset Rates response + * Market Data */ -export interface PartnerListAssetRatesResponse { - result: { - rates: Array<{ - timestamp: string; // RFC 3339 datetime - price: string; // decimal128 - }>; - meta: any; // Simplified - metadata object - }; +⋮---- +export interface FuturesTradeHistoryItem { + price: number; + side?: string; // "buy" if taker is buyer, "sell" if taker is seller + size?: string; + time: string; + trade_id?: number; + type?: 'fill' | 'liquidation' | 'assignment' | 'termination' | 'block'; + uid?: string; + instrument_identification_type?: string; + isin?: string; + execution_venue?: string; + price_notation?: string; + price_currency?: string; + notional_amount?: number; + notional_currency?: string; + publication_time?: string; + publication_venue?: string; + transaction_identification_code?: string; + to_be_cleared?: boolean; } ⋮---- -timestamp: string; // RFC 3339 datetime -price: string; // decimal128 +side?: string; // "buy" if taker is buyer, "sell" if taker is seller ⋮---- -meta: any; // Simplified - metadata object +export interface FuturesOrderBook { + asks: [number, number][]; // [price, size] + bids: [number, number][]; // [price, size] +} ⋮---- -/** - * Request Quote response - */ -export interface PartnerRequestQuoteResponse { - result: { - quote_id: string; - type: 'receive' | 'spend'; - status: any; // Simplified - status object - expires: string; // ISO 8601 datetime - spend: any; // Simplified - spend details object - quoted_spend?: any; // Simplified - optional quoted spend object - receive: any; // Simplified - receive details object - quoted_receive?: any; // Simplified - optional quoted receive object - unit_price: any; // Simplified - unit price object - quoted_unit_price?: any; // Simplified - optional quoted unit price object - }; +asks: [number, number][]; // [price, size] +bids: [number, number][]; // [price, size] +⋮---- +export interface TickerGreeks { + iv: number; // Implied volatility, -1.0 if impossible to calculate + delta: number; + gamma: number | null; + vega: number | null; + theta: number | null; + rho: number | null; } ⋮---- -status: any; // Simplified - status object -expires: string; // ISO 8601 datetime -spend: any; // Simplified - spend details object -quoted_spend?: any; // Simplified - optional quoted spend object -receive: any; // Simplified - receive details object -quoted_receive?: any; // Simplified - optional quoted receive object -unit_price: any; // Simplified - unit price object -quoted_unit_price?: any; // Simplified - optional quoted unit price object +iv: number; // Implied volatility, -1.0 if impossible to calculate ⋮---- -/** - * Get Quote response - */ -export interface PartnerGetQuoteResponse { - result?: { - quote_id: string; - transaction_id?: string; - type: 'receive' | 'spend'; - status: any; // Simplified - status object - expires: string; // ISO 8601 datetime - spend: any; // Simplified - spend details object - quoted_spend?: any; // Simplified - optional quoted spend object - receive: any; // Simplified - receive details object - quoted_receive?: any; // Simplified - optional quoted receive object - unit_price: any; // Simplified - unit price object - quoted_unit_price?: any; // Simplified - optional quoted unit price object - }; +export interface FuturesTicker { + symbol: string; + last?: number; + lastTime?: string; + lastSize?: number; + tag: 'perpetual' | 'month' | 'quarter' | 'semiannual'; + pair: string; + markPrice: number; + bid?: number; + bidSize?: number; + ask?: number; + askSize?: number; + vol24h: number; + volumeQuote: number; + openInterest: number; + open24h?: number; + high24h?: number; + low24h?: number; + extrinsicValue?: number; // Only for options + fundingRate?: number; // Only for perpetuals + fundingRatePrediction?: number; // Only for perpetuals + suspended: boolean; + indexPrice: number; + postOnly: boolean; + change24h: number; + greeks?: TickerGreeks; // Only for options + isUnderlyingMarketClosed?: boolean; // Only for tradfi markets } ⋮---- -status: any; // Simplified - status object -expires: string; // ISO 8601 datetime -spend: any; // Simplified - spend details object -quoted_spend?: any; // Simplified - optional quoted spend object -receive: any; // Simplified - receive details object -quoted_receive?: any; // Simplified - optional quoted receive object -unit_price: any; // Simplified - unit price object -quoted_unit_price?: any; // Simplified - optional quoted unit price object +extrinsicValue?: number; // Only for options +fundingRate?: number; // Only for perpetuals +fundingRatePrediction?: number; // Only for perpetuals +⋮---- +greeks?: TickerGreeks; // Only for options +isUnderlyingMarketClosed?: boolean; // Only for tradfi markets ⋮---- /** - * Execute Quote response + * Instrument Details */ -export interface PartnerExecuteQuoteResponse { - result?: { - quote_id: string; - status: any; // Simplified - status object - transaction_id?: string; - }; +⋮---- +export interface FuturesMarginLevel { + contracts?: number | null; + numNonContractUnits?: number | null; + initialMargin: number; + maintenanceMargin: number; } ⋮---- -status: any; // Simplified - status object +export interface FuturesMarginSchedule { + retail: FuturesMarginLevel[]; + professional: FuturesMarginLevel[]; +} ⋮---- -/** - * Get Portfolio Summary response - */ -export interface PartnerGetPortfolioSummaryResponse { - result: { - timestamp: string; // ISO 8601 datetime - currency: string; - portfolio_value: string; // decimal128 - withheld_value: string; // decimal128 - open_orders: string; // decimal128 - available_balance: string; // decimal128 - lots_upnl?: string; // decimal128 - cost_basis?: string; // decimal128 - current_day_pnl?: { - since: string; // ISO 8601 datetime - pnl: string; // decimal128 - }; - }; +export interface FuturesInstrument { + symbol: string; + type: 'flexible_futures' | 'futures_inverse' | 'futures_vanilla'; + tradeable: boolean; + tradfi: boolean; + pair?: string; + base?: string; + quote?: string; + underlying?: string; + tickSize?: number; + contractSize?: number; + contractValueTradePrecision?: number; + impactMidSize?: number; + maxPositionSize?: number; + openingDate?: string; + lastTradingTime?: string; + category?: string; + fundingRateCoefficient?: number; + maxRelativeFundingRate?: number; + isin?: string; + marginSchedules?: Record; + retailMarginLevels?: FuturesMarginLevel[]; + marginLevels?: FuturesMarginLevel[]; + postOnly?: boolean; + /** @deprecated Effective 2026-06-22. Fee schedules are deprecated; use Spot GetTradeVolume instead. */ + feeScheduleUid?: string; + tags?: string[]; + underlyingFuture?: string; + mtf?: boolean; } ⋮---- -timestamp: string; // ISO 8601 datetime -⋮---- -portfolio_value: string; // decimal128 -withheld_value: string; // decimal128 -open_orders: string; // decimal128 -available_balance: string; // decimal128 -lots_upnl?: string; // decimal128 -cost_basis?: string; // decimal128 -⋮---- -since: string; // ISO 8601 datetime -pnl: string; // decimal128 +/** @deprecated Effective 2026-06-22. Fee schedules are deprecated; use Spot GetTradeVolume instead. */ ⋮---- -/** - * Get Portfolio History response - */ -export interface PartnerGetPortfolioHistoryResponse { - result: { - start_date: string; // RFC3339 date - end_date: string; // RFC3339 date - next_cursor?: string; - currency?: string; // AssetName - total_pnl?: string; // decimal128 - total_pnl_pct?: string; // decimal128 - history: any[]; // Simplified - array of historical data points - }; +export interface FuturesInstrumentStatus { + tradeable: string; + experiencingDislocation: boolean; + priceDislocationDirection: 'ABOVE_UPPER_BOUND' | 'BELOW_LOWER_BOUND' | null; + experiencingExtremeVolatility: boolean; + extremeVolatilityInitialMarginMultiplier: number; } ⋮---- -start_date: string; // RFC3339 date -end_date: string; // RFC3339 date -⋮---- -currency?: string; // AssetName -total_pnl?: string; // decimal128 -total_pnl_pct?: string; // decimal128 -history: any[]; // Simplified - array of historical data points -⋮---- /** - * List Portfolio Details response + * Order Management */ -export interface PartnerListPortfolioDetailsResponse { - result?: { - timestamp: string; // ISO 8601 datetime - currency: string; - assets: any[]; // Simplified - array of asset detail objects - }; -} -⋮---- -timestamp: string; // ISO 8601 datetime -⋮---- -assets: any[]; // Simplified - array of asset detail objects ⋮---- -/** - * List Portfolio Transactions response - */ -export interface PartnerListPortfolioTransactionsResponse { - result?: { - transactions: any[]; // Simplified - array of transaction objects - stats?: { - transactions_seen?: number; - }; - next_cursor?: string; - }; +export interface FuturesOrderJson { + orderId: string; + cliOrdId?: string | null; + type: + | 'lmt' + | 'ioc' + | 'post' + | 'liquidation' + | 'assignment' + | 'stp' + | 'unwind' + | 'block' + | 'fok' + | 'unknown'; + symbol: string; + side: 'buy' | 'sell' | 'unknown'; + quantity: number; + filled: number; + limitPrice: number; + reduceOnly: boolean; + timestamp: string; + lastUpdateTimestamp: string; + reducedQuantity?: number | null; } ⋮---- -transactions: any[]; // Simplified - array of transaction objects -⋮---- -/** - * Get Earn Summary response - */ -export interface PartnerGetEarnSummaryResponse { - result: { - auto_earn_eligible: boolean; - auto_earn_enabled: boolean; - auto_earn_last_changed?: string; // ISO 8601 datetime - payout_period: string; // ISO 8601 duration - total_allocated_converted: string; // decimal128 - total_rewarded_converted_true_rates: string; // decimal128 - total_rewarded_converted_current_rate: string; // decimal128 - num_earning_assets: number; // uint32 - upcoming_rewards: any[]; // Simplified - array of upcoming reward objects - }; +export interface FuturesOrderTriggerJson { + uid: string; + clientId: string | null; + type: + | 'lmt' + | 'ioc' + | 'post' + | 'liquidation' + | 'assignment' + | 'stp' + | 'unwind' + | 'fok' + | 'unknown'; + symbol: string; + side: 'buy' | 'sell' | 'unknown'; + quantity: number | null; + limitPrice: number | null; + triggerPrice: number | null; + triggerSide: 'trigger_above' | 'trigger_below' | 'unknown' | null; + triggerSignal: 'mark_price' | 'last_price' | 'spot_price' | 'unknown' | null; + reduceOnly: boolean; + timestamp: string; + lastUpdateTimestamp: string; + startTime: string | null; } ⋮---- -auto_earn_last_changed?: string; // ISO 8601 datetime -payout_period: string; // ISO 8601 duration -total_allocated_converted: string; // decimal128 -total_rewarded_converted_true_rates: string; // decimal128 -total_rewarded_converted_current_rate: string; // decimal128 -num_earning_assets: number; // uint32 -upcoming_rewards: any[]; // Simplified - array of upcoming reward objects -⋮---- -/** - * List Earn Assets response - */ -export interface PartnerListEarnAssetsResponse { - result: { - assets: Record; // Simplified - object with asset names as keys - }; +export interface FuturesPlaceEvent { + type: 'PLACE'; + order: FuturesOrderJson; } ⋮---- -assets: Record; // Simplified - object with asset names as keys -⋮---- -/** - * Toggle Auto-Earn response - */ -export interface PartnerToggleAutoEarnResponse { - result?: any; // Empty/null on success +export interface FuturesCancelEvent { + type: 'CANCEL'; + uid: string; + order: FuturesOrderJson; } ⋮---- -result?: any; // Empty/null on success +export interface FuturesEditEvent { + type: 'EDIT'; + old: FuturesOrderJson; + new: FuturesOrderJson & { reducedQuantity: number | null }; +} ⋮---- -/** - * Withdraw Funds response - */ -export interface PartnerWithdrawFundsResponse { - result?: { - reference_id: string; - }; +export interface FuturesRejectEvent { + type: 'REJECT'; + uid: string; + order: FuturesOrderJson; + reason: 'POST_WOULD_EXECUTE' | 'IOC_WOULD_NOT_EXECUTE'; } ⋮---- -/** - * List Funding Transactions response - */ -export interface PartnerListFundingTransactionsResponse { - result: { - transactions: Array<{ - type: 'withdrawal' | 'deposit'; - date: string; // ISO 8601 datetime - asset: string; - amount: string; // decimal128 - status: - | 'initial' - | 'pending' - | 'settled' - | 'success' - | 'partial' - | 'failure'; - ref_id: string; - }>; - next_cursor?: string; +export interface FuturesExecuteEvent { + type: 'EXECUTION'; + executionId: string; + price: number; + amount: number; + orderPriorEdit: FuturesOrderJson; + orderPriorExecution: FuturesOrderJson & { + takerReducedQuantity: number | null; }; } ⋮---- -date: string; // ISO 8601 datetime +export interface FuturesPlaceTriggerEvent { + type: 'PLACE'; + orderTrigger: FuturesOrderTriggerJson; +} ⋮---- -amount: string; // decimal128 +export interface FuturesCancelTriggerEvent { + type: 'CANCEL'; + uid: string; + orderTrigger: FuturesOrderTriggerJson; +} ⋮---- -/** - * List Settlement Reports response - */ -export interface PartnerListSettlementReportsResponse { - result?: { - reports: Array<{ - id: string; - date: string; // RFC3339 date - type: 'trades' | 'transfers' | 'earn_rewards'; - size: number; // int64, bytes - name: string; - }>; - links: { - self?: string; - first?: string; - last?: string; - prev?: string; - next?: string; - }; - meta: { - total_items?: number; - total_pages?: number; - page_size?: number; - page_number?: number; - }; - }; -} -⋮---- -date: string; // RFC3339 date -⋮---- -size: number; // int64, bytes -⋮---- -/** - * Get Settlement Report response - */ -export interface PartnerGetSettlementReportResponse { - result?: { - id: string; - date: string; // RFC3339 date - type: 'trades' | 'transfers' | 'earn_rewards'; - size: number; // int64, bytes - name: string; - download_url: string; - expires_at: string; // ISO 8601 datetime - }; +export interface FuturesRejectTriggerEvent { + type: 'REJECT'; + uid: string; + orderTrigger: FuturesOrderTriggerJson; + reason: + | 'MARKET_SUSPENDED' + | 'MARKET_NOT_FOUND' + | 'INVALID_PRICE' + | 'INVALID_QUANTITY' + | 'SMALL_ORDER_LIMIT_EXCEEDED' + | 'INSUFFICIENT_MARGIN' + | 'WOULD_CAUSE_LIQUIDATION' + | 'CLIENT_ORDER_ID_IN_USE' + | 'CLIENT_ORDER_ID_TOO_LONG' + | 'MAX_POSITION_EXCEEDED' + | 'PRICE_COLLAR' + | 'PRICE_DISLOCATION' + | 'EDIT_HAS_NO_EFFECT' + | 'ORDER_FOR_CANCELLATION_NOT_FOUND' + | 'ORDER_FOR_EDIT_NOT_FOUND' + | 'ORDER_CANNOT_HAVE_TRIGGER_PRICE' + | 'POST_WOULD_EXECUTE' + | 'IOC_WOULD_NOT_EXECUTE' + | 'WOULD_EXECUTE_SELF' + | 'WOULD_NOT_REDUCE_POSITION' + | 'REJECTED_AFTER_EXECUTION' + | 'MARKET_IS_POST_ONLY' + | 'ORDER_LIMIT_EXCEEDED' + | 'FIXED_LEVERAGE_TOO_HIGH' + | 'CANNOT_EDIT_TRIGGER_PRICE_OF_TRAILING_STOP' + | 'CANNOT_EDIT_LIMIT_PRICE_OF_TRAILING_STOP' + | 'TRAILING_STOP_ORDER_LIMIT_EXCEEDED' + | 'TRAILING_STOP_PERCENT_DEVIATION_EXCEEDS_MAX_DECIMAL_PLACES' + | 'TRAILING_STOP_QUOTE_DEVIATION_NOT_MULTIPLE_OF_TICK_SIZE' + | 'TRAILING_STOP_MAX_DEVIATION_TOO_LARGE' + | 'TRAILING_STOP_MAX_DEVIATION_TOO_SMALL' + | 'INSUFFICIENT_HEADROOM_AROUND_CURRENT_PRICE_TO_EDIT_TRAILING_STOP' + | 'NO_REFERENCE_PRICE_AVAILABLE_FOR_CALCULATING_TRAILING_STOP_TRIGGER_PRICE' + | 'INSUFFICIENT_CLOSING_MARGIN' + | 'LIMIT_PRICE_SET_AS_ABSOLUTE_AND_RELATIVE' + | 'LIMIT_PRICE_OFFSET_VALUE_INVALID' + | 'LIMIT_PRICE_OFFSET_UNIT_INVALID' + | 'LIMIT_PRICE_OFFSET_MUST_HAVE_VALUE_AND_UNIT' + | 'LIMIT_PRICE_OFFSET_QUOTE_CURRENCY_VALUE_MUST_BE_MULTIPLE_OF_TICK_SIZE' + | 'LIMIT_PRICE_OFFSET_PERCENT_VALUE_TOO_MANY_DECIMAL_PLACES' + | 'LIMIT_PRICE_OFFSET_TOO_HIGH' + | 'LIMIT_PRICE_OFFSET_TOO_LOW'; } ⋮---- -date: string; // RFC3339 date -⋮---- -size: number; // int64, bytes -⋮---- -expires_at: string; // ISO 8601 datetime +export type FuturesOrderEvent = + | FuturesPlaceEvent + | FuturesCancelEvent + | FuturesEditEvent + | FuturesRejectEvent + | FuturesExecuteEvent + | FuturesPlaceTriggerEvent + | FuturesCancelTriggerEvent + | FuturesRejectTriggerEvent; ⋮---- -/** - * List Ramp Buy Crypto Assets response - */ -export interface PartnerListRampBuyCryptoAssetsResponse { - result: { - assets: any[]; // Simplified - array of crypto asset objects - }; +export interface FuturesBatchOrderStatus { + cliOrdId?: string; + dateTimeReceived?: string | null; + orderEvents: FuturesOrderEvent[]; + order_id?: string | null; + order_tag?: string | null; + status: + | 'placed' + | 'edited' + | 'cancelled' + | 'invalidOrderType' + | 'invalidSide' + | 'invalidSize' + | 'invalidPrice' + | 'insufficientAvailableFunds' + | 'selfFill' + | 'tooManySmallOrders' + | 'marketSuspended' + | 'marketInactive' + | 'clientOrderIdAlreadyExist' + | 'clientOrderIdTooLong' + | 'outsidePriceCollar' + | 'postWouldExecute' + | 'iocWouldNotExecute'; } ⋮---- -assets: any[]; // Simplified - array of crypto asset objects -⋮---- -/** - * List Ramp Fiat Currencies response - */ -export interface PartnerListRampFiatCurrenciesResponse { - result: { - currencies: Array<{ - asset: string; // AssetName, 3-16 chars - asset_class?: 'currency'; - }>; - }; +export interface FuturesCancelledOrder { + cliOrdId?: string | null; + order_id: string; } ⋮---- -asset: string; // AssetName, 3-16 chars -⋮---- -/** - * List Ramp Payment Methods response - */ -export interface PartnerListRampPaymentMethodsResponse { - result: { - methods: Array<{ - funding_type: string; - external_id?: string; - }>; - }; +export interface FuturesCancelAllOrdersStatus { + cancelOnly: string; + cancelledOrders: FuturesCancelledOrder[]; + orderEvents: FuturesOrderEvent[]; + receivedTime: string; + status: 'noOrdersToCancel' | 'cancelled'; } ⋮---- -/** - * List Ramp Countries response - */ -export interface PartnerListRampCountriesResponse { - result: { - countries: any[]; // Simplified - array of country objects - }; +export interface FuturesDeadMansSwitchStatus { + currentTime: string; + triggerTime: string; } ⋮---- -countries: any[]; // Simplified - array of country objects -⋮---- -/** - * Get Ramp Limits response - */ -export interface PartnerGetRampLimitsResponse { - result: { - limits: any; // Simplified - complex nested limits object - }; +export interface FuturesCancelOrderStatus { + cliOrdId?: string | null; + orderEvents?: FuturesOrderEvent[]; + order_id?: string; + receivedTime?: string; + status: 'cancelled' | 'filled' | 'notFound'; } ⋮---- -limits: any; // Simplified - complex nested limits object -⋮---- -/** - * Get Ramp Prospective Quote response - */ -export interface PartnerGetRampProspectiveQuoteResponse { - result: { - spend: any; // Simplified - asset breakdown object - receive: any; // Simplified - asset breakdown object - unit_price: any; // Simplified - unit price object - }; +export interface FuturesEditOrderStatus { + orderId?: string | null; + cliOrdId?: string | null; + orderEvents: FuturesOrderEvent[]; + receivedTime?: string | null; + status: + | 'edited' + | 'invalidSize' + | 'invalidPrice' + | 'insufficientAvailableFunds' + | 'selfFill' + | 'tooManySmallOrders' + | 'outsidePriceCollar' + | 'postWouldExecute' + | 'wouldNotReducePosition' + | 'orderForEditNotFound' + | 'orderForEditNotAStop'; } ⋮---- -spend: any; // Simplified - asset breakdown object -receive: any; // Simplified - asset breakdown object -unit_price: any; // Simplified - unit price object -⋮---- -/** - * Get Ramp Checkout URL response - */ -export interface PartnerGetRampCheckoutUrlResponse { - result: { - checkout_url: string; // URI - request_data: any; // Simplified - original request payload object - }; +export interface FuturesOpenOrder { + order_id: string; + cliOrdId?: string; + status: 'untouched' | 'partiallyFilled'; + side: 'buy' | 'sell' | 'unknown'; + orderType: 'lmt' | 'stop' | 'take_profit' | 'unknown'; + symbol: string; + limitPrice?: number; + stopPrice?: number; + filledSize: number; + unfilledSize?: number; + reduceOnly: boolean; + triggerSignal?: 'mark' | 'last' | 'spot' | 'unknown'; + lastUpdateTime: string; + receivedTime: string; } ⋮---- -checkout_url: string; // URI -request_data: any; // Simplified - original request payload object -⋮---- -/** Shared price trigger for custom orders (Embed) */ -export interface PartnerCustomOrderPriceTrigger { - type: 'price'; - base_asset: string; - quote_asset: string; - target_price: string; - condition: 'gte' | 'lte'; +export interface FuturesSendOrderStatus { + cliOrdId?: string; + orderEvents?: FuturesOrderEvent[]; + order_id?: string; + receivedTime?: string; + status: + | 'placed' + | 'partiallyFilled' + | 'filled' + | 'cancelled' + | 'edited' + | 'marketSuspended' + | 'marketInactive' + | 'invalidPrice' + | 'invalidSize' + | 'tooManySmallOrders' + | 'insufficientAvailableFunds' + | 'wouldCauseLiquidation' + | 'clientOrderIdAlreadyExist' + | 'clientOrderIdTooBig' + | 'maxPositionViolation' + | 'outsidePriceCollar' + | 'wouldIncreasePriceDislocation' + | 'notFound' + | 'orderForEditNotAStop' + | 'orderForEditNotFound' + | 'postWouldExecute' + | 'iocWouldNotExecute' + | 'selfFill' + | 'wouldNotReducePosition' + | 'marketIsPostOnly' + | 'tooManyOrders' + | 'fixedLeverageTooHigh' + | 'clientOrderIdInvalid' + | 'cannotEditTriggerPriceOfTrailingStop' + | 'cannotEditLimitPriceOfTrailingStop' + | 'wouldProcessAfterSpecifiedTime'; } ⋮---- -/** Shared action object for custom orders (Embed) */ -export interface PartnerCustomOrderAction { - type: 'receive' | 'spend'; - amount: { - asset_class?: 'currency'; - asset: string; - amount: string; - }; - quote: { - asset: string; - fee_bps: string; - spread_bps: string; - }; +export interface FuturesTriggerOptions { + triggerPrice: number; + triggerSide: 'TRIGGER_ABOVE' | 'TRIGGER_BELOW' | 'unknown'; + triggerSignal: 'MARK_PRICE' | 'LAST_PRICE' | 'SPOT_PRICE' | 'unknown'; + triggerTime: string | null; } ⋮---- -/** Single custom order in responses */ -export interface PartnerCustomOrder { - id: string; - name: string; - action: PartnerCustomOrderAction; - trigger: PartnerCustomOrderPriceTrigger; - created_at: string; // date-time - updated_at: string; // date-time +export interface FuturesOrderStatusInfo { + order: { + type: 'TRIGGER_ORDER' | 'ORDER'; + orderId: string; + cliOrdId: string | null; + symbol: string; + side: string; + quantity: number | null; + filled: number | null; + limitPrice: number | null; + reduceOnly: boolean; + timestamp: string; + lastUpdateTimestamp: string; + priceTriggerOptions?: FuturesTriggerOptions; + }; status: - | { status: 'active' } - | { status: 'completed' } - | { status: 'cancelled' } - | { status: 'paused' }; + | 'ENTERED_BOOK' + | 'FULLY_EXECUTED' + | 'REJECTED' + | 'CANCELLED' + | 'TRIGGER_PLACED' + | 'TRIGGER_ACTIVATION_FAILURE'; + updateReason: + | 'LOADING_MARKET' + | 'NEW_USER_ORDER' + | 'LIQUIDATION_ORDER' + | 'STOP_ORDER_TRIGGERED' + | 'LIMIT_FROM_STOP' + | 'PARTIAL_FILL' + | 'FULL_FILL' + | 'CANCELLED_BY_USER' + | 'CONTRACT_EXPIRED' + | 'NOT_ENOUGH_MARGIN' + | 'MARKET_INACTIVE' + | 'DEAD_MAN_SWITCH' + | 'CANCELLED_BY_ADMIN' + | 'POST_WOULD_EXECUTE_REASON' + | 'IOC_WOULD_NOT_EXECUTE_REASON' + | 'WOULD_EXECUTE_SELF_REASON' + | 'WOULD_NOT_REDUCE_POSITION' + | 'EDITED_BY_USER' + | 'ORDER_FOR_EDIT_NOT_FOUND_REASON' + | 'EXPIRED' + | 'TRAILING_STOP_PRICE_UPDATED' + | 'TRAILING_STOP_CANCELLED_AND_REPLACED_BY_ADMIN' + | 'unknown'; + error?: string; // OrderError type - reusing the same errors as FuturesRejectTriggerEvent } ⋮---- -created_at: string; // date-time -updated_at: string; // date-time +error?: string; // OrderError type - reusing the same errors as FuturesRejectTriggerEvent ⋮---- /** - * Create Custom Order response + * Multi-Collateral */ -export interface PartnerCreateCustomOrderResponse { - result?: { - order: PartnerCustomOrder; - }; -} ⋮---- -/** - * List Custom Orders response - */ -export interface PartnerListCustomOrdersResponse { - result?: { - orders: PartnerCustomOrder[]; - next_cursor?: string; - }; +export interface FuturesPnlPreference { + symbol: string; + pnlCurrency: string; } ⋮---- -/** - * Get Custom Order response - */ -export interface PartnerGetCustomOrderResponse { - result?: { - order: PartnerCustomOrder; - }; +export interface FuturesLeveragePreference { + symbol: string; + maxLeverage: number; } ⋮---- /** - * Cancel Custom Order response + * Account Information */ -export interface PartnerCancelCustomOrderResponse { - result?: { - order: PartnerCustomOrder; - }; -} ⋮---- -/** Asset amount object used in quote limits/limits response */ -export interface PartnerQuoteLimitAmount { - asset: string; - amount: string; +export interface FuturesFlexCurrencySummary { + quantity: number; + value: number; + collateral: number; } ⋮---- -/** - * Get Quote Limits response (RFQ) - */ -export interface PartnerGetQuoteLimitsResponse { - result?: { - asset: string; - minimum: string; - maximum: string; - precision: number; - minimum_tradable_amount?: string | null; - minimum_in_display?: PartnerQuoteLimitAmount | null; - maximum_in_display?: PartnerQuoteLimitAmount | null; - minimum_tradable_amount_in_display?: PartnerQuoteLimitAmount | null; - }; +export interface FuturesPortfolioMarginBreakdown { + totalCrossAssetNettedMarketRisk: number; + totalMarketRisk: number; + totalScenarioPnls: number[]; + totalAbsoluteOptionPositionDeltaNotional: number; + netPortfolioDelta: number; + totalPremium: number; + isBuyOnly: boolean; + futuresMaintenanceMargin: number; } ⋮---- -/** Spend/receive breakdown in prospective quote */ -export interface PartnerProspectiveQuoteBreakdown { - asset: string; - asset_class?: 'currency' | null; - total: string; - fee: string; - subtotal: string; +export interface FuturesFlexAccount { + type: 'multiCollateralMarginAccount'; + currencies: Record; + available: number; + initialMargin: number; + initialMarginWithOrders: number; + maintenanceMargin: number; + balanceValue: number; + portfolioValue: number; + collateralValue: number; + pnl: number; + unrealizedFunding: number; + totalUnrealized: number; + totalUnrealizedAsMargin: number; + availableMargin: number; + marginEquity: number; + portfolioMarginBreakdown?: FuturesPortfolioMarginBreakdown; } ⋮---- -/** Unit price in prospective quote */ -export interface PartnerProspectiveQuoteUnitPrice { - asset: string; - asset_class?: 'currency' | null; - unit_price: string; - denomination_asset: string; - denomination_asset_class?: 'currency' | null; +export interface FuturesCashAccount { + type: 'cashAccount'; + balances: Record; } ⋮---- -/** - * Request Prospective Quote response (RFQ) - */ -export interface PartnerRequestProspectiveQuoteResponse { - result?: { - type: 'receive' | 'spend'; - spend: PartnerProspectiveQuoteBreakdown; - receive: PartnerProspectiveQuoteBreakdown; - unit_price: PartnerProspectiveQuoteUnitPrice; - quoted_spend?: PartnerProspectiveQuoteBreakdown | null; - quoted_receive?: PartnerProspectiveQuoteBreakdown | null; - quoted_unit_price?: PartnerProspectiveQuoteUnitPrice | null; +export interface FuturesMarginAccount { + type: 'marginAccount'; + currency: string; + balances: Record; + auxiliary: { + usd: number; + pv: number; + pnl: number; + af: number; + funding: number; + }; + marginRequirements: { + im: number; + mm: number; + lt: number; + tt: number; + }; + triggerEstimates: { + im: number; + mm: number; + lt: number; + tt: number; }; } - -================ -File: src/types/response/shared.types.ts -================ -import { RestClientOptions } from '../../lib/requestUtils.js'; -⋮---- -export type DerivativesAPISuccessResponse = { - result: 'success'; - serverTime: string; -} & TData; ⋮---- -export interface DerivativesAPIErrorResponse { - result: 'error'; - error: string; - serverTime: string; +export interface FuturesAccounts { + cash?: FuturesCashAccount; + flex?: FuturesFlexAccount; + [key: string]: + | FuturesMarginAccount + | FuturesCashAccount + | FuturesFlexAccount + | undefined; } ⋮---- -export type DerivativesAPIResponse = - | DerivativesAPISuccessResponse - | DerivativesAPIErrorResponse; -⋮---- -export type SpotAPISuccessResponse = { - error: string[]; - result: TData; -}; -⋮---- -export interface SpotAPIErrorResponse { - // e.g.{ error: [ 'EGeneral:Invalid arguments:ordertype' ] }, - error: string[]; +export interface FuturesOpenPosition { + symbol: string; + side: 'long' | 'short'; + size: number; + price: number; + fillTime: string; + unrealizedFunding: number | null; + pnlCurrency?: string | null; // USD, EUR, GBP, USDC, USDT, BTC, ETH + maxFixedLeverage?: number | null; } ⋮---- -// e.g.{ error: [ 'EGeneral:Invalid arguments:ordertype' ] }, -⋮---- -export type SpotAPIResponse = - | SpotAPISuccessResponse - | SpotAPIErrorResponse; -⋮---- -export interface GenericAPIError { - code: number; - message: string; - body: TBody; - headers: Record; - requestOptions: RestClientOptions; - requestParams: Record; -} - -================ -File: src/types/response/spot.types.ts -================ -/** - * Market Data - */ +pnlCurrency?: string | null; // USD, EUR, GBP, USDC, USDT, BTC, ETH ⋮---- -export interface SpotSystemStatus { - status: 'online' | 'maintenance' | 'cancel_only' | 'post_only'; - timestamp: string; +export interface FuturesUnwindQueuePosition { + symbol: string; + percentile: number; } ⋮---- -export interface SpotAssetInfo { - aclass: string; - altname: string; - decimals: number; - display_decimals: number; - collateral_value?: number; - status?: string; +export interface FuturesOptionsUserLimitsPerBaseCurrency { + maxTotalPositionSize: number; + maxTotalOpenOrdersSize: number; } ⋮---- -export interface SpotAssetPair { - altname: string; - wsname?: string; - aclass_base: string; - base: string; - aclass_quote: string; - quote: string; - lot?: string; - pair_decimals: number; - cost_decimals: number; - lot_decimals: number; - lot_multiplier: number; - leverage_buy?: number[]; - leverage_sell?: number[]; - fees?: number[][]; - fees_maker?: number[][]; - fee_volume_currency?: string; - margin_call?: number; - margin_stop?: number; - ordermin: string; - costmin?: string; - tick_size?: string; - status?: string; - long_position_limit?: number; - short_position_limit?: number; - execution_venue?: string; +export interface FuturesPortfolioMarginParameters { + crossAssetNettingFactor: number; + extremePriceShockMultiplier: number; + volShockMultiplicationFactor: number; + volShockExponentFactor: number; + optionExpiryTimeShockHours: number; + optionsInitialMarginFactor: number; + totalOptionOrdersConsideredInInitialMarginCalc: number; + priceShockLevels: number[]; + optionsUserLimits: { + maxNetPositionDelta: number; + limitsPerBaseCurrency: Record< + string, + FuturesOptionsUserLimitsPerBaseCurrency + >; + }; } ⋮---- -export interface SpotAssetTickerInfo { - a: string[]; // Ask [price, whole lot volume, lot volume] - b: string[]; // Bid [price, whole lot volume, lot volume] - c: string[]; // Last trade closed [price, lot volume] - v: string[]; // Volume [today, last 24 hours] - p: string[]; // Volume weighted average price [today, last 24 hours] - t: number[]; // Number of trades [today, last 24 hours] - l: string[]; // Low [today, last 24 hours] - h: string[]; // High [today, last 24 hours] - o: string; // Today's opening price +export interface FuturesOptionGreeks { + iv: number; // -1.0 if impossible to calculate + delta: number; + gamma: number | null; + vega: number | null; + theta: number | null; + rho: number | null; } ⋮---- -a: string[]; // Ask [price, whole lot volume, lot volume] -b: string[]; // Bid [price, whole lot volume, lot volume] -c: string[]; // Last trade closed [price, lot volume] -v: string[]; // Volume [today, last 24 hours] -p: string[]; // Volume weighted average price [today, last 24 hours] -t: number[]; // Number of trades [today, last 24 hours] -l: string[]; // Low [today, last 24 hours] -h: string[]; // High [today, last 24 hours] -o: string; // Today's opening price -⋮---- -// [time, open, high, low, close, vwap, volume, count] -export type SpotOHLCData = [ - number, - string, - string, - string, - string, - string, - string, - number, -]; +iv: number; // -1.0 if impossible to calculate ⋮---- -export interface SpotOHLCResponse { - last: number; - [pairName: string]: SpotOHLCData[] | number; +export interface FuturesPortfolioSimulation { + maintenanceMargin: number; + initialMargin: number; + pnl: number; + portfolioMarginBreakdown: FuturesPortfolioMarginBreakdown; + greeks: Record; } ⋮---- -// [price, volume, timestamp] -export type SpotOrderBookEntry = [string, string, number]; -⋮---- -export interface SpotOrderBook { - asks: SpotOrderBookEntry[]; - bids: SpotOrderBookEntry[]; -} +/** + * Assignment Program + */ ⋮---- -export interface SpotOrderBookResponse { - [pairName: string]: SpotOrderBook; +export interface FuturesAssignmentProgramParticipant { + contractType: string; + contract: string | null; + maxSize: number | null; + maxPosition: number | null; + acceptLong: boolean; + acceptShort: boolean; + timeFrame: 'all' | 'weekdays' | 'weekends'; + enabled: boolean; } ⋮---- -// [price, volume, time, buy/sell, market/limit, miscellaneous, trade_id] -export type SpotTradeData = [ - string, - string, - number, - string, - string, - string, - number, -]; -⋮---- -export interface SpotRecentTradesResponse { - last: string; - [pairName: string]: SpotTradeData[] | string; +export interface FuturesAssignmentProgram { + id: number; + participant: FuturesAssignmentProgramParticipant; + contractType: string; + contract: string | null; + maxSize: number | null; + maxPosition: number | null; + acceptLong: boolean; + acceptShort: boolean; + timeFrame: 'all' | 'weekdays' | 'weekends'; + enabled: boolean; } ⋮---- -// [time, bid, ask] -export type SpotSpreadData = [number, string, string]; -⋮---- -export interface SpotRecentSpreadsResponse { - last: number; - [pairName: string]: SpotSpreadData[] | number; +export interface FuturesAssignmentProgramHistory { + deleted: boolean; + participant: FuturesAssignmentProgramParticipant; + contractType: string; + contract: string | null; + maxSize: number | null; + maxPosition: number | null; + acceptLong: boolean; + acceptShort: boolean; + timeFrame: 'all' | 'weekdays' | 'weekends'; + enabled: boolean; + timestamp: string; } ⋮---- /** - * Account Data + * Fee Schedules + * + * @deprecated Effective 2026-06-22. Use Spot GetTradeVolume (SpotClient.getTradingVolume) instead. */ ⋮---- -export interface SpotAccountBalance { - [assetName: string]: string; -} -⋮---- -export interface SpotExtendedBalanceAsset { - balance: string; - credit: string; - credit_used: string; - hold_trade: string; +export interface FuturesFeeTier { + makerFee: number; + takerFee: number; + usdVolume: number; } ⋮---- -export interface SpotExtendedBalance { - [assetName: string]: SpotExtendedBalanceAsset; +export interface FuturesFeeSchedule { + tiers: FuturesFeeTier[]; + name: string; + uid: string; } ⋮---- -export interface SpotCreditLinesAsset { - balance: string; - credit_limit: string; - credit_used: string; - available_credit: string; -} +/** + * General + */ ⋮---- -export interface SpotCreditLinesMonitor { - total_credit_usd: string | null; - total_credit_used_usd: string | null; - total_collateral_value_usd: string | null; - equity_usd: string | null; - ongoing_balance: string | null; - debt_to_equity: string | null; +export interface FuturesNotification { + effectiveTime: string; + note: string; + priority: 'low' | 'medium' | 'high'; + type: + | 'new_feature' + | 'bug_fix' + | 'settlement' + | 'general' + | 'maintenance' + | 'market'; + expectedDowntimeMinutes?: number; } ⋮---- -export interface SpotCreditLines { - asset_details: { - [assetName: string]: SpotCreditLinesAsset; - }; - limits_monitor: SpotCreditLinesMonitor; -} +/** + * Historical Data + */ ⋮---- -export interface SpotTradeBalance { - eb: string; // Equivalent balance - tb: string; // Trade balance - m: string; // Margin amount of open positions - n: string; // Unrealized net profit/loss of open positions - c: string; // Cost basis of open positions - v: string; // Current floating valuation of open positions - e: string; // Equity: trade balance + unrealized net profit/loss - mf: string; // Free margin - ml: string; // Margin level - uv: string; // Unexecuted value +export interface FuturesFill { + cliOrdId?: string | null; + fillTime: string; + fillType: + | 'maker' + | 'taker' + | 'liquidation' + | 'assignor' + | 'assignee' + | 'takerAfterEdit' + | 'unwindBankrupt' + | 'unwindCounterparty'; + fill_id: string; + order_id: string; + price: number; + side: 'buy' | 'sell' | 'unknown'; + size: number; + symbol: string; } ⋮---- -eb: string; // Equivalent balance -tb: string; // Trade balance -m: string; // Margin amount of open positions -n: string; // Unrealized net profit/loss of open positions -c: string; // Cost basis of open positions -v: string; // Current floating valuation of open positions -e: string; // Equity: trade balance + unrealized net profit/loss -mf: string; // Free margin -ml: string; // Margin level -uv: string; // Unexecuted value +/** + * Historical Funding Rates + */ ⋮---- -export interface SpotOpenOrderDescription { - pair: string; - type: 'buy' | 'sell'; - ordertype: - | 'market' - | 'limit' - | 'iceberg' - | 'stop-loss' - | 'take-profit' - | 'stop-loss-limit' - | 'take-profit-limit' - | 'trailing-stop' - | 'trailing-stop-limit' - | 'settle-position'; - price: string; - price2: string; - leverage: string; - order: string; - close: string; +export interface FuturesHistoricalFundingRate { + fundingRate: number; + relativeFundingRate: number; + timestamp: string; } ⋮---- -export interface SpotOpenOrder { - refid: string | null; - userref: number | null; - cl_ord_id: string | null; - status: 'pending' | 'open' | 'closed' | 'canceled' | 'expired'; - opentm: number; - starttm: number; - expiretm: number; - descr: SpotOpenOrderDescription; - vol: string; - vol_exec: string; - cost: string; - fee: string; - price: string; - stopprice: string; - limitprice: string; - trigger?: 'last' | 'index'; - margin?: boolean; - misc: string; - stopped?: string; - touched?: string; - liquidated?: string; - partial?: string; - amended?: string; - sender_sub_id: string | null; - oflags: string; - trades?: string[]; -} +/** + * Subaccounts + */ ⋮---- -export interface SpotOpenOrdersResponse { - open: { - [orderId: string]: SpotOpenOrder; - }; +export interface FuturesHoldingAccount { + currency: string; + amount: number; } ⋮---- -export interface SpotClosedOrder extends SpotOpenOrder { - closetm: number; - reason: string; +export interface FuturesSingleCollateralAccount { + name: string; + availableMargin: number; } ⋮---- -export interface SpotClosedOrdersResponse { - closed: { - [orderId: string]: SpotClosedOrder; - }; - count?: number; +export interface FuturesSubaccountFlexCurrency { + currency: string; + quantity: number; + value: number; + collateral: number; + available: number; } ⋮---- -export interface SpotQueryOrdersResponse { - [orderId: string]: SpotOpenOrder | SpotClosedOrder; +export interface FuturesSubaccountFlexAccount { + currencies: FuturesSubaccountFlexCurrency[]; + initialMargin: number; + initialMarginWithOrders: number; + maintenanceMargin: number; + balanceValue: number; + portfolioValue: number; + collateralValue: number; + pnl: number; + unrealizedFunding: number; + totalUnrealized: number; + totalUnrealizedAsMargin: number; + availableMargin: number; + marginEquity: number; + portfolioMarginBreakdown?: FuturesPortfolioMarginBreakdown; } ⋮---- -export interface SpotOrderAmend { - amend_id: string; - amend_type: 'original' | 'user' | 'restated'; - order_qty: string; - display_qty: string; - remaining_qty: string; - limit_price: string; - trigger_price: string; - reason: string; - post_only: boolean; - timestamp: number; +export interface FuturesSubaccount { + accountUid: string; + email: string; + fullName: string | null; + holdingAccounts: FuturesHoldingAccount[]; + futuresAccounts: FuturesSingleCollateralAccount[]; + flexAccount: FuturesSubaccountFlexAccount; } ⋮---- -export interface SpotOrderAmendsResponse { - count: number; - amends: SpotOrderAmend[]; +export interface FuturesSubaccountsInfo { + masterAccountUid: string; + subaccounts: FuturesSubaccount[]; } ⋮---- -export interface SpotTrade { - ordertxid: string; - postxid: string; - pair: string; - time: number; - type: string; - ordertype: string; - price: string; - cost: string; - fee: string; - vol: string; - margin: string; - leverage: string; - misc: string; - ledgers?: string[]; - trade_id: number; - maker: boolean; - posstatus?: string; - cprice?: number; - ccost?: number; - cfee?: number; - cvol?: number; - cmargin?: number; - net?: number; - trades?: string[]; +/** + * RFQs + */ +⋮---- +export interface FuturesRfqLeg { + symbol: string; + size: number; + markPrice: number; } ⋮---- -export interface SpotTradesHistoryResponse { - count: number; - trades: { - [tradeId: string]: SpotTrade; - }; +export interface FuturesRfq { + rfqUid: string; + expiry: string; + markPrice: number; + legs: FuturesRfqLeg[]; } ⋮---- -export interface SpotQueryTradesResponse { - [tradeId: string]: SpotTrade; +export interface FuturesOpenOffer { + uid: string; + rfqUid: string; + placementDate: string; + lastUpdateDate: string; + bid?: string; + ask?: string; } ⋮---- -export interface SpotOpenPosition { - ordertxid: string; - posstatus: 'open'; - pair: string; - time: number; - type: string; - ordertype: string; - cost: string; - fee: string; - vol: string; - vol_closed: string; - margin: string; - value?: string; - net?: string; - terms: string; - rollovertm: string; - misc: string; - oflags: string; -} -⋮---- -export interface SpotOpenPositionsResponse { - [positionId: string]: SpotOpenPosition; -} -⋮---- -export interface SpotLedgerEntry { - refid: string; - time: number; - type: - | 'none' - | 'trade' - | 'deposit' - | 'withdrawal' - | 'transfer' - | 'margin' - | 'adjustment' - | 'rollover' - | 'spend' - | 'receive' - | 'settled' - | 'credit' - | 'staking' - | 'reward' - | 'dividend' - | 'sale' - | 'conversion' - | 'nfttrade' - | 'nftcreatorfee' - | 'nftrebate' - | 'custodytransfer'; - subtype: string; - aclass: string; - asset: string; - amount: string; - fee: string; - balance: string; -} -⋮---- -export interface SpotLedgersInfoResponse { - ledger: { - [ledgerId: string]: SpotLedgerEntry; - }; - count?: number; -} +/** + * Account History + */ ⋮---- -export interface SpotQueryLedgersResponse { - [ledgerId: string]: SpotLedgerEntry; +export interface FuturesHistoryResponse { + accountUid: string; + len: number; + serverTime: string; + elements: T[]; + continuationToken?: string; } ⋮---- -export interface SpotFeeTierInfo { - fee: string; - min_fee: string; - max_fee: string; - next_fee: string | null; - tier_volume: string | null; - next_volume: string | null; +export interface FuturesHistoryEventElement { + uid: string; + timestamp: number; + event: T; } ⋮---- -export interface SpotTradeVolume { - currency: string; - volume: string; - fees?: { - [pairName: string]: SpotFeeTierInfo; - }; - fees_maker?: { - [pairName: string]: SpotFeeTierInfo; - }; -} +// Complex nested structures with multiple oneOf variants - keeping generic for flexibility +export type FuturesHistoryExecutionEvent = FuturesHistoryEventElement; +export type FuturesHistoryOrderEvent = FuturesHistoryEventElement; +export type FuturesHistoryTriggerEvent = FuturesHistoryEventElement; ⋮---- -export interface SpotRequestExportReportResponse { - id: string; +export interface FuturesPositionUpdateEvent { + accountUid: string; + tradeable: string; + oldPosition: string; + oldAverageEntryPrice: string | null; + newPosition: string; + newAverageEntryPrice: string; + fillTime?: number | null; + fee?: string; + feeCurrency?: string; + realizedPnL?: string; + positionChange: + | 'open' + | 'close' + | 'increase' + | 'decrease' + | 'reverse' + | 'noChange' + | 'unknown'; + executionUid?: string; + executionPrice?: string; + executionSize?: string; + tradeType?: + | 'userExecution' + | 'liquidation' + | 'assignment' + | 'unwind' + | 'unknown'; + fundingRealizationTime?: number; + realizedFunding?: string; + settlementPrice?: string; + timestamp: number; + updateReason: 'trade' | 'fundingRealisation' | 'settlement' | 'unknown'; } ⋮---- -export interface SpotExportReportStatus { - id: string; - descr: string; - format: string; - report: string; - subtype: string; - status: 'Queued' | 'Processing' | 'Processed'; - flags: string; - fields: string; - createdtm: string; - expiretm: string; - starttm: string; - completedtm: string; - datastarttm: string; - dataendtm: string; - aclass: string; +export interface FuturesAccountLogEntry { asset: string; + booking_uid: string; + collateral: string | null; + contract: string | null; + date: string; // RFC 3339 formatted date-time + execution: string | null; + fee: number | null; + funding_rate: number | null; + id: number; + info: string; + margin_account: string; + mark_price: number | null; + new_average_entry_price: number | null; + new_balance: number; + old_average_entry_price: number | null; + old_balance: number; + realized_funding: number | null; + realized_pnl: number | null; + trade_price: number | null; + conversion_spread_percentage?: number | null; + liquidation_fee?: number | null; + exchange_rate?: number; + conversion_fee?: number; + exchange_rate_from?: string; } ⋮---- -export interface SpotDeleteExportReportResponse { - delete?: boolean; - cancel?: boolean; +date: string; // RFC 3339 formatted date-time +⋮---- +export interface FuturesAccountLog { + accountUid: string; + logs: FuturesAccountLogEntry[]; } ⋮---- /** - * Trading + * Market History */ ⋮---- -export interface SpotAddOrderDescription { - order: string; - close?: string; +export interface FuturesMarketHistoryResponse { + len: number; + elements: T[]; + continuationToken?: string; } ⋮---- -export interface SpotSubmitOrderResponse { - descr: SpotAddOrderDescription; - txid: string[]; +export interface FuturesMarketHistoryEventElement { + uid: string; + timestamp: number; + event: T; } ⋮---- -export interface SpotWebSocketsTokenResponse { - token: string; - expires: number; -} +// Complex nested structures - keeping generic for flexibility +export type FuturesPublicExecutionEvent = FuturesMarketHistoryEventElement; +export type FuturesPublicOrderEvent = FuturesMarketHistoryEventElement; ⋮---- -export interface SpotBatchOrderResult { - descr?: { - order: string; +export interface FuturesPublicMarkPriceEvent { + uid: string; + timestamp: number; + event: { + price: string; }; - error?: string; - txid?: string; } ⋮---- /** - * Funding + * Charts - Candles */ ⋮---- -export interface SpotDepositMethod { - method: string; - limit: string | boolean; - fee: string; - 'address-setup-fee': string; - 'gen-address': boolean; - minimum: string; +export type FuturesTickType = 'spot' | 'mark' | 'trade'; +export type FuturesResolution = + | '1m' + | '5m' + | '15m' + | '30m' + | '1h' + | '4h' + | '12h' + | '1d' + | '1w'; +⋮---- +export interface FuturesCandle { + time: number; // Epoch in ms + high: string; + low: string; + open: string; + close: string; + volume: number; } ⋮---- -export interface SpotDepositAddress { - address: string; - expiretm: string; - new: boolean; - tag?: string; +time: number; // Epoch in ms +⋮---- +export interface FuturesCandles { + candles: FuturesCandle[]; + more_candles: boolean; } ⋮---- -export interface SpotDepositStatus { - method: string; - aclass: string; - asset: string; - refid: string; - txid: string; - info: string; - amount: string; - fee: string; - time: number; - status: string; - 'status-prop'?: 'return' | 'onhold'; - originators?: string[]; -} -⋮---- -export interface SpotDepositStatusResponse { - cursor?: string; - [key: string]: SpotDepositStatus[] | string | undefined; -} +/** + * Charts - Analytics + */ ⋮---- -export interface SpotWithdrawalMethod { - asset: string; - method: string; - network: string; - minimum: string; -} +export type FuturesAnalyticsType = + | 'open-interest' + | 'aggressor-differential' + | 'trade-volume' + | 'trade-count' + | 'liquidation-volume' + | 'rolling-volatility' + | 'long-short-ratio' + | 'long-short-info' + | 'cvd' + | 'top-traders' + | 'orderbook' + | 'spreads' + | 'liquidity' + | 'slippage' + | 'future-basis'; ⋮---- -export interface SpotWithdrawalAddress { - address: string; - asset: string; - method: string; - key: string; - tag?: string; - verified: boolean; +export interface FuturesAnalyticsError { + severity: string; + error_class: string; + type: string; + msg: string; + value?: string; + field?: string; } ⋮---- -export interface SpotWithdrawalInfo { - method: string; - limit: string; - amount: string; - fee: string; +export interface FuturesAnalyticsResponse { + result: { + timestamp: number[]; + more: boolean; + data: any; // Complex oneOf structure with multiple types - keeping generic + }; + errors: FuturesAnalyticsError[]; } ⋮---- -export interface SpotWithdrawalStatus { - method: string; - network: string; - aclass: string; - asset: string; - refid: string; - txid: string; - info: string; - amount: string; - fee: string; - time: number; - status: 'Initial' | 'Pending' | 'Settled' | 'Success' | 'Failure'; - 'status-prop'?: - | 'cancel-pending' - | 'canceled' - | 'cancel-denied' - | 'return' - | 'onhold'; - key: string; -} +data: any; // Complex oneOf structure with multiple types - keeping generic ⋮---- /** - * Subaccounts + * Auth - API Keys */ ⋮---- -export interface SpotAccountTransferResponse { - transfer_id: string; - status: string; +export type FuturesApiKeyV3AccessLevel = + | 'NO_ACCESS' + | 'READ_ONLY' + | 'FULL_ACCESS'; +⋮---- +export interface FuturesApiKeyV3Check { + apiKey: string; // base64 + accountUid: string; // uuid + iiban: string; // Account IIBAN (format: ^AA[A-Z0-9]{2} [A-Z0-9]{4} [A-Z0-9]{4} [A-Z0-9]{4}$) + createdAt: string; // RFC 3339 date-time + permissions: { + general: FuturesApiKeyV3AccessLevel; + transfer: FuturesApiKeyV3AccessLevel; + }; + allowedCidrBlock: string | null; // CIDR format (e.g., 192.168.0.0/16) } ⋮---- +apiKey: string; // base64 +accountUid: string; // uuid +iiban: string; // Account IIBAN (format: ^AA[A-Z0-9]{2} [A-Z0-9]{4} [A-Z0-9]{4} [A-Z0-9]{4}$) +createdAt: string; // RFC 3339 date-time +⋮---- +allowedCidrBlock: string | null; // CIDR format (e.g., 192.168.0.0/16) +⋮---- /** - * Earn + * Stats - Market Share */ ⋮---- -export interface SpotEarnAmount { - native: string; - converted: string; +export interface FuturesMarketShareContract { + marketShare: string; + volume: string; + usdRebateCredited: string; } ⋮---- -export interface SpotEarnAllocationDetails { - native: string; - converted: string; - created_at: string; - expires: string; +export interface FuturesMarketShare { + contracts: Record; } ⋮---- -export interface SpotEarnAllocationState { - allocation_count: number; - allocations: SpotEarnAllocationDetails[]; - native: string; - converted: string; -} +// trading settings ⋮---- -export interface SpotEarnPayout { - accumulated_reward: SpotEarnAmount; - estimated_reward: SpotEarnAmount; - period_start: string; - period_end: string; -} +export type FuturesSelfTradeStrategy = + | 'REJECT_TAKER' + | 'CANCEL_MAKER_SELF' + | 'CANCEL_MAKER_CHILD' + | 'CANCEL_MAKER_ANY'; + +================ +File: src/types/response/partner.types.ts +================ +// Partner API response types ⋮---- -export interface SpotEarnAllocation { - strategy_id: string; - native_asset: string; - amount_allocated: { - total: SpotEarnAmount; - bonding?: SpotEarnAllocationState; - exit_queue?: SpotEarnAllocationState; - unbonding?: SpotEarnAllocationState; - pending?: SpotEarnAmount; +/** + * Create User response + */ +export interface PartnerCreateUserResponse { + result: { + user: { + iiban: string; // Internet International Bank Account Number (IIBAN), 14-42 characters + }; }; - total_rewarded: SpotEarnAmount; - payout?: SpotEarnPayout; } ⋮---- -export interface SpotListEarnAllocationsResponse { - converted_asset: string; - total_allocated: string; - total_rewarded: string; - items: SpotEarnAllocation[]; -} +iiban: string; // Internet International Bank Account Number (IIBAN), 14-42 characters ⋮---- -export interface SpotEarnAPREstimate { - low: string; - high: string; +/** + * Get User response + */ +export interface PartnerGetUserResponse { + result?: { + user: string; // Kraken-assigned account id, 14-42 characters + external_id?: string; // Optional external ID for the user set by the partner + user_type: 'individual' | 'corporate'; // Type of the user + status: { + state: string; // e.g., "ok" + required_actions?: any[]; // Simplified - array of required action objects + }; + created_at: string; // ISO 8601 datetime + }; } ⋮---- -export interface SpotEarnAutoCompound { - type: 'disabled' | string; - default?: boolean; -} +user: string; // Kraken-assigned account id, 14-42 characters +external_id?: string; // Optional external ID for the user set by the partner +user_type: 'individual' | 'corporate'; // Type of the user ⋮---- -export interface SpotEarnLockType { - type: 'flex' | 'bonded' | 'timed' | 'instant'; - payout_frequency?: number; - bonding_period?: number; - bonding_period_variable?: boolean; - bonding_rewards?: boolean; - unbonding_period?: number; - unbonding_period_variable?: boolean; - unbonding_rewards?: boolean; - exit_queue_period?: number; -} +state: string; // e.g., "ok" +required_actions?: any[]; // Simplified - array of required action objects ⋮---- -export interface SpotEarnYieldSource { - type: 'staking' | 'off_chain' | string; -} +created_at: string; // ISO 8601 datetime ⋮---- -export interface SpotEarnStrategy { - id: string; - asset: string; - lock_type: SpotEarnLockType; - apr_estimate?: SpotEarnAPREstimate; - user_min_allocation?: string; - allocation_fee: string | number; - deallocation_fee: string | number; - auto_compound: SpotEarnAutoCompound; - yield_source: SpotEarnYieldSource; - can_allocate: boolean; - can_deallocate: boolean; - allocation_restriction_info: string[]; - user_cap?: string; +/** + * Update User response + */ +export interface PartnerUpdateUserResponse { + result?: 'success'; } ⋮---- /** - * Transparency + * Submit Verification response */ -⋮---- -export interface SpotPreTradeLevel { - side: 'BUY' | 'SELL'; - price: string; - qty: string; - count: number; - publication_ts: string; +export interface PartnerSubmitVerificationResponse { + result?: { + verification_id: string; + }; } ⋮---- -export interface SpotPreTradeData { - symbol: string; - description: string; - base_asset: string; - base_notation: 'NOML'; - quote_asset: string; - quote_notation: 'MONE'; - venue: string; - system: 'CLOB'; - bids: SpotPreTradeLevel[]; - asks: SpotPreTradeLevel[]; +/** + * List Assets response + */ +export interface PartnerListAssetsResponse { + result: { + assets: any[]; // Simplified - array of asset objects + links: any; // Pagination links + meta: { + total_items?: number; + total_pages?: number; + page_size?: number; + page_number?: number; + }; + }; } ⋮---- -export interface SpotPostTrade { - trade_id: string; - price: string; - quantity: string; - symbol: string; - description: string; - base_asset: string; - base_notation: 'UNIT'; - quote_asset: string; - quote_notation: 'MONE'; - trade_venue: string; - trade_ts: string; - publication_venue: string; - publication_ts: string; -} +assets: any[]; // Simplified - array of asset objects +links: any; // Pagination links ⋮---- -export interface SpotPostTradeDataResponse { - last_ts: string; - count: number; - trades: SpotPostTrade[]; +/** + * Get Asset response + */ +export interface PartnerGetAssetResponse { + result: any; // Simplified - asset details object } ⋮---- +result: any; // Simplified - asset details object +⋮---- /** - * OAuth + * List Asset Rates response */ -⋮---- -export interface OauthGetAccessTokenResponse { - access_token: string; - token_type: 'bearer'; - expires_in: number; - refresh_token: string; +export interface PartnerListAssetRatesResponse { + result: { + rates: Array<{ + timestamp: string; // RFC 3339 datetime + price: string; // decimal128 + }>; + meta: any; // Simplified - metadata object + }; } ⋮---- -export interface OauthGetUserInfoResponse { +timestamp: string; // RFC 3339 datetime +price: string; // decimal128 +⋮---- +meta: any; // Simplified - metadata object +⋮---- +/** + * Request Quote response + */ +export interface PartnerRequestQuoteResponse { result: { - email: string; - iban: string; + quote_id: string; + type: 'receive' | 'spend'; + status: any; // Simplified - status object + expires: string; // ISO 8601 datetime + spend: any; // Simplified - spend details object + quoted_spend?: any; // Simplified - optional quoted spend object + receive: any; // Simplified - receive details object + quoted_receive?: any; // Simplified - optional quoted receive object + unit_price: any; // Simplified - unit price object + quoted_unit_price?: any; // Simplified - optional quoted unit price object }; } ⋮---- -export interface OauthFastApiKey { - api_key?: string; // Only returned on creation - api_key_name: string; - created_time: string; - id: string; - ip_allowlist: string[]; - last_used: number; - modified_time: string; - nonce: number; - nonce_window: number; - oauth_client: string; - permissions: any; // Simplified - purpose: string; - query_from: number; - query_to: number; - valid_until: number; -} +status: any; // Simplified - status object +expires: string; // ISO 8601 datetime +spend: any; // Simplified - spend details object +quoted_spend?: any; // Simplified - optional quoted spend object +receive: any; // Simplified - receive details object +quoted_receive?: any; // Simplified - optional quoted receive object +unit_price: any; // Simplified - unit price object +quoted_unit_price?: any; // Simplified - optional quoted unit price object ⋮---- -api_key?: string; // Only returned on creation +/** + * Get Quote response + */ +export interface PartnerGetQuoteResponse { + result?: { + quote_id: string; + transaction_id?: string; + type: 'receive' | 'spend'; + status: any; // Simplified - status object + expires: string; // ISO 8601 datetime + spend: any; // Simplified - spend details object + quoted_spend?: any; // Simplified - optional quoted spend object + receive: any; // Simplified - receive details object + quoted_receive?: any; // Simplified - optional quoted receive object + unit_price: any; // Simplified - unit price object + quoted_unit_price?: any; // Simplified - optional quoted unit price object + }; +} ⋮---- -permissions: any; // Simplified +status: any; // Simplified - status object +expires: string; // ISO 8601 datetime +spend: any; // Simplified - spend details object +quoted_spend?: any; // Simplified - optional quoted spend object +receive: any; // Simplified - receive details object +quoted_receive?: any; // Simplified - optional quoted receive object +unit_price: any; // Simplified - unit price object +quoted_unit_price?: any; // Simplified - optional quoted unit price object ⋮---- -export interface OauthCreateFastApiKeyResponse { - result: OauthFastApiKey & { - secret: string; // Only returned on creation +/** + * Execute Quote response + */ +export interface PartnerExecuteQuoteResponse { + result?: { + quote_id: string; + status: any; // Simplified - status object + transaction_id?: string; }; } ⋮---- -secret: string; // Only returned on creation - -================ -File: src/types/response/wsapi.types.ts -================ +status: any; // Simplified - status object +⋮---- /** - * Websocket API v2 Spot Response Types + * Get Portfolio Summary response */ -⋮---- -export interface WSAPIAddSpotOrderResult { - order_id: string; - cl_ord_id?: string; - order_userref?: number; - warnings?: string[]; +export interface PartnerGetPortfolioSummaryResponse { + result: { + timestamp: string; // ISO 8601 datetime + currency: string; + portfolio_value: string; // decimal128 + withheld_value: string; // decimal128 + open_orders: string; // decimal128 + available_balance: string; // decimal128 + lots_upnl?: string; // decimal128 + cost_basis?: string; // decimal128 + current_day_pnl?: { + since: string; // ISO 8601 datetime + pnl: string; // decimal128 + }; + }; } ⋮---- -export interface WSAPIAmendSpotOrderResult { - amend_id: string; - order_id?: string; - cl_ord_id?: string; - warnings?: string[]; -} +timestamp: string; // ISO 8601 datetime ⋮---- -export interface WSAPICancelSpotOrderResult { - order_id: string; - cl_ord_id?: string; - warnings?: string[]; -} +portfolio_value: string; // decimal128 +withheld_value: string; // decimal128 +open_orders: string; // decimal128 +available_balance: string; // decimal128 +lots_upnl?: string; // decimal128 +cost_basis?: string; // decimal128 ⋮---- -export interface WSAPICancelAllSpotOrdersResult { - count: number; - warnings?: string[]; -} +since: string; // ISO 8601 datetime +pnl: string; // decimal128 ⋮---- -export interface WSAPICancelAllSpotOrdersAfterResult { - currentTime: string; - triggerTime: string; - warnings?: string[]; +/** + * Get Portfolio History response + */ +export interface PartnerGetPortfolioHistoryResponse { + result: { + start_date: string; // RFC3339 date + end_date: string; // RFC3339 date + next_cursor?: string; + currency?: string; // AssetName + total_pnl?: string; // decimal128 + total_pnl_pct?: string; // decimal128 + history: any[]; // Simplified - array of historical data points + }; } ⋮---- -export interface WSAPIBatchAddSpotOrdersResult { - order_id: string; - cl_ord_id?: string; - order_userref?: number; - warnings?: string[]; -} +start_date: string; // RFC3339 date +end_date: string; // RFC3339 date ⋮---- -export interface WSAPIBatchCancelSpotOrdersResult { - count: number; - warnings?: string[]; -} +currency?: string; // AssetName +total_pnl?: string; // decimal128 +total_pnl_pct?: string; // decimal128 +history: any[]; // Simplified - array of historical data points ⋮---- -export interface WSAPIEditSpotOrderResult { - order_id: string; - original_order_id: string; - warnings?: string[]; +/** + * List Portfolio Details response + */ +export interface PartnerListPortfolioDetailsResponse { + result?: { + timestamp: string; // ISO 8601 datetime + currency: string; + assets: any[]; // Simplified - array of asset detail objects + }; } - -================ -File: src/types/websockets/ws-subscriptions.ts -================ -] as const; // Note: Admin topics (Status, Heartbeat & Ping are automatically used internally and can't be subscribed to manually). ⋮---- -export type WSSpotPublicTopic = (typeof WS_SPOT_PUBLIC_TOPICS)[number]; +timestamp: string; // ISO 8601 datetime ⋮---- -export type WSSpotPrivateTopic = (typeof WS_SPOT_PRIVATE_TOPICS)[number]; +assets: any[]; // Simplified - array of asset detail objects ⋮---- -export type WSSpotTopic = WSSpotPublicTopic | WSSpotPrivateTopic; +/** + * List Portfolio Transactions response + */ +export interface PartnerListPortfolioTransactionsResponse { + result?: { + transactions: any[]; // Simplified - array of transaction objects + stats?: { + transactions_seen?: number; + }; + next_cursor?: string; + }; +} ⋮---- -export type WSDerivativesPublicTopic = - (typeof WS_DERIVATIVES_PUBLIC_TOPICS)[number]; +transactions: any[]; // Simplified - array of transaction objects ⋮---- -export type WSDerivativesPrivateTopic = - (typeof WS_DERIVATIVES_PRIVATE_TOPICS)[number]; +/** + * Get Earn Summary response + */ +export interface PartnerGetEarnSummaryResponse { + result: { + auto_earn_eligible: boolean; + auto_earn_enabled: boolean; + auto_earn_last_changed?: string; // ISO 8601 datetime + payout_period: string; // ISO 8601 duration + total_allocated_converted: string; // decimal128 + total_rewarded_converted_true_rates: string; // decimal128 + total_rewarded_converted_current_rate: string; // decimal128 + num_earning_assets: number; // uint32 + upcoming_rewards: any[]; // Simplified - array of upcoming reward objects + }; +} ⋮---- -export type WSDerivativesTopic = - | WSDerivativesPublicTopic - | WSDerivativesPrivateTopic; +auto_earn_last_changed?: string; // ISO 8601 datetime +payout_period: string; // ISO 8601 duration +total_allocated_converted: string; // decimal128 +total_rewarded_converted_true_rates: string; // decimal128 +total_rewarded_converted_current_rate: string; // decimal128 +num_earning_assets: number; // uint32 +upcoming_rewards: any[]; // Simplified - array of upcoming reward objects ⋮---- -export type WSTopic = WSSpotTopic | WSDerivativesTopic; - -================ -File: src/InstitutionalClient.ts -================ -import { nanoid } from 'nanoid'; +/** + * List Earn Assets response + */ +export interface PartnerListEarnAssetsResponse { + result: { + assets: Record; // Simplified - object with asset names as keys + }; +} ⋮---- -import { BaseRestClient } from './lib/BaseRestClient.js'; -import { REST_CLIENT_TYPE_ENUM, RestClientType } from './lib/requestUtils.js'; -import { - CustodyDepositAddressesParams, - CustodyDepositMethodsParams, - CustodyGetTransactionParams, - CustodyListActivitiesParams, - CustodyListTasksParams, - CustodyListTransactionsParams, - CustodyListVaultsParams, - CustodyWithdrawAddressesParams, - CustodyWithdrawMethodsParams, - OTCCreateQuoteRequestParams, - OTCUpdateQuoteParams, -} from './types/request/institutional.types.js'; -import { - CustodyDepositAddressesResponse, - CustodyDepositMethodsResponse, - CustodyGetActivityResponse, - CustodyGetTaskResponse, - CustodyGetTransactionResponse, - CustodyGetVaultResponse, - CustodyListActivitiesResponse, - CustodyListTasksResponse, - CustodyListTransactionsResponse, - CustodyListVaultsResponse, - CustodyWithdrawAddressesResponse, - CustodyWithdrawMethodsResponse, - OTCCheckClientResponse, - OTCCreateQuoteResponse, - OTCGetActiveQuotesResponse, - OTCGetExposuresResponse, - OTCGetHistoricalQuotesResponse, - OTCGetPairsResponse, - OTCUpdateQuoteResponse, -} from './types/response/institutional.types.js'; +assets: Record; // Simplified - object with asset names as keys ⋮---- /** - * The InstitutionalClient provides integration to the Kraken Institutional API. - * - * Docs: - * - https://docs.kraken.com/api/docs/custody-api - * - https://docs.kraken.com/api/docs/otc-api + * Toggle Auto-Earn response */ -export class InstitutionalClient extends BaseRestClient +export interface PartnerToggleAutoEarnResponse { + result?: any; // Empty/null on success +} ⋮---- -getClientType(): RestClientType +result?: any; // Empty/null on success ⋮---- /** - * - * Misc Utility Methods - * - */ -⋮---- -generateNewOrderID(): string + * Withdraw Funds response + */ +export interface PartnerWithdrawFundsResponse { + result?: { + reference_id: string; + }; +} ⋮---- /** - * - * Custody REST API - Portfolios - * - */ + * List Funding Transactions response + */ +export interface PartnerListFundingTransactionsResponse { + result: { + transactions: Array<{ + type: 'withdrawal' | 'deposit'; + date: string; // ISO 8601 datetime + asset: string; + amount: string; // decimal128 + status: + | 'initial' + | 'pending' + | 'settled' + | 'success' + | 'partial' + | 'failure'; + ref_id: string; + }>; + next_cursor?: string; + }; +} +⋮---- +date: string; // ISO 8601 datetime +⋮---- +amount: string; // decimal128 ⋮---- /** - * List vaults - * - * Retrieve all vaults within the custody domain. - */ -listCustodyVaults( - params: CustodyListVaultsParams, -): Promise + * List Settlement Reports response + */ +export interface PartnerListSettlementReportsResponse { + result?: { + reports: Array<{ + id: string; + date: string; // RFC3339 date + type: 'trades' | 'transfers' | 'earn_rewards'; + size: number; // int64, bytes + name: string; + }>; + links: { + self?: string; + first?: string; + last?: string; + prev?: string; + next?: string; + }; + meta: { + total_items?: number; + total_pages?: number; + page_size?: number; + page_number?: number; + }; + }; +} +⋮---- +date: string; // RFC3339 date +⋮---- +size: number; // int64, bytes ⋮---- /** - * Get vault information by id - * - * Retrieve information and balances for a specific vault. - */ -getCustodyVaultbyId(params: { + * Get Settlement Report response + */ +export interface PartnerGetSettlementReportResponse { + result?: { id: string; - nonce?: number; -}): Promise + date: string; // RFC3339 date + type: 'trades' | 'transfers' | 'earn_rewards'; + size: number; // int64, bytes + name: string; + download_url: string; + expires_at: string; // ISO 8601 datetime + }; +} ⋮---- -/** - * Get deposit methods - * - * Retrieve the available deposit funding methods for depositing a specific asset. - * The deposit method is required to retrieve deposit addresses using the Get Deposit Addresses API. - */ -getCustodyDepositMethods( - params: CustodyDepositMethodsParams, -): Promise +date: string; // RFC3339 date ⋮---- -/** - * Get deposit addresses - * - * Retrieve (or generate a new) deposit addresses for a particular asset and funding method. - * Use the Get Deposit Methods API to identify the appropriate deposit method. - */ -getCustodyDepositAddresses( - params: CustodyDepositAddressesParams, -): Promise +size: number; // int64, bytes ⋮---- -/** - * List custody transactions - * - * Retrieve the transaction history for a specified vault. - */ -listCustodyTransactions( - params: CustodyListTransactionsParams, -): Promise +expires_at: string; // ISO 8601 datetime ⋮---- /** - * Get transaction by id - * - * Get transaction by id - */ -getCustodyTransactionbyId( - params: CustodyGetTransactionParams, -): Promise + * List Ramp Buy Crypto Assets response + */ +export interface PartnerListRampBuyCryptoAssetsResponse { + result: { + assets: any[]; // Simplified - array of crypto asset objects + }; +} ⋮---- -/** - * - * Custody REST API - Transfers - * - */ +assets: any[]; // Simplified - array of crypto asset objects ⋮---- /** - * Get withdraw methods - * - * Retrieve a list of withdrawal methods available for a specified vault. - */ -getCustodyWithdrawMethods( - params: CustodyWithdrawMethodsParams, -): Promise + * List Ramp Fiat Currencies response + */ +export interface PartnerListRampFiatCurrenciesResponse { + result: { + currencies: Array<{ + asset: string; // AssetName, 3-16 chars + asset_class?: 'currency'; + }>; + }; +} ⋮---- -/** - * Get withdraw addresses - * - * Retrieve a list of withdrawal addresses for a specified vault. - */ -getCustodyWithdrawAddresses( - params: CustodyWithdrawAddressesParams, -): Promise +asset: string; // AssetName, 3-16 chars ⋮---- /** - * - * Custody REST API - Tasks - * - */ + * List Ramp Payment Methods response + */ +export interface PartnerListRampPaymentMethodsResponse { + result: { + methods: Array<{ + funding_type: string; + external_id?: string; + }>; + }; +} ⋮---- /** - * List tasks - * - * Retrieve review tasks that match the specified filter criteria. - */ -listCustodyTasks( - params: CustodyListTasksParams, -): Promise + * List Ramp Countries response + */ +export interface PartnerListRampCountriesResponse { + result: { + countries: any[]; // Simplified - array of country objects + }; +} ⋮---- -/** - * Get task by id - * - * Retrieve details for a specific task. - */ -getCustodyTaskbyId(params: { - id: string; - nonce?: number; -}): Promise +countries: any[]; // Simplified - array of country objects ⋮---- /** - * List activities - * - * Retrieve all activities that match the specified filter criteria. - */ -listCustodyActivities( - params: CustodyListActivitiesParams, -): Promise + * Get Ramp Limits response + */ +export interface PartnerGetRampLimitsResponse { + result: { + limits: any; // Simplified - complex nested limits object + }; +} ⋮---- -/** - * Get activity by id - * - * Retrieve details for a specific task activity. - */ -getCustodyActivitybyId(params: { - id: string; - nonce?: number; -}): Promise +limits: any; // Simplified - complex nested limits object ⋮---- /** - * - * OTC REST API - Quotes - * - */ + * Get Ramp Prospective Quote response + */ +export interface PartnerGetRampProspectiveQuoteResponse { + result: { + spend: any; // Simplified - asset breakdown object + receive: any; // Simplified - asset breakdown object + unit_price: any; // Simplified - unit price object + }; +} ⋮---- -/** - * Create OTC Quote - * - * Creates a new OTC request for quote. - * API Key Permissions Required: Orders and trades - Create & modify orders - */ -createOtcQuoteRequest( - params: OTCCreateQuoteRequestParams, -): Promise +spend: any; // Simplified - asset breakdown object +receive: any; // Simplified - asset breakdown object +unit_price: any; // Simplified - unit price object ⋮---- /** - * Update OTC Quote - * - * Accepts or rejects an OTC quote. - * API Key Permissions Required: Orders and trades - Create & modify orders - */ -updateOtcQuote( - params: OTCUpdateQuoteParams, -): Promise + * Get Ramp Checkout URL response + */ +export interface PartnerGetRampCheckoutUrlResponse { + result: { + checkout_url: string; // URI + request_data: any; // Simplified - original request payload object + }; +} ⋮---- -/** - * Get OTC Pairs - * - * Retrieves the list of OTC trading pairs. - * API Key Permissions Required: Funds permissions - Query and Funds permissions - Deposit - */ -getOtcPairs(params?: +checkout_url: string; // URI +request_data: any; // Simplified - original request payload object ⋮---- -/** - * Get OTC Active Quotes - * - * Retrieves a list of active OTC quotes. - * API Key Permissions Required: Orders and trades - Query open orders & trades - */ -getOtcActiveQuotes(params?: { - nonce?: number; - vault_id?: string; -}): Promise +/** Shared price trigger for custom orders (Embed) */ +export interface PartnerCustomOrderPriceTrigger { + type: 'price'; + base_asset: string; + quote_asset: string; + target_price: string; + condition: 'gte' | 'lte'; +} ⋮---- -/** - * Get OTC Historical Quotes - * - * Retrieves OTC quotes history. - * API Key Permissions Required: Orders and trades - Query open orders & trades - */ -getOtcHistoricalQuotes(params?: { - nonce?: number; -}): Promise +/** Shared action object for custom orders (Embed) */ +export interface PartnerCustomOrderAction { + type: 'receive' | 'spend'; + amount: { + asset_class?: 'currency'; + asset: string; + amount: string; + }; + quote: { + asset: string; + fee_bps: string; + spread_bps: string; + }; +} ⋮---- -/** - * Get OTC Exposures - * - * Retrieves the max and used OTC exposures. - * API Key Permissions Required: Orders and trades - Query open orders & trades - */ -getOtcExposures(params?: { - nonce?: number; -}): Promise +/** Single custom order in responses */ +export interface PartnerCustomOrder { + id: string; + name: string; + action: PartnerCustomOrderAction; + trigger: PartnerCustomOrderPriceTrigger; + created_at: string; // date-time + updated_at: string; // date-time + status: + | { status: 'active' } + | { status: 'completed' } + | { status: 'cancelled' } + | { status: 'paused' }; +} ⋮---- -/** - * Check OTC Eligibility - * - * Retrieves the client permissions for the OTC Portal. - * API Key Permissions Required: Funds permissions - Query and Funds permissions - Deposit - */ -checkOtcClient(params?: - -================ -File: webpack/webpack.config.cjs -================ -function generateConfig(name) +created_at: string; // date-time +updated_at: string; // date-time ⋮---- -// Add '.ts' and '.tsx' as resolvable extensions. +/** + * Create Custom Order response + */ +export interface PartnerCreateCustomOrderResponse { + result?: { + order: PartnerCustomOrder; + }; +} ⋮---- -// Node.js core modules not available in browsers -// The REST client's https.Agent (for keepAlive) is Node.js-only and won't work in browsers +/** + * List Custom Orders response + */ +export interface PartnerListCustomOrdersResponse { + result?: { + orders: PartnerCustomOrder[]; + next_cursor?: string; + }; +} ⋮---- -// Code is already transpiled from TypeScript, no additional loaders needed - -================ -File: jest.config.ts -================ /** - * For a detailed explanation regarding each configuration property, visit: - * https://jestjs.io/docs/configuration + * Get Custom Order response */ +export interface PartnerGetCustomOrderResponse { + result?: { + order: PartnerCustomOrder; + }; +} ⋮---- -import type { Config } from 'jest'; +/** + * Cancel Custom Order response + */ +export interface PartnerCancelCustomOrderResponse { + result?: { + order: PartnerCustomOrder; + }; +} ⋮---- -// All imported modules in your tests should be mocked automatically -// automock: false, -⋮---- -// Stop running tests after `n` failures -// bail: 0, -bail: false, // enable to stop test when an error occur, -⋮---- -// The directory where Jest should store its cached dependency information -// cacheDirectory: "/private/var/folders/kf/2k3sz4px6c9cbyzj1h_b192h0000gn/T/jest_dx", -⋮---- -// Automatically clear mock calls, instances, contexts and results before every test +/** Asset amount object used in quote limits/limits response */ +export interface PartnerQuoteLimitAmount { + asset: string; + amount: string; +} ⋮---- -// Indicates whether the coverage information should be collected while executing the test +/** + * Get Quote Limits response (RFQ) + */ +export interface PartnerGetQuoteLimitsResponse { + result?: { + asset: string; + minimum: string; + maximum: string; + precision: number; + minimum_tradable_amount?: string | null; + minimum_in_display?: PartnerQuoteLimitAmount | null; + maximum_in_display?: PartnerQuoteLimitAmount | null; + minimum_tradable_amount_in_display?: PartnerQuoteLimitAmount | null; + }; +} ⋮---- -// An array of glob patterns indicating a set of files for which coverage information should be collected +/** Spend/receive breakdown in prospective quote */ +export interface PartnerProspectiveQuoteBreakdown { + asset: string; + asset_class?: 'currency' | null; + total: string; + fee: string; + subtotal: string; +} ⋮---- -// The directory where Jest should output its coverage files +/** Unit price in prospective quote */ +export interface PartnerProspectiveQuoteUnitPrice { + asset: string; + asset_class?: 'currency' | null; + unit_price: string; + denomination_asset: string; + denomination_asset_class?: 'currency' | null; +} ⋮---- -// An array of regexp pattern strings used to skip coverage collection -// coveragePathIgnorePatterns: [ -// "/node_modules/" -// ], +/** + * Request Prospective Quote response (RFQ) + */ +export interface PartnerRequestProspectiveQuoteResponse { + result?: { + type: 'receive' | 'spend'; + spend: PartnerProspectiveQuoteBreakdown; + receive: PartnerProspectiveQuoteBreakdown; + unit_price: PartnerProspectiveQuoteUnitPrice; + quoted_spend?: PartnerProspectiveQuoteBreakdown | null; + quoted_receive?: PartnerProspectiveQuoteBreakdown | null; + quoted_unit_price?: PartnerProspectiveQuoteUnitPrice | null; + }; +} + +================ +File: src/types/response/shared.types.ts +================ +import { RestClientOptions } from '../../lib/requestUtils.js'; ⋮---- -// Indicates which provider should be used to instrument code for coverage +export type DerivativesAPISuccessResponse = { + result: 'success'; + serverTime: string; +} & TData; ⋮---- -// A list of reporter names that Jest uses when writing coverage reports -// coverageReporters: [ -// "json", -// "text", -// "lcov", -// "clover" -// ], +export interface DerivativesAPIErrorResponse { + result: 'error'; + error: string; + serverTime: string; +} ⋮---- -// An object that configures minimum threshold enforcement for coverage results -// coverageThreshold: undefined, +export type DerivativesAPIResponse = + | DerivativesAPISuccessResponse + | DerivativesAPIErrorResponse; ⋮---- -// A path to a custom dependency extractor -// dependencyExtractor: undefined, +export type SpotAPISuccessResponse = { + error: string[]; + result: TData; +}; ⋮---- -// Make calling deprecated APIs throw helpful error messages -// errorOnDeprecated: false, +export interface SpotAPIErrorResponse { + // e.g.{ error: [ 'EGeneral:Invalid arguments:ordertype' ] }, + error: string[]; +} ⋮---- -// The default configuration for fake timers -// fakeTimers: { -// "enableGlobally": false -// }, +// e.g.{ error: [ 'EGeneral:Invalid arguments:ordertype' ] }, ⋮---- -// Force coverage collection from ignored files using an array of glob patterns -// forceCoverageMatch: [], +export type SpotAPIResponse = + | SpotAPISuccessResponse + | SpotAPIErrorResponse; ⋮---- -// A path to a module which exports an async function that is triggered once before all test suites -// globalSetup: undefined, +export interface GenericAPIError { + code: number; + message: string; + body: TBody; + headers: Record; + requestOptions: RestClientOptions; + requestParams: Record; +} + +================ +File: src/types/response/spot.types.ts +================ +/** + * Market Data + */ ⋮---- -// A path to a module which exports an async function that is triggered once after all test suites -// globalTeardown: undefined, +export interface SpotSystemStatus { + status: 'online' | 'maintenance' | 'cancel_only' | 'post_only'; + timestamp: string; +} ⋮---- -// A set of global variables that need to be available in all test environments -// globals: {}, +export interface SpotAssetInfo { + aclass: string; + altname: string; + decimals: number; + display_decimals: number; + collateral_value?: number; + status?: string; +} ⋮---- -// The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. -maxWorkers: '1', // run tests sequentially to avoid nonce issues +export interface SpotAssetPair { + altname: string; + wsname?: string; + aclass_base: string; + base: string; + aclass_quote: string; + quote: string; + lot?: string; + pair_decimals: number; + cost_decimals: number; + lot_decimals: number; + lot_multiplier: number; + leverage_buy?: number[]; + leverage_sell?: number[]; + fees?: number[][]; + fees_maker?: number[][]; + fee_volume_currency?: string; + margin_call?: number; + margin_stop?: number; + ordermin: string; + costmin?: string; + tick_size?: string; + status?: string; + long_position_limit?: number; + short_position_limit?: number; + execution_venue?: string; +} ⋮---- -// An array of directory names to be searched recursively up from the requiring module's location -// moduleDirectories: [ -// "node_modules" -// ], +export interface SpotAssetTickerInfo { + a: string[]; // Ask [price, whole lot volume, lot volume] + b: string[]; // Bid [price, whole lot volume, lot volume] + c: string[]; // Last trade closed [price, lot volume] + v: string[]; // Volume [today, last 24 hours] + p: string[]; // Volume weighted average price [today, last 24 hours] + t: number[]; // Number of trades [today, last 24 hours] + l: string[]; // Low [today, last 24 hours] + h: string[]; // High [today, last 24 hours] + o: string; // Today's opening price +} ⋮---- -// An array of file extensions your modules use +a: string[]; // Ask [price, whole lot volume, lot volume] +b: string[]; // Bid [price, whole lot volume, lot volume] +c: string[]; // Last trade closed [price, lot volume] +v: string[]; // Volume [today, last 24 hours] +p: string[]; // Volume weighted average price [today, last 24 hours] +t: number[]; // Number of trades [today, last 24 hours] +l: string[]; // Low [today, last 24 hours] +h: string[]; // High [today, last 24 hours] +o: string; // Today's opening price ⋮---- -// modulePaths: ['src'], +// [time, open, high, low, close, vwap, volume, count] +export type SpotOHLCData = [ + number, + string, + string, + string, + string, + string, + string, + number, +]; ⋮---- -// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module -// moduleNameMapper: {}, +export interface SpotOHLCResponse { + last: number; + [pairName: string]: SpotOHLCData[] | number; +} ⋮---- -// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader -// modulePathIgnorePatterns: [], +// [price, volume, timestamp] +export type SpotOrderBookEntry = [string, string, number]; ⋮---- -// Activates notifications for test results -// notify: false, +export interface SpotOrderBook { + asks: SpotOrderBookEntry[]; + bids: SpotOrderBookEntry[]; +} ⋮---- -// An enum that specifies notification mode. Requires { notify: true } -// notifyMode: "failure-change", +export interface SpotOrderBookResponse { + [pairName: string]: SpotOrderBook; +} ⋮---- -// A preset that is used as a base for Jest's configuration -// preset: undefined, +export interface SpotGroupedBookLevel { + price: string; + qty: string; +} ⋮---- -// Run tests from one or more projects -// projects: undefined, +export interface SpotGroupedBookResponse { + pair: string; + grouping: number; + bids: SpotGroupedBookLevel[]; + asks: SpotGroupedBookLevel[]; +} ⋮---- -// Use this configuration option to add custom reporters to Jest -// reporters: undefined, +export interface SpotLevel3OrderEntry { + price: string; + qty: string; + order_id: string; + timestamp: number; +} ⋮---- -// Automatically reset mock state before every test -// resetMocks: false, +export interface SpotLevel3OrderBookResponse { + pair: string; + bids: SpotLevel3OrderEntry[]; + asks: SpotLevel3OrderEntry[]; +} ⋮---- -// Reset the module registry before running each individual test -// resetModules: false, -⋮---- -// A path to a custom resolver -// resolver: undefined, +// [price, volume, time, buy/sell, market/limit, miscellaneous, trade_id] +export type SpotTradeData = [ + string, + string, + number, + string, + string, + string, + number, +]; ⋮---- -// Automatically restore mock state and implementation before every test -// restoreMocks: false, +export interface SpotRecentTradesResponse { + last: string; + [pairName: string]: SpotTradeData[] | string; +} ⋮---- -// The root directory that Jest should scan for tests and modules within -// rootDir: undefined, +// [time, bid, ask] +export type SpotSpreadData = [number, string, string]; ⋮---- -// A list of paths to directories that Jest should use to search for files in -// roots: [ -// "" -// ], +export interface SpotRecentSpreadsResponse { + last: number; + [pairName: string]: SpotSpreadData[] | number; +} ⋮---- -// Allows you to use a custom runner instead of Jest's default test runner -// runner: "jest-runner", +/** + * Account Data + */ ⋮---- -// The paths to modules that run some code to configure or set up the testing environment before each test -// setupFiles: [], +/** @deprecated Kraken deprecated `.F` suffixed balance assets (Nov 2025). Keys may still appear until removed server-side. */ +export interface SpotAccountBalance { + [assetName: string]: string; +} ⋮---- -// A list of paths to modules that run some code to configure or set up the testing framework before each test -// setupFilesAfterEnv: [], +export interface SpotExtendedBalanceAsset { + balance: string; + credit: string; + credit_used: string; + hold_trade: string; +} ⋮---- -// The number of seconds after which a test is considered as slow and reported as such in the results. -// slowTestThreshold: 5, +export interface SpotExtendedBalance { + [assetName: string]: SpotExtendedBalanceAsset; +} ⋮---- -// A list of paths to snapshot serializer modules Jest should use for snapshot testing -// snapshotSerializers: [], +export interface SpotCreditLinesAsset { + balance: string; + credit_limit: string; + credit_used: string; + available_credit: string; +} ⋮---- -// The test environment that will be used for testing -// testEnvironment: "jest-environment-node", +export interface SpotCreditLinesMonitor { + total_credit_usd: string | null; + total_credit_used_usd: string | null; + total_collateral_value_usd: string | null; + equity_usd: string | null; + ongoing_balance: string | null; + debt_to_equity: string | null; +} ⋮---- -// Options that will be passed to the testEnvironment -// testEnvironmentOptions: {}, +export interface SpotCreditLines { + asset_details: { + [assetName: string]: SpotCreditLinesAsset; + }; + limits_monitor: SpotCreditLinesMonitor; +} ⋮---- -// Adds a location field to test results -// testLocationInResults: false, +export interface SpotTradeBalance { + eb: string; // Equivalent balance + tb: string; // Trade balance + m: string; // Margin amount of open positions + n: string; // Unrealized net profit/loss of open positions + c: string; // Cost basis of open positions + v: string; // Current floating valuation of open positions + e: string; // Equity: trade balance + unrealized net profit/loss + mf: string; // Free margin + ml: string; // Margin level + uv: string; // Unexecuted value +} ⋮---- -// The glob patterns Jest uses to detect test files +eb: string; // Equivalent balance +tb: string; // Trade balance +m: string; // Margin amount of open positions +n: string; // Unrealized net profit/loss of open positions +c: string; // Cost basis of open positions +v: string; // Current floating valuation of open positions +e: string; // Equity: trade balance + unrealized net profit/loss +mf: string; // Free margin +ml: string; // Margin level +uv: string; // Unexecuted value ⋮---- -// "**/__tests__/**/*.[jt]s?(x)", +export interface SpotOpenOrderDescription { + pair: string; + type: 'buy' | 'sell'; + ordertype: + | 'market' + | 'limit' + | 'iceberg' + | 'stop-loss' + | 'take-profit' + | 'stop-loss-limit' + | 'take-profit-limit' + | 'trailing-stop' + | 'trailing-stop-limit' + | 'settle-position'; + price: string; + price2: string; + leverage: string; + order: string; + close: string; +} ⋮---- -// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped -// testPathIgnorePatterns: [ -// "/node_modules/" -// ], +export interface SpotOpenOrder { + refid: string | null; + userref: number | null; + cl_ord_id: string | null; + status: 'pending' | 'open' | 'closed' | 'canceled' | 'expired'; + opentm: number; + starttm: number; + expiretm: number; + descr: SpotOpenOrderDescription; + vol: string; + vol_exec: string; + cost: string; + fee: string; + price: string; + stopprice: string; + limitprice: string; + trigger?: 'last' | 'index'; + margin?: boolean; + misc: string; + stopped?: string; + touched?: string; + liquidated?: string; + partial?: string; + amended?: string; + sender_sub_id: string | null; + oflags: string; + trades?: string[]; +} ⋮---- -// The regexp pattern or array of patterns that Jest uses to detect test files -// testRegex: [], +export interface SpotOpenOrdersResponse { + open: { + [orderId: string]: SpotOpenOrder; + }; +} ⋮---- -// This option allows the use of a custom results processor -// testResultsProcessor: undefined, +export interface SpotClosedOrder extends SpotOpenOrder { + closetm: number; + reason: string; +} ⋮---- -// This option allows use of a custom test runner -// testRunner: "jest-circus/runner", +export interface SpotClosedOrdersResponse { + closed: { + [orderId: string]: SpotClosedOrder; + }; + count?: number; +} ⋮---- -// A map from regular expressions to paths to transformers -// transform: undefined, +export interface SpotQueryOrdersResponse { + [orderId: string]: SpotOpenOrder | SpotClosedOrder; +} ⋮---- -// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation -// transformIgnorePatterns: [ -// "/node_modules/", -// "\\.pnp\\.[^\\/]+$" -// ], +export interface SpotOrderAmend { + amend_id: string; + amend_type: 'original' | 'user' | 'restated'; + order_qty: string; + display_qty: string; + remaining_qty: string; + limit_price: string; + trigger_price: string; + reason: string; + post_only: boolean; + timestamp: number; +} ⋮---- -// Prevents import esm module error from v1 axios release, issue #5026 +export interface SpotOrderAmendsResponse { + count: number; + amends: SpotOrderAmend[]; +} ⋮---- -// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them -// unmockedModulePathPatterns: undefined, +export interface SpotTrade { + ordertxid: string; + postxid: string; + pair: string; + time: number; + type: string; + ordertype: string; + price: string; + cost: string; + fee: string; + vol: string; + margin: string; + leverage: string; + misc: string; + ledgers?: string[]; + trade_id: number; + maker: boolean; + posstatus?: string; + cprice?: number; + ccost?: number; + cfee?: number; + cvol?: number; + cmargin?: number; + net?: number; + trades?: string[]; +} ⋮---- -// Indicates whether each individual test should be reported during the run -// verbose: undefined, -verbose: true, // report individual test +export interface SpotTradesHistoryResponse { + count: number; + trades: { + [tradeId: string]: SpotTrade; + }; +} ⋮---- -// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode -// watchPathIgnorePatterns: [], +export interface SpotQueryTradesResponse { + [tradeId: string]: SpotTrade; +} ⋮---- -// Whether to use watchman for file crawling -// watchman: true, - -================ -File: examples/Derivatives/WebSockets/privateWs.ts -================ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -import { - DefaultLogger, - LogParams, - WebsocketClient, - WS_KEY_MAP, - WSTopicRequest, -} from '../../../src/index.js'; -import { WSDerivativesTopic } from '../../../src/types/websockets/ws-subscriptions.js'; -// normally you should install this module via npm: `npm install @siebly/kraken-api` and import the module: -// import { LogParams, WebsocketClient, WsTopicRequest } from '@siebly/kraken-api'; -⋮---- -// eslint-disable-next-line @typescript-eslint/no-unused-vars -⋮---- -// console.log(new Date(), '--> trace', ...params); -⋮---- -async function start() -⋮---- -/** - * The WebsocketClient is the core class to manage WebSocket subscriptions. Give it the topics you want to subscribe to, and it will handle the rest: - * - Connection management (connect, disconnect, reconnect) - * - Authentication for private topics - * - Subscription management (subscribe, unsubscribe, resubscribe on reconnect) - * - Message handling (dispatch messages to appropriate handlers) - * - * All you need to do is provide the topics you want to subscribe to when calling `subscribe()`, and the client will take care of the rest. - * - * Here we create a WebsocketClient instance with API key/secret for private topic subscriptions. - * - * In terms of product groups such as Spot, Derivatives, etc., the WebsocketClient understand the product group from the WsKey you provide when subscribing. For example, using `WS_KEY_MAP.spotPrivateV2` indicates that the subscription is for Spot private topics, as shown below. - * - * Refer to WS_KEY_MAP in the source code for all available WsKey options. - */ -⋮---- -// Data received +export interface SpotOpenPosition { + ordertxid: string; + posstatus: 'open'; + pair: string; + time: number; + type: string; + ordertype: string; + cost: string; + fee: string; + vol: string; + vol_closed: string; + margin: string; + value?: string; + net?: string; + terms: string; + rollovertm: string; + misc: string; + oflags: string; +} ⋮---- -// Something happened, attempting to reconnect +export interface SpotOpenPositionsResponse { + [positionId: string]: SpotOpenPosition; +} ⋮---- -// Reconnect successful +export interface SpotLedgerEntry { + refid: string; + time: number; + type: + | 'none' + | 'trade' + | 'deposit' + | 'withdrawal' + | 'transfer' + | 'margin' + | 'adjustment' + | 'rollover' + | 'spend' + | 'receive' + | 'settled' + | 'credit' + | 'staking' + | 'reward' + | 'dividend' + | 'sale' + | 'conversion' + | 'nfttrade' + | 'nftcreatorfee' + | 'nftrebate' + | 'custodytransfer'; + subtype: string; + aclass: string; + asset: string; + amount: string; + fee: string; + balance: string; +} ⋮---- -// Connection closed. If unexpected, expect reconnect -> reconnected. +export interface SpotLedgersInfoResponse { + ledger: { + [ledgerId: string]: SpotLedgerEntry; + }; + count?: number; +} ⋮---- -// Reply to a request, e.g. "subscribe"/"unsubscribe"/"authenticate" +export interface SpotQueryLedgersResponse { + [ledgerId: string]: SpotLedgerEntry; +} ⋮---- -/** - * The below examples demonstrate how you can subscribe to private topics. - * - * Note: while the documentation specifies "api_key", "original_challenge" and "signed_challenge" as required parameters, but don't worry about that. The SDK will automatically: - * - Fetch the challenge using your API key, - * - Cache the challenge - * - Include the key, original challenge and signed challenge parameters for you when subscribing to private topics on the derivativesPrivateV1 WebSocket connection. - * - * You do NOT need to manually fetch or provide the "original_challenge" and "signed_challenge" tokens when subscribing to private topics. - * - * Do note that all of these include the "derivativesPrivateV1" WsKey reference. This tells the WebsocketClient to use the private "wss://futures.kraken.com/ws/v1" endpoint for these private subscription requests. It will also automatically authenticate the connection when it is established. - */ +export interface SpotFeeTierInfo { + fee: string; + min_fee: string; + max_fee: string; + next_fee: string | null; + tier_volume: string | null; + next_volume: string | null; +} ⋮---- -/** - * All of the following parameters require API keys for Derivatives APIs. - * - * Note: your "WsTopicRequest" does not need to include "api_key", "original_challenge" and "signed_challenge". See above for details, or below for examples. - */ +export interface SpotTradeVolumeInputs { + domain_spot_volume_30d: string; + domain_futures_volume_30d: string; + domain_assets_on_platform: string; +} ⋮---- -// Open orders: https://docs.kraken.com/api/docs/futures-api/websocket/open_orders +export interface SpotTradeVolumeFeeScheduleTier { + maker_fee: string; + taker_fee: string; + min_spot_volume?: string | null; + min_futures_volume?: string | null; + min_assets_on_platform?: string | null; + active?: boolean | null; +} ⋮---- -// Note: if there are no parameters needed, you can also just request the topic by name -// This is the same as openOrdersTopicRequest, since openOrdersTopicRequest contains no parameters -// client.subscribe('open_orders', WS_KEY_MAP.derivativesPrivateV1); +export interface SpotTradeVolumeFeeSchedule { + pair: string; + class: + | 'currency' + | 'forex' + | 'equity' + | 'equity_pair' + | 'nft' + | 'derivatives' + | 'tokenized_asset' + | 'futures_contract' + | 'volume'; + tiers: SpotTradeVolumeFeeScheduleTier[]; +} +⋮---- +export interface SpotTradeVolumeSubaccount { + iiban: string; + volume: string; +} ⋮---- -// Open orders (verbose): https://docs.kraken.com/api/docs/futures-api/websocket/open_orders +export interface SpotTradeVolume { + currency: string; + asset_class?: + | 'currency' + | 'forex' + | 'equity' + | 'equity_pair' + | 'nft' + | 'derivatives' + | 'tokenized_asset' + | 'futures_contract' + | null; + volume: string; + inputs: SpotTradeVolumeInputs; + fees?: { + [pairName: string]: SpotFeeTierInfo; + } | null; + fees_maker?: { + [pairName: string]: SpotFeeTierInfo; + } | null; + volume_subaccounts?: SpotTradeVolumeSubaccount[]; + schedules?: SpotTradeVolumeFeeSchedule[] | null; +} +⋮---- +export interface SpotApiKeyInfo { + apiKeyName: string; + apiKey: string; + nonce: string; + nonceWindow: number; + permissions: string[]; + iban: string; + validUntil: string; + queryFrom: string; + queryTo: string; + createdTime: string; + modifiedTime: string; + ipAllowlist: string[]; + lastUsed: string | null; +} ⋮---- -// Fills: https://docs.kraken.com/api/docs/futures-api/websocket/fills +export interface SpotRequestExportReportResponse { + id: string; +} ⋮---- -// Optionally, the product_ids field can be used to subscribe only to specific product. -// payload: { -// product_ids: ['PF_XBTUSD'], -// }, +export interface SpotExportReportStatus { + id: string; + descr: string; + format: string; + report: string; + subtype: string; + status: 'Queued' | 'Processing' | 'Processed'; + flags: string; + fields: string; + createdtm: string; + expiretm: string; + starttm: string; + completedtm: string; + datastarttm: string; + dataendtm: string; + aclass: string; + asset: string; +} ⋮---- -// Balances: https://docs.kraken.com/api/docs/futures-api/websocket/balances +export interface SpotDeleteExportReportResponse { + delete?: boolean; + cancel?: boolean; +} ⋮---- -// Open Position: https://docs.kraken.com/api/docs/futures-api/websocket/open_position +/** + * Trading + */ ⋮---- -// Account Log: https://docs.kraken.com/api/docs/futures-api/websocket/account_log +export interface SpotAddOrderDescription { + order: string; + close?: string; +} ⋮---- -// Notification: https://docs.kraken.com/api/docs/futures-api/websocket/notifications - -================ -File: examples/Spot/Private/account.ts -================ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { SpotClient } from '../../../src/index.js'; +export interface SpotSubmitOrderResponse { + descr: SpotAddOrderDescription; + txid: string[]; +} ⋮---- -// This example shows how to call Kraken API endpoint with either node.js, -// javascript (js) or typescript (ts) with the npm module "@siebly/kraken-api" for Kraken exchange -// for ACCOUNT INFORMATION +export interface SpotWebSocketsTokenResponse { + token: string; + expires: number; +} ⋮---- -/** - * import { SpotClient } from '@siebly/kraken-api'; - */ +export interface SpotBatchOrderResult { + descr?: { + order: string; + }; + error?: string; + txid?: string; +} ⋮---- -// initialise the client /** - * - * Kraken API uses API Key and Private Key (base64 encoded) - * - * Example: - * { - * apiKey: 'your-api-key', - * apiSecret: 'your-base64-encoded-private-key', - * } - * - * API Key Permissions Required: - * - Funds permissions - Query - * - Data - Query ledger entries - * + * Funding */ ⋮---- -async function getAccountBalance() -⋮---- -// Get all cash balances (net of pending withdrawals) -⋮---- -// Note: Staking/Earn assets may have these extensions: -// .B - balances in new yield-bearing products -// .F - balances earning automatically in Kraken Rewards -// .T - tokenized assets +export interface SpotDepositMethod { + method: string; + limit: string | boolean; + fee: string; + 'address-setup-fee': string; + 'gen-address': boolean; + minimum: string; +} ⋮---- -async function getExtendedBalance() +export interface SpotDepositAddress { + address: string; + expiretm: string; + new: boolean; + tag?: string; +} ⋮---- -// Get extended balances including credits and held amounts -// Available balance = balance + credit - credit_used - hold_trade -⋮---- -async function getTradeBalance() -⋮---- -// Get trade balance summary (margin info) -⋮---- -// Response includes: -// - eb: equivalent balance -// - tb: trade balance -// - m: margin amount -// - n: unrealized P&L -// - e: equity -// - mf: free margin -⋮---- -async function getLedgers() -⋮---- -// Query specific ledger entries by ID -⋮---- -// Ledger entry types include: -// - trade, deposit, withdrawal, transfer, margin -// - adjustment, rollover, spend, receive, settled -// - credit, staking, reward, dividend, sale, conversion -⋮---- -async function getLedgersInfo() -⋮---- -// Get ledger info with filters (returns 50 most recent by default) -⋮---- -asset: 'XBT', // Filter by asset -type: 'deposit', // Filter by type -⋮---- -async function getTradingVolume() +export interface SpotDepositStatus { + method: string; + aclass: string; + asset: string; + refid: string; + txid: string; + info: string; + amount: string; + fee: string; + time: number; + status: string; + 'status-prop'?: 'return' | 'onhold'; + originators?: string[]; +} ⋮---- -// Get 30-day USD trading volume and fee schedule +export interface SpotDepositStatusResponse { + cursor?: string; + [key: string]: SpotDepositStatus[] | string | undefined; +} ⋮---- -// Response includes: -// - currency: volume currency -// - volume: current trading volume -// - fees: fee schedule by pair -// - fees_maker: maker fee schedule +export interface SpotWithdrawalMethod { + asset: string; + method: string; + network: string; + minimum: string; +} ⋮---- -// Uncomment the function you want to test: +export interface SpotWithdrawalAddress { + address: string; + asset: string; + method: string; + key: string; + tag?: string; + verified: boolean; +} ⋮---- -// getExtendedBalance(); -// getTradeBalance(); -// getLedgers(); -// getLedgersInfo(); -// getTradingVolume(); - -================ -File: examples/Spot/Private/orderManagement.ts -================ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { SpotClient } from '../../../src/index.js'; +export interface SpotWithdrawalInfo { + method: string; + limit: string; + amount: string; + fee: string; +} ⋮---- -// This example shows how to call Kraken API endpoint with either node.js, -// javascript (js) or typescript (ts) with the npm module "@siebly/kraken-api" for Kraken exchange -// for ORDER MANAGEMENT +export interface SpotWithdrawalStatus { + method: string; + network: string; + aclass: string; + asset: string; + refid: string; + txid: string; + info: string; + amount: string; + fee: string; + time: number; + status: 'Initial' | 'Pending' | 'Settled' | 'Success' | 'Failure'; + 'status-prop'?: + | 'cancel-pending' + | 'canceled' + | 'cancel-denied' + | 'return' + | 'onhold'; + key: string; +} ⋮---- /** - * import { SpotClient } from '@siebly/kraken-api'; + * Subaccounts */ ⋮---- -// initialise the client +export interface SpotAccountTransferResponse { + transfer_id: string; + status: string; +} +⋮---- /** - * - * Kraken API uses API Key and Private Key (base64 encoded) - * - * Example: - * { - * apiKey: 'your-api-key', - * apiSecret: 'your-base64-encoded-private-key', - * } - * - * API Key Permissions Required: - * - Funds permissions - Query (for balance) - * - Orders and trades - Query open orders & trades - * - Orders and trades - Query closed orders & trades - * + * Earn */ ⋮---- -async function getTradeBalance() -⋮---- -// Get trade balance summary -⋮---- -async function getOpenOrders() -⋮---- -// Get all open orders -⋮---- -async function getOpenOrdersWithTrades() +export interface SpotEarnAmount { + native: string; + converted: string; +} ⋮---- -// Get open orders with related trades +export interface SpotEarnAllocationDetails { + native: string; + converted: string; + created_at: string; + expires: string; +} ⋮---- -trades: true, // Include trades related to orders +export interface SpotEarnAllocationState { + allocation_count: number; + allocations: SpotEarnAllocationDetails[]; + native: string; + converted: string; +} ⋮---- -async function getOpenOrdersByClientId() +export interface SpotEarnPayout { + accumulated_reward: SpotEarnAmount; + estimated_reward: SpotEarnAmount; + period_start: string; + period_end: string; +} ⋮---- -// Get open orders filtered by client order ID +export interface SpotEarnAllocation { + strategy_id: string; + native_asset: string; + amount_allocated: { + total: SpotEarnAmount; + bonding?: SpotEarnAllocationState; + exit_queue?: SpotEarnAllocationState; + unbonding?: SpotEarnAllocationState; + pending?: SpotEarnAmount; + }; + total_rewarded: SpotEarnAmount; + payout?: SpotEarnPayout; +} ⋮---- -async function getClosedOrders() +export interface SpotListEarnAllocationsResponse { + converted_asset: string; + total_allocated: string; + total_rewarded: string; + items: SpotEarnAllocation[]; +} ⋮---- -// Get closed orders (last 50) +export interface SpotEarnAPREstimate { + low: string; + high: string; +} ⋮---- -async function getClosedOrdersWithFilters() +export interface SpotEarnAutoCompound { + type: 'disabled' | string; + default?: boolean; +} ⋮---- -// Get closed orders with filters +export interface SpotEarnLockType { + type: 'flex' | 'bonded' | 'timed' | 'instant'; + payout_frequency?: number; + bonding_period?: number; + bonding_period_variable?: boolean; + bonding_rewards?: boolean; + unbonding_period?: number; + unbonding_period_variable?: boolean; + unbonding_rewards?: boolean; + exit_queue_period?: number; +} ⋮---- -trades: true, // Include related trades -start: Math.floor(Date.now() / 1000) - 86400 * 7, // Last 7 days -closetime: 'close', // Filter by close time +export interface SpotEarnYieldSource { + type: 'staking' | 'off_chain' | string; +} ⋮---- -async function getClosedOrdersByClientId() +export interface SpotEarnStrategy { + id: string; + asset: string; + lock_type: SpotEarnLockType; + apr_estimate?: SpotEarnAPREstimate; + user_min_allocation?: string; + allocation_fee: string | number; + deallocation_fee: string | number; + auto_compound: SpotEarnAutoCompound; + yield_source: SpotEarnYieldSource; + can_allocate: boolean; + can_deallocate: boolean; + allocation_restriction_info: string[]; + user_cap?: string; +} ⋮---- -// Get closed orders by client order ID +/** + * Transparency + */ ⋮---- -async function getOrdersByTxId() +export interface SpotPreTradeLevel { + side: 'BUY' | 'SELL'; + price: string; + qty: string; + count: number; + publication_ts: string; +} ⋮---- -// Query specific orders by transaction ID +export interface SpotPreTradeData { + symbol: string; + description: string; + base_asset: string; + base_notation: 'NOML'; + quote_asset: string; + quote_notation: 'MONE'; + venue: string; + system: 'CLOB'; + bids: SpotPreTradeLevel[]; + asks: SpotPreTradeLevel[]; +} ⋮---- -// Uncomment the function you want to test: -⋮---- -// getTradeBalance(); -// getOpenOrders(); -// getOpenOrdersWithTrades(); -// getOpenOrdersByClientId(); -// getClosedOrders(); -// getClosedOrdersWithFilters(); -// getClosedOrdersByClientId(); -// getOrdersByTxId(); - -================ -File: examples/Spot/Private/submitOrder.ts -================ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { SpotClient } from '../../../src/index.js'; -⋮---- -// This example shows how to call Kraken API endpoint with either node.js, -// javascript (js) or typescript (ts) with the npm module "@siebly/kraken-api" for Kraken exchange -// for SUBMITTING ORDERS +export interface SpotPostTrade { + trade_id: string; + price: string; + quantity: string; + symbol: string; + description: string; + base_asset: string; + base_notation: 'UNIT'; + quote_asset: string; + quote_notation: 'MONE'; + trade_venue: string; + trade_ts: string; + publication_venue: string; + publication_ts: string; +} ⋮---- -/** - * import { SpotClient } from '@siebly/kraken-api'; - */ +export interface SpotPostTradeDataResponse { + last_ts: string; + count: number; + trades: SpotPostTrade[]; +} ⋮---- -// initialise the client /** - * - * Kraken API uses API Key and Private Key (base64 encoded) - * - * Example: - * { - * apiKey: 'your-api-key', - * apiSecret: 'your-base64-encoded-private-key', - * } - * - * API Key Permissions Required: Orders and trades - Create & modify orders - * + * OAuth */ ⋮---- -async function submitMarketOrder() -⋮---- -// submit market spot order -⋮---- -async function submitLimitOrder() -⋮---- -// Submit limit spot order -⋮---- -async function submitLimitOrderWithFlags() -⋮---- -// Submit post-only limit order (maker-only) -⋮---- -oflags: 'post', // post-only flag -timeinforce: 'GTC', // Good-til-cancelled -⋮---- -async function submitBatchOrders() +export interface OauthGetAccessTokenResponse { + access_token: string; + token_type: 'bearer'; + expires_in: number; + refresh_token: string; +} ⋮---- -// Submit batch of orders (minimum 2, maximum 15) -// All orders must be for the same pair +export interface OauthGetUserInfoResponse { + result: { + email: string; + iban: string; + }; +} ⋮---- -async function submitBatchOrdersValidateOnly() +export interface OauthFastApiKey { + api_key?: string; // Only returned on creation + api_key_name: string; + created_time: string; + id: string; + ip_allowlist: string[]; + last_used: number; + modified_time: string; + nonce: number; + nonce_window: number; + oauth_client: string; + permissions: any; // Simplified + purpose: string; + query_from: number; + query_to: number; + valid_until: number; +} ⋮---- -// Validate batch orders without submitting them +api_key?: string; // Only returned on creation ⋮---- -validate: true, // Only validate, don't submit +permissions: any; // Simplified ⋮---- -// Uncomment the function you want to test: +export interface OauthCreateFastApiKeyResponse { + result: OauthFastApiKey & { + secret: string; // Only returned on creation + }; +} ⋮---- -// submitLimitOrder(); -// submitLimitOrderWithFlags(); -// submitBatchOrders(); -// submitBatchOrdersValidateOnly(); +secret: string; // Only returned on creation ================ -File: examples/Spot/WebSockets/wsAPI.RAW.ts +File: src/InstitutionalClient.ts ================ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -import { - DefaultLogger, - LogParams, - WebsocketClient, - WS_KEY_MAP, -} from '../../../src/index.js'; -// normally you should install this module via npm: `npm install @siebly/kraken-api` and import the module: -// import { DefaultLogger, LogParams, WebsocketClient, WS_KEY_MAP } from '@siebly/kraken-api'; +import { nanoid } from 'nanoid'; ⋮---- -// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { BaseRestClient } from './lib/BaseRestClient.js'; +import { REST_CLIENT_TYPE_ENUM, RestClientType } from './lib/requestUtils.js'; +import { + CustodyDepositAddressesParams, + CustodyDepositMethodsParams, + CustodyGetTransactionParams, + CustodyListActivitiesParams, + CustodyListTasksParams, + CustodyListTransactionsParams, + CustodyListVaultsParams, + CustodyWithdrawAddressesParams, + CustodyWithdrawMethodsParams, + OTCCreateQuoteRequestParams, + OTCUpdateQuoteParams, +} from './types/request/institutional.types.js'; +import { + CustodyDepositAddressesResponse, + CustodyDepositMethodsResponse, + CustodyGetActivityResponse, + CustodyGetTaskResponse, + CustodyGetTransactionResponse, + CustodyGetVaultResponse, + CustodyListActivitiesResponse, + CustodyListTasksResponse, + CustodyListTransactionsResponse, + CustodyListVaultsResponse, + CustodyWithdrawAddressesResponse, + CustodyWithdrawMethodsResponse, + OTCCheckClientResponse, + OTCCreateQuoteResponse, + OTCGetActiveQuotesResponse, + OTCGetExposuresResponse, + OTCGetHistoricalQuotesResponse, + OTCGetPairsResponse, + OTCUpdateQuoteResponse, +} from './types/response/institutional.types.js'; ⋮---- -// console.log('trace', ...params); +/** + * The InstitutionalClient provides integration to the Kraken Institutional API. + * + * Docs: + * - https://docs.kraken.com/api/docs/custody-api + * - https://docs.kraken.com/api/docs/otc-api + */ +export class InstitutionalClient extends BaseRestClient ⋮---- -async function start() +getClientType(): RestClientType ⋮---- /** - * The WebsocketClient is the core class to manage WebSocket subscriptions. Give it the topics you want to subscribe to, and it will handle the rest: - * - Connection management (connect, disconnect, reconnect) - * - Authentication for private topics - * - Subscription management (subscribe, unsubscribe, resubscribe on reconnect) - * - Message handling (dispatch messages to appropriate handlers) * - * All you need to do is provide the topics you want to subscribe to when calling `subscribe()`, and the client will take care of the rest. - * - * Here we create a WebsocketClient instance with API key/secret for private topic subscriptions. - * - * In terms of product groups such as Spot, Derivatives, etc., the WebsocketClient understand the product group from the WsKey you provide when subscribing. For example, using `WS_KEY_MAP.spotPrivateV2` indicates that the subscription is for Spot private topics, as shown below. + * Misc Utility Methods * - * Refer to WS_KEY_MAP in the source code for all available WsKey options. */ ⋮---- -// Data received -⋮---- -// Something happened, attempting to reconnect -⋮---- -// Reconnect successful -⋮---- -// Connection closed. If unexpected, expect reconnect -> reconnected. -⋮---- -// Reply to a request, e.g. "subscribe"/"unsubscribe"/"authenticate" +generateNewOrderID(): string ⋮---- /** - * The below examples demonstrate how you can subscribe to private topics. - * - * Note: while the documentation specifies "token" as a required parameter, the SDK will automatically: - * - fetch the token using your API key/secret, - * - manage token caching/refreshing, - * - include the token in the request for you. * - * So you do NOT need to manually fetch or provide the token when subscribing to private topics. + * Custody REST API - Portfolios * - * Do note that all of these include the "spotPrivateV2" WsKey reference. This tells the WebsocketClient to use the private "wss://ws-auth.kraken.com/v2" endpoint for these private subscription requests. */ - -================ -File: examples/Spot/WebSockets/wsAPI.ts -================ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -import { - DefaultLogger, - LogParams, - WebsocketAPIClient, -} from '../../../src/index.js'; -// normally you should install this module via npm: `npm install @siebly/kraken-api` and import the module: -// import { DefaultLogger, LogParams, WebsocketAPIClient, WS_KEY_MAP } from '@siebly/kraken-api'; -⋮---- -// eslint-disable-next-line @typescript-eslint/no-unused-vars -⋮---- -// console.log('trace', ...params); -⋮---- -async function start() ⋮---- /** - * The WebsocketClient is the core class to manage WebSocket subscriptions. Give it the topics you want to subscribe to, and it will handle the rest: - * - Connection management (connect, disconnect, reconnect) - * - Authentication for private topics - * - Subscription management (subscribe, unsubscribe, resubscribe on reconnect) - * - Message handling (dispatch messages to appropriate handlers) - * - * All you need to do is provide the topics you want to subscribe to when calling `subscribe()`, and the client will take care of the rest. - * - * Here we create a WebsocketClient instance with API key/secret for private topic subscriptions. - * - * In terms of product groups such as Spot, Derivatives, etc., the WebsocketClient understand the product group from the WsKey you provide when subscribing. For example, using `WS_KEY_MAP.spotPrivateV2` indicates that the subscription is for Spot private topics, as shown below. + * List vaults * - * Refer to WS_KEY_MAP in the source code for all available WsKey options. + * Retrieve all vaults within the custody domain. */ +listCustodyVaults( + params: CustodyListVaultsParams, +): Promise ⋮---- /** - * The below examples demonstrate how you can subscribe to private topics. - * - * Note: while the documentation specifies "token" as a required parameter, the SDK will automatically: - * - fetch the token using your API key/secret, - * - manage token caching/refreshing, - * - include the token in the request for you. - * - * So you do NOT need to manually fetch or provide the token when subscribing to private topics. + * Get vault information by id * - * Do note that all of these include the "spotPrivateV2" WsKey reference. This tells the WebsocketClient to use the private "wss://ws-auth.kraken.com/v2" endpoint for these private subscription requests. + * Retrieve information and balances for a specific vault. */ - -================ -File: src/lib/websocket/WsStore.ts -================ -import WebSocket from 'isomorphic-ws'; +getCustodyVaultbyId(params: { + id: string; + nonce?: number; +}): Promise ⋮---- -import { DefaultLogger } from './logger.js'; -import { - DeferredPromise, - WSConnectedResult, - WsConnectionStateEnum, - WsStoredState, -} from './WsStore.types.js'; +/** + * Get deposit methods + * + * Retrieve the available deposit funding methods for depositing a specific asset. + * The deposit method is required to retrieve deposit addresses using the Get Deposit Addresses API. + */ +getCustodyDepositMethods( + params: CustodyDepositMethodsParams, +): Promise ⋮---- /** - * Simple comparison of two objects, recursive for nested objects. Adoped from OKX SDK. - */ -export function isDeepObjectMatch(object1: any, object2: any): boolean + * Get deposit addresses + * + * Retrieve (or generate a new) deposit addresses for a particular asset and funding method. + * Use the Get Deposit Methods API to identify the appropriate deposit method. + */ +getCustodyDepositAddresses( + params: CustodyDepositAddressesParams, +): Promise ⋮---- -// console.log('not same key count', { keys1, keys2 }); -// not the same amount of keys or keys don't match +/** + * List custody transactions + * + * Retrieve the transaction history for a specified vault. + */ +listCustodyTransactions( + params: CustodyListTransactionsParams, +): Promise ⋮---- -// console.log('not same key names: ', { keys1, keys2 }); +/** + * Get transaction by id + * + * Get transaction by id + */ +getCustodyTransactionbyId( + params: CustodyGetTransactionParams, +): Promise ⋮---- -type DeferredPromiseRef = - (typeof DEFERRED_PROMISE_REF)[keyof typeof DEFERRED_PROMISE_REF]; +/** + * + * Custody REST API - Transfers + * + */ ⋮---- -export class WsStore< -WsKey extends string, +/** + * Get withdraw methods + * + * Retrieve a list of withdrawal methods available for a specified vault. + */ +getCustodyWithdrawMethods( + params: CustodyWithdrawMethodsParams, +): Promise ⋮---- -constructor(logger: DefaultLogger) +/** + * Get withdraw addresses + * + * Retrieve a list of withdrawal addresses for a specified vault. + */ +getCustodyWithdrawAddresses( + params: CustodyWithdrawAddressesParams, +): Promise ⋮---- -/** Get WS stored state for key, optionally create if missing */ -get( - key: WsKey, - createIfMissing?: true, - ): WsStoredState; +/** + * + * Custody REST API - Tasks + * + */ ⋮---- -get( - key: WsKey, - createIfMissing?: false, - ): WsStoredState | undefined; +/** + * List tasks + * + * Retrieve review tasks that match the specified filter criteria. + */ +listCustodyTasks( + params: CustodyListTasksParams, +): Promise ⋮---- -get( - key: WsKey, - createIfMissing?: boolean, -): WsStoredState | undefined +/** + * Get task by id + * + * Retrieve details for a specific task. + */ +getCustodyTaskbyId(params: { + id: string; + nonce?: number; +}): Promise ⋮---- -getKeys(): WsKey[] +/** + * List activities + * + * Retrieve all activities that match the specified filter criteria. + */ +listCustodyActivities( + params: CustodyListActivitiesParams, +): Promise ⋮---- -create(key: WsKey): WsStoredState | undefined +/** + * Get activity by id + * + * Retrieve details for a specific task activity. + */ +getCustodyActivitybyId(params: { + id: string; + nonce?: number; +}): Promise ⋮---- -delete(key: WsKey): void +/** + * + * OTC REST API - Quotes + * + */ ⋮---- -// TODO: should we allow this at all? Perhaps block this from happening... +/** + * Create OTC Quote + * + * Creates a new OTC request for quote. + * API Key Permissions Required: Orders and trades - Create & modify orders + */ +createOtcQuoteRequest( + params: OTCCreateQuoteRequestParams, +): Promise ⋮---- -/* connection websocket */ +/** + * Update OTC Quote + * + * Accepts or rejects an OTC quote. + * API Key Permissions Required: Orders and trades - Create & modify orders + */ +updateOtcQuote( + params: OTCUpdateQuoteParams, +): Promise ⋮---- -hasExistingActiveConnection(key: WsKey): boolean +/** + * Get OTC Pairs + * + * Retrieves the list of OTC trading pairs. + * API Key Permissions Required: Funds permissions - Query and Funds permissions - Deposit + */ +getOtcPairs(params?: ⋮---- -getWs(key: WsKey): WebSocket | undefined +/** + * Get OTC Active Quotes + * + * Retrieves a list of active OTC quotes. + * API Key Permissions Required: Orders and trades - Query open orders & trades + */ +getOtcActiveQuotes(params?: { + nonce?: number; + vault_id?: string; +}): Promise ⋮---- -setWs(key: WsKey, wsConnection: WebSocket): WebSocket +/** + * Get OTC Historical Quotes + * + * Retrieves OTC quotes history. + * API Key Permissions Required: Orders and trades - Query open orders & trades + */ +getOtcHistoricalQuotes(params?: { + nonce?: number; +}): Promise ⋮---- /** - * deferred promises + * Get OTC Exposures + * + * Retrieves the max and used OTC exposures. + * API Key Permissions Required: Orders and trades - Query open orders & trades */ +getOtcExposures(params?: { + nonce?: number; +}): Promise ⋮---- -getDeferredPromise( - wsKey: WsKey, - promiseRef: string | DeferredPromiseRef, -): DeferredPromise | undefined +/** + * Check OTC Eligibility + * + * Retrieves the client permissions for the OTC Portal. + * API Key Permissions Required: Funds permissions - Query and Funds permissions - Deposit + */ +checkOtcClient(params?: + +================ +File: webpack/webpack.config.cjs +================ +function generateConfig(name) ⋮---- -createDeferredPromise( - wsKey: WsKey, - promiseRef: string | DeferredPromiseRef, - throwIfExists: boolean, -): DeferredPromise +// Add '.ts' and '.tsx' as resolvable extensions. ⋮---- -// console.log('existing promise'); +// Node.js core modules not available in browsers +// The REST client's https.Agent (for keepAlive) is Node.js-only and won't work in browsers ⋮---- -// console.log('create promise'); +// Code is already transpiled from TypeScript, no additional loaders needed + +================ +File: jest.config.ts +================ +/** + * For a detailed explanation regarding each configuration property, visit: + * https://jestjs.io/docs/configuration + */ ⋮---- -// TODO: Once stable, use Promise.withResolvers in future +import type { Config } from 'jest'; ⋮---- -resolveDeferredPromise( - wsKey: WsKey, - promiseRef: string | DeferredPromiseRef, - value: unknown, - removeAfter: boolean, -): void +// All imported modules in your tests should be mocked automatically +// automock: false, ⋮---- -rejectDeferredPromise( - wsKey: WsKey, - promiseRef: string | DeferredPromiseRef, - value: unknown, - removeAfter: boolean, -): void +// Stop running tests after `n` failures +// bail: 0, +bail: false, // enable to stop test when an error occur, ⋮---- -removeDeferredPromise( - wsKey: WsKey, - promiseRef: string | DeferredPromiseRef, -): void +// The directory where Jest should store its cached dependency information +// cacheDirectory: "/private/var/folders/kf/2k3sz4px6c9cbyzj1h_b192h0000gn/T/jest_dx", ⋮---- -// Just in case it's pending +// Automatically clear mock calls, instances, contexts and results before every test ⋮---- -rejectAllDeferredPromises(wsKey: WsKey, reason: string): void +// Indicates whether the coverage information should be collected while executing the test ⋮---- -// Skip reserved keys, such as the connection promise +// An array of glob patterns indicating a set of files for which coverage information should be collected ⋮---- -/** Get promise designed to track a connection attempt in progress. Resolves once connected. */ -getConnectionInProgressPromise( - wsKey: WsKey, -): DeferredPromise | undefined +// The directory where Jest should output its coverage files ⋮---- -getAuthenticationInProgressPromise( - wsKey: WsKey, -): DeferredPromise +// Indicates which provider should be used to instrument code for coverage ⋮---- -createAuthenticationInProgressPromise( - wsKey: WsKey, - throwIfExists: boolean, -): DeferredPromise +// An array of file extensions your modules use ⋮---- -getTopicsAsArray(key: WsKey): TWSTopicSubscribeEventArgs[] +// modulePaths: ['src'], ⋮---- -getTopicsByKey(): Record> +// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module +// moduleNameMapper: {}, ⋮---- -/** - * Find matching "topic" request from the store - * @param key - * @param topic - * @returns - */ -getMatchingTopic(key: WsKey, topic: TWSTopicSubscribeEventArgs) +// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader +// modulePathIgnorePatterns: [], ⋮---- -addTopic(key: WsKey, topic: TWSTopicSubscribeEventArgs) +// Activates notifications for test results +// notify: false, ⋮---- -// Check for duplicate topic. If already tracked, don't store this one +// An enum that specifies notification mode. Requires { notify: true } +// notifyMode: "failure-change", ⋮---- -deleteTopic(key: WsKey, topic: TWSTopicSubscribeEventArgs) +// A preset that is used as a base for Jest's configuration +// preset: undefined, ⋮---- -// Check if we're subscribed to a topic like this - -================ -File: src/types/request/derivatives.types.ts -================ -/** - * Order Management - */ +// Run tests from one or more projects +// projects: undefined, ⋮---- -export interface FuturesBatchOrderSend { - order: 'send'; - order_tag: string; - orderType: - | 'lmt' - | 'post' - | 'ioc' - | 'mkt' - | 'stp' - | 'take_profit' - | 'trailing_stop' - | 'fok'; - symbol: string; - side: 'buy' | 'sell'; - size: number; - limitPrice?: number; - stopPrice?: number; - cliOrdId?: string; - triggerSignal?: 'mark' | 'index' | 'last'; - reduceOnly?: boolean; - trailingStopMaxDeviation?: number; - trailingStopDeviationUnit?: 'PERCENT' | 'QUOTE_CURRENCY' | 'unknown'; -} +// Use this configuration option to add custom reporters to Jest +// reporters: undefined, ⋮---- -export interface FuturesBatchOrderEdit { - order: 'edit'; - order_id: string; - cliOrdId?: string | null; - size?: number; - limitPrice?: number; - stopPrice?: number; - trailingStopMaxDeviation?: number; - trailingStopDeviationUnit?: 'PERCENT' | 'QUOTE_CURRENCY' | 'unknown'; - qtyMode?: 'ABSOLUTE' | 'RELATIVE'; -} +// Automatically reset mock state before every test +// resetMocks: false, ⋮---- -export interface FuturesBatchOrderCancel { - order: 'cancel'; - order_id?: string; - cliOrdId?: string; -} +// Reset the module registry before running each individual test +// resetModules: false, ⋮---- -export interface FuturesBatchOrderParams { - ProcessBefore?: string; - json: { - batchOrder: ( - | FuturesBatchOrderSend - | FuturesBatchOrderEdit - | FuturesBatchOrderCancel - )[]; - }; -} +// A path to a custom resolver +// resolver: undefined, ⋮---- -export interface FuturesCancelOrderParams { - processBefore?: string; - order_id?: string; - cliOrdId?: string; -} +// Automatically restore mock state and implementation before every test +// restoreMocks: false, ⋮---- -export interface FuturesEditOrderParams { - processBefore?: string; - orderId?: string; - cliOrdId?: string; - size?: number; - limitPrice?: number; - stopPrice?: number; - trailingStopMaxDeviation?: number; - trailingStopDeviationUnit?: 'PERCENT' | 'QUOTE_CURRENCY' | 'unknown'; - qtyMode?: 'ABSOLUTE' | 'RELATIVE'; -} +// The root directory that Jest should scan for tests and modules within +// rootDir: undefined, ⋮---- -export interface FuturesSendOrderParams { - processBefore?: string; - orderType: - | 'lmt' - | 'post' - | 'ioc' - | 'mkt' - | 'stp' - | 'take_profit' - | 'trailing_stop' - | 'fok'; - symbol: string; - side: 'buy' | 'sell'; - size: number; - limitPrice?: number; - stopPrice?: number; - cliOrdId?: string; - triggerSignal?: 'mark' | 'index' | 'last'; - reduceOnly?: boolean; - trailingStopMaxDeviation?: number; - trailingStopDeviationUnit?: 'PERCENT' | 'QUOTE_CURRENCY' | 'unknown'; - limitPriceOffsetValue?: number; - limitPriceOffsetUnit?: 'QUOTE_CURRENCY' | 'PERCENT'; - broker?: string; -} +// A list of paths to directories that Jest should use to search for files in +// roots: [ +// "" +// ], ⋮---- -/** - * Assignment Program - */ +// Allows you to use a custom runner instead of Jest's default test runner +// runner: "jest-runner", ⋮---- -export interface FuturesAddAssignmentPreferenceParams { - contractType: string; - contract?: string; - maxSize?: number; - maxPosition?: number; - acceptLong: boolean; - acceptShort: boolean; - timeFrame: 'all' | 'weekdays' | 'weekends'; - enabled: boolean; -} +// The paths to modules that run some code to configure or set up the testing environment before each test +// setupFiles: [], ⋮---- -/** - * Trading Settings - */ +// A list of paths to modules that run some code to configure or set up the testing framework before each test +// setupFilesAfterEnv: [], ⋮---- -export interface FuturesUpdateSelfTradeStrategyParams { - strategy: - | 'REJECT_TAKER' - | 'CANCEL_MAKER_SELF' - | 'CANCEL_MAKER_CHILD' - | 'CANCEL_MAKER_ANY'; -} +// The number of seconds after which a test is considered as slow and reported as such in the results. +// slowTestThreshold: 5, ⋮---- -/** - * Transfers - */ +// A list of paths to snapshot serializer modules Jest should use for snapshot testing +// snapshotSerializers: [], ⋮---- -export interface FuturesInitiateWalletTransferParams { - fromAccount: string; - toAccount: string; - unit: string; - amount: number; -} -⋮---- -export interface FuturesInitiateSubaccountTransferParams { - fromUser: string; - toUser: string; - fromAccount: string; - toAccount: string; - unit: string; - amount: string; -} +// The test environment that will be used for testing +// testEnvironment: "jest-environment-node", ⋮---- -export interface FuturesSubmitToSpotParams { - currency: string; - amount: string; - sourceWallet?: string; -} +// Options that will be passed to the testEnvironment +// testEnvironmentOptions: {}, ⋮---- -/** - * Account History - */ +// Adds a location field to test results +// testLocationInResults: false, ⋮---- -export interface FuturesHistoryBaseParams { - since?: number; // Timestamp in milliseconds - before?: number; // Timestamp in milliseconds - sort?: 'asc' | 'desc'; - continuation_token?: string; // base64 - count?: number; - tradeable?: string; -} +// The glob patterns Jest uses to detect test files ⋮---- -since?: number; // Timestamp in milliseconds -before?: number; // Timestamp in milliseconds +// "**/__tests__/**/*.[jt]s?(x)", ⋮---- -continuation_token?: string; // base64 +// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped +// testPathIgnorePatterns: [ +// "/node_modules/" +// ], ⋮---- -export interface FuturesGetOrderEventsParams extends FuturesHistoryBaseParams { - opened?: boolean; - closed?: boolean; -} +// The regexp pattern or array of patterns that Jest uses to detect test files +// testRegex: [], ⋮---- -export interface FuturesGetTriggerEventsParams - extends FuturesHistoryBaseParams { - opened?: boolean; - closed?: boolean; -} +// This option allows the use of a custom results processor +// testResultsProcessor: undefined, ⋮---- -export interface FuturesGetPositionEventsParams - extends FuturesHistoryBaseParams { - opened?: boolean; - closed?: boolean; - increased?: boolean; - decreased?: boolean; - reversed?: boolean; - no_change?: boolean; - trades?: boolean; - funding_realization?: boolean; - settlement?: boolean; -} +// This option allows use of a custom test runner +// testRunner: "jest-circus/runner", ⋮---- -export interface FuturesGetAccountLogParams { - since?: number; // Timestamp in milliseconds - before?: number; // Timestamp in milliseconds - from?: number; // ID of the first entry (inclusive) - to?: number; // ID of the last entry (inclusive) - sort?: 'asc' | 'desc'; - info?: string[]; // Types of entry to filter by - count?: number; - conversion_details?: boolean; -} +// A map from regular expressions to paths to transformers +// transform: undefined, ⋮---- -since?: number; // Timestamp in milliseconds -before?: number; // Timestamp in milliseconds -from?: number; // ID of the first entry (inclusive) -to?: number; // ID of the last entry (inclusive) +// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation +// transformIgnorePatterns: [ +// "/node_modules/", +// "\\.pnp\\.[^\\/]+$" +// ], ⋮---- -info?: string[]; // Types of entry to filter by +// Prevents import esm module error from v1 axios release, issue #5026 ⋮---- -/** - * Market History - */ +// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them +// unmockedModulePathPatterns: undefined, ⋮---- -export interface FuturesMarketHistoryBaseParams { - tradeable: string; // Symbol of the contract - since?: number; // Timestamp in milliseconds - before?: number; // Timestamp in milliseconds - sort?: 'asc' | 'desc'; - continuation_token?: string; // base64 - count?: number; -} +// Indicates whether each individual test should be reported during the run +// verbose: undefined, +verbose: true, // report individual test ⋮---- -tradeable: string; // Symbol of the contract -since?: number; // Timestamp in milliseconds -before?: number; // Timestamp in milliseconds +// An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode +// watchPathIgnorePatterns: [], ⋮---- -continuation_token?: string; // base64 +// Whether to use watchman for file crawling +// watchman: true, + +================ +File: examples/Derivatives/WebSockets/privateWs.ts +================ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { + DefaultLogger, + LogParams, + WebsocketClient, + WS_KEY_MAP, + WSTopicRequest, +} from '../../../src/index.js'; +import { WSDerivativesTopic } from '../../../src/types/websockets/ws-subscriptions.js'; +// normally you should install this module via npm: `npm install @siebly/kraken-api` and import the module: +// import { LogParams, WebsocketClient, WsTopicRequest } from '@siebly/kraken-api'; ⋮---- -/** - * Charts - Candles - */ +// eslint-disable-next-line @typescript-eslint/no-unused-vars ⋮---- -export interface FuturesGetCandlesParams { - tickType: 'spot' | 'mark' | 'trade'; - symbol: string; - resolution: '1m' | '5m' | '15m' | '30m' | '1h' | '4h' | '12h' | '1d' | '1w'; - from?: number; // From date in epoch seconds - to?: number; // To date in epoch seconds - count?: number; // Number of candles to return -} +// console.log(new Date(), '--> trace', ...params); ⋮---- -from?: number; // From date in epoch seconds -to?: number; // To date in epoch seconds -count?: number; // Number of candles to return +async function start() ⋮---- /** - * Charts - Analytics - */ -⋮---- -export interface FuturesGetAnalyticsParams { - symbol: string; - analyticsType: string; - since: number; // Epoch time in seconds (required) - interval: 60 | 300 | 900 | 1800 | 3600 | 14400 | 43200 | 86400 | 604800; // Resolution in seconds (required) - to?: number; // Epoch time in seconds, default now -} + * The WebsocketClient is the core class to manage WebSocket subscriptions. Give it the topics you want to subscribe to, and it will handle the rest: + * - Connection management (connect, disconnect, reconnect) + * - Authentication for private topics + * - Subscription management (subscribe, unsubscribe, resubscribe on reconnect) + * - Message handling (dispatch messages to appropriate handlers) + * + * All you need to do is provide the topics you want to subscribe to when calling `subscribe()`, and the client will take care of the rest. + * + * Here we create a WebsocketClient instance with API key/secret for private topic subscriptions. + * + * In terms of product groups such as Spot, Derivatives, etc., the WebsocketClient understand the product group from the WsKey you provide when subscribing. For example, using `WS_KEY_MAP.spotPrivateV2` indicates that the subscription is for Spot private topics, as shown below. + * + * Refer to WS_KEY_MAP in the source code for all available WsKey options. + */ ⋮---- -since: number; // Epoch time in seconds (required) -interval: 60 | 300 | 900 | 1800 | 3600 | 14400 | 43200 | 86400 | 604800; // Resolution in seconds (required) -to?: number; // Epoch time in seconds, default now - -================ -File: src/types/websockets/ws-api.ts -================ -import { WS_KEY_MAP, WSOperation } from '../../lib/websocket/websocket-util.js'; -import { - WSAPIAddSpotOrderParams, - WSAPIAmendSpotOrderParams, - WSAPIBatchAddSpotOrdersParams, - WSAPIBatchCancelSpotOrdersParams, - WSAPICancelAllSpotOrdersAfterParams, - WSAPICancelSpotOrderParams, - WSAPIEditSpotOrderParams, -} from '../request/wsapi.types.js'; -import { - WSAPIAddSpotOrderResult, - WSAPIAmendSpotOrderResult, - WSAPIBatchAddSpotOrdersResult, - WSAPIBatchCancelSpotOrdersResult, - WSAPICancelAllSpotOrdersAfterResult, - WSAPICancelAllSpotOrdersResult, - WSAPICancelSpotOrderResult, - WSAPIEditSpotOrderResult, -} from '../response/wsapi.types.js'; +// Data received ⋮---- -export type Exact = { - // This part says: if there's any key that's not in T, it's an error - // This conflicts sometimes for some reason... - // [K: string]: never; -} & { - [K in keyof T]: T[K]; -}; +// Something happened, attempting to reconnect ⋮---- -// This part says: if there's any key that's not in T, it's an error -// This conflicts sometimes for some reason... -// [K: string]: never; +// Reconnect successful ⋮---- -export interface WsRequestOperation { - id: number; - type: WSOperation; - topic: TWSTopic; - privateChannel: boolean; - response: boolean; -} +// Connection closed. If unexpected, expect reconnect -> reconnected. ⋮---- -export interface WSAPIAuthenticationRequestFromServer { - timestamp: number; - sessionId: string; -} +// Reply to a request, e.g. "subscribe"/"unsubscribe"/"authenticate" ⋮---- -export interface WSAPIAuthenticationConfirmedFromServer { - pingInterval: number; - sessionId: string; - pingTimeout: number; - data: 'welcome'; -} +/** + * The below examples demonstrate how you can subscribe to private topics. + * + * Note: while the documentation specifies "api_key", "original_challenge" and "signed_challenge" as required parameters, but don't worry about that. The SDK will automatically: + * - Fetch the challenge using your API key, + * - Cache the challenge + * - Include the key, original challenge and signed challenge parameters for you when subscribing to private topics on the derivativesPrivateV1 WebSocket connection. + * + * You do NOT need to manually fetch or provide the "original_challenge" and "signed_challenge" tokens when subscribing to private topics. + * + * Do note that all of these include the "derivativesPrivateV1" WsKey reference. This tells the WebsocketClient to use the private "wss://futures.kraken.com/ws/v1" endpoint for these private subscription requests. It will also automatically authenticate the connection when it is established. + */ ⋮---- /** - * WS API commands (for sending requests via WS) - */ + * All of the following parameters require API keys for Derivatives APIs. + * + * Note: your "WsTopicRequest" does not need to include "api_key", "original_challenge" and "signed_challenge". See above for details, or below for examples. + */ ⋮---- -export type WSAPIOperation = (typeof WS_API_Operations)[number]; +// Open orders: https://docs.kraken.com/api/docs/futures-api/websocket/open_orders ⋮---- -export interface WSAPIRequestOperationKrakenSpot< - TWSOperation extends WSAPIOperation = WSAPIOperation, - TWSParams extends object = any, -> { - method: TWSOperation; - params?: TWSParams; - req_id: number; -} +// Note: if there are no parameters needed, you can also just request the topic by name +// This is the same as openOrdersTopicRequest, since openOrdersTopicRequest contains no parameters +// client.subscribe('open_orders', WS_KEY_MAP.derivativesPrivateV1); ⋮---- -export interface WSAPIWsKeyTopicMap { - [WS_KEY_MAP.spotPrivateV2]: WSAPIOperation; - [WS_KEY_MAP.spotBetaPrivateV2]: WSAPIOperation; -} +// Open orders (verbose): https://docs.kraken.com/api/docs/futures-api/websocket/open_orders ⋮---- -export type WSAPIWsKey = keyof WSAPIWsKeyTopicMap; +// Fills: https://docs.kraken.com/api/docs/futures-api/websocket/fills ⋮---- -export interface WSAPISpotResponse< - TResponseData extends object = object, - TWSAPIOperation = WSAPIOperation, -> { - wsKey: WSAPIWsKey; - error?: string; - method: TWSAPIOperation; - req_id: number; - success: boolean; - time_in: string; - time_out: string; - result: TResponseData; - request: any; -} +// Optionally, the product_ids field can be used to subscribe only to specific product. +// payload: { +// product_ids: ['PF_XBTUSD'], +// }, ⋮---- -export interface WSAPITopicRequestParamMap { - [key: string]: unknown; - - add_order: WSAPIAddSpotOrderParams; - amend_order: WSAPIAmendSpotOrderParams; - cancel_order: WSAPICancelSpotOrderParams; - cancel_all: never; - cancel_all_orders_after: WSAPICancelAllSpotOrdersAfterParams; - batch_add: WSAPIBatchAddSpotOrdersParams; - batch_cancel: WSAPIBatchCancelSpotOrdersParams; - edit_order: WSAPIEditSpotOrderParams; -} +// Balances: https://docs.kraken.com/api/docs/futures-api/websocket/balances ⋮---- -export interface WSAPITopicResponseMap { - [k: string]: unknown; - - add_order: WSAPISpotResponse; - amend_order: WSAPISpotResponse; - cancel_order: WSAPISpotResponse; - cancel_all: WSAPISpotResponse; - cancel_all_orders_after: WSAPISpotResponse< - WSAPICancelAllSpotOrdersAfterResult, - 'cancel_all_orders_after' - >; - batch_add: WSAPISpotResponse; - batch_cancel: WSAPISpotResponse< - WSAPIBatchCancelSpotOrdersResult, - 'batch_cancel' - >; - edit_order: WSAPISpotResponse; -} +// Open Position: https://docs.kraken.com/api/docs/futures-api/websocket/open_position +⋮---- +// Account Log: https://docs.kraken.com/api/docs/futures-api/websocket/account_log +⋮---- +// Notification: https://docs.kraken.com/api/docs/futures-api/websocket/notifications ================ -File: src/WebsocketAPIClient.ts +File: examples/Spot/Private/account.ts ================ -import { DefaultLogger } from './lib/websocket/logger.js'; -import { WS_KEY_MAP } from './lib/websocket/websocket-util.js'; -import { - WSAPIAddSpotOrderParams, - WSAPIAmendSpotOrderParams, - WSAPIBatchAddSpotOrdersParams, - WSAPIBatchCancelSpotOrdersParams, - WSAPICancelAllSpotOrdersAfterParams, - WSAPICancelSpotOrderParams, - WSAPIEditSpotOrderParams, -} from './types/request/wsapi.types.js'; -import { - WSAPIAddSpotOrderResult, - WSAPIAmendSpotOrderResult, - WSAPIBatchAddSpotOrdersResult, - WSAPIBatchCancelSpotOrdersResult, - WSAPICancelAllSpotOrdersAfterResult, - WSAPICancelAllSpotOrdersResult, - WSAPICancelSpotOrderResult, - WSAPIEditSpotOrderResult, -} from './types/response/wsapi.types.js'; -import { WSAPISpotResponse, WSAPIWsKey } from './types/websockets/ws-api.js'; -import { WSClientConfigurableOptions } from './types/websockets/ws-general.js'; -import { WebsocketClient } from './WebsocketClient.js'; +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { SpotClient } from '../../../src/index.js'; ⋮---- -/** - * Configurable options specific to only the REST-like WebsocketAPIClient - */ -export interface WSAPIClientConfigurableOptions { - /** - * Default: true - * - * Attach default event listeners, which will console log any high level - * events (opened/reconnecting/reconnected/etc). - * - * If you disable this, you should set your own event listeners - * on the embedded WS Client `wsApiClient.getWSClient().on(....)`. - */ - attachEventListeners: boolean; -} +// This example shows how to call Kraken API endpoint with either node.js, +// javascript (js) or typescript (ts) with the npm module "@siebly/kraken-api" for Kraken exchange +// for ACCOUNT INFORMATION ⋮---- /** - * Default: true - * - * Attach default event listeners, which will console log any high level - * events (opened/reconnecting/reconnected/etc). - * - * If you disable this, you should set your own event listeners - * on the embedded WS Client `wsApiClient.getWSClient().on(....)`. - */ + * import { SpotClient } from '@siebly/kraken-api'; + */ ⋮---- +// initialise the client /** - * This is a minimal Websocket API wrapper around the WebsocketClient. * - * Some methods support passing in a custom "wsKey". This is a reference to which WS connection should - * be used to transmit that message. This is only useful if you wish to use an alternative wss - * domain that is supported by the SDK. E.g. WS_API_KEY_MAP.spotBetaPrivateV2. + * Kraken API uses API Key and Private Key (base64 encoded) * - * Note: You can also directly use the sendWSAPIRequest() method to make WS API calls, but some - * may find the below methods slightly more intuitive. + * Example: + * { + * apiKey: 'your-api-key', + * apiSecret: 'your-base64-encoded-private-key', + * } * - * Refer to the WS API promises example for a more detailed example on using sendWSAPIRequest() directly: - * https://github.com/sieblyio/kraken-api/blob/main/examples/WebSockets/Spot/wsAPI.RAW.ts#L105 + * API Key Permissions Required: + * - Funds permissions - Query + * - Data - Query ledger entries * - * Docs: - * - Spot WS API: https://docs.kraken.com/api/docs/websocket-v2/add_order/ */ -export class WebsocketAPIClient ⋮---- -constructor( - options?: WSClientConfigurableOptions & - Partial, - logger?: DefaultLogger, -) +async function getAccountBalance() ⋮---- -public getWSClient(): WebsocketClient +// Get all cash balances (net of pending withdrawals) ⋮---- -/** - * Add a spot order - */ -submitSpotOrder( - params: Omit, - wsKey?: WSAPIWsKey, -): Promise> +// Note: Staking/Earn assets may have these extensions: +// .B - balances in new yield-bearing products +// .F - balances earning automatically in Kraken Rewards +// .T - tokenized assets ⋮---- -/** - * Amend an existing order - */ -amendSpotOrder( - params: WSAPIAmendSpotOrderParams, - wsKey?: WSAPIWsKey, -): Promise> +async function getExtendedBalance() ⋮---- -/** - * Cancel one or more orders - */ -cancelSpotOrder( - params: WSAPICancelSpotOrderParams, - wsKey?: WSAPIWsKey, -): Promise> +// Get extended balances including credits and held amounts +// Available balance = balance + credit - credit_used - hold_trade ⋮---- -/** - * Cancel all open orders - */ -cancelAllSpotOrders( - wsKey?: WSAPIWsKey, -): Promise> +async function getTradeBalance() ⋮---- -/** - * Cancel all orders after a timeout (Dead Man's Switch) - */ -cancelAllSpotOrdersAfter( - params: WSAPICancelAllSpotOrdersAfterParams, - wsKey?: WSAPIWsKey, - ): Promise< - WSAPISpotResponse< - WSAPICancelAllSpotOrdersAfterResult, - 'cancel_all_orders_after' - > - > { - return this.wsClient.sendWSAPIRequest( - wsKey || WS_KEY_MAP.spotPrivateV2, - 'cancel_all_orders_after', - params, - ); +// Get trade balance summary (margin info) ⋮---- -/** - * Add multiple orders in a single batch (2-15 orders) - */ -batchSubmitSpotOrders( - params: WSAPIBatchAddSpotOrdersParams, - wsKey?: WSAPIWsKey, -): Promise> +// Response includes: +// - eb: equivalent balance +// - tb: trade balance +// - m: margin amount +// - n: unrealized P&L +// - e: equity +// - mf: free margin ⋮---- -/** - * Cancel multiple orders in a single batch (2-50 orders) - */ -batchCancelSpotOrders( - params: WSAPIBatchCancelSpotOrdersParams, - wsKey?: WSAPIWsKey, - ): Promise< - WSAPISpotResponse - > { - return this.wsClient.sendWSAPIRequest( - wsKey || WS_KEY_MAP.spotPrivateV2, - 'batch_cancel', - params, - ); +async function getLedgers() ⋮---- -/** - * Edit an existing order (legacy method, use amendSpotOrder instead) - * @deprecated Use amendSpotOrder for better performance and features - */ -editSpotOrder( - params: WSAPIEditSpotOrderParams, - wsKey?: WSAPIWsKey, -): Promise> -/** - * - * - * - * - * - * - * - * Private methods for handling some of the convenience/automation provided by the WS API Client - * - * - * +// Query specific ledger entries by ID +⋮---- +// Ledger entry types include: +// - trade, deposit, withdrawal, transfer, margin +// - adjustment, rollover, spend, receive, settled +// - credit, staking, reward, dividend, sale, conversion +⋮---- +async function getLedgersInfo() +⋮---- +// Get ledger info with filters (returns 50 most recent by default) +⋮---- +asset: 'XBT', // Filter by asset +type: 'deposit', // Filter by type +⋮---- +async function getTradingVolume() +⋮---- +// Get 30-day USD trading volume and fee schedule +⋮---- +// Response includes: +// - currency: volume currency +// - volume: current trading volume +// - fees: fee schedule by pair +// - fees_maker: maker fee schedule +⋮---- +// Uncomment the function you want to test: +⋮---- +// getExtendedBalance(); +// getTradeBalance(); +// getLedgers(); +// getLedgersInfo(); +// getTradingVolume(); + +================ +File: examples/Spot/Private/orderManagement.ts +================ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { SpotClient } from '../../../src/index.js'; +⋮---- +// This example shows how to call Kraken API endpoint with either node.js, +// javascript (js) or typescript (ts) with the npm module "@siebly/kraken-api" for Kraken exchange +// for ORDER MANAGEMENT +⋮---- +/** + * import { SpotClient } from '@siebly/kraken-api'; + */ +⋮---- +// initialise the client +/** + * + * Kraken API uses API Key and Private Key (base64 encoded) + * + * Example: + * { + * apiKey: 'your-api-key', + * apiSecret: 'your-base64-encoded-private-key', + * } + * + * API Key Permissions Required: + * - Funds permissions - Query (for balance) + * - Orders and trades - Query open orders & trades + * - Orders and trades - Query closed orders & trades + * + */ +⋮---- +async function getTradeBalance() +⋮---- +// Get trade balance summary +⋮---- +async function getOpenOrders() +⋮---- +// Get all open orders +⋮---- +async function getOpenOrdersWithTrades() +⋮---- +// Get open orders with related trades +⋮---- +trades: true, // Include trades related to orders +⋮---- +async function getOpenOrdersByClientId() +⋮---- +// Get open orders filtered by client order ID +⋮---- +async function getClosedOrders() +⋮---- +// Get closed orders (last 50) +⋮---- +async function getClosedOrdersWithFilters() +⋮---- +// Get closed orders with filters +⋮---- +trades: true, // Include related trades +start: Math.floor(Date.now() / 1000) - 86400 * 7, // Last 7 days +closetime: 'close', // Filter by close time +⋮---- +async function getClosedOrdersByClientId() +⋮---- +// Get closed orders by client order ID +⋮---- +async function getOrdersByTxId() +⋮---- +// Query specific orders by transaction ID +⋮---- +// Uncomment the function you want to test: +⋮---- +// getTradeBalance(); +// getOpenOrders(); +// getOpenOrdersWithTrades(); +// getOpenOrdersByClientId(); +// getClosedOrders(); +// getClosedOrdersWithFilters(); +// getClosedOrdersByClientId(); +// getOrdersByTxId(); + +================ +File: examples/Spot/Private/submitOrder.ts +================ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { SpotClient } from '../../../src/index.js'; +⋮---- +// This example shows how to call Kraken API endpoint with either node.js, +// javascript (js) or typescript (ts) with the npm module "@siebly/kraken-api" for Kraken exchange +// for SUBMITTING ORDERS +⋮---- +/** + * import { SpotClient } from '@siebly/kraken-api'; + */ +⋮---- +// initialise the client +/** + * + * Kraken API uses API Key and Private Key (base64 encoded) + * + * Example: + * { + * apiKey: 'your-api-key', + * apiSecret: 'your-base64-encoded-private-key', + * } + * + * API Key Permissions Required: Orders and trades - Create & modify orders + * + */ +⋮---- +async function submitMarketOrder() +⋮---- +// submit market spot order +⋮---- +async function submitLimitOrder() +⋮---- +// Submit limit spot order +⋮---- +async function submitLimitOrderWithFlags() +⋮---- +// Submit post-only limit order (maker-only) +⋮---- +oflags: 'post', // post-only flag +timeinforce: 'GTC', // Good-til-cancelled +⋮---- +async function submitBatchOrders() +⋮---- +// Submit batch of orders (minimum 2, maximum 15) +// All orders must be for the same pair +⋮---- +async function submitBatchOrdersValidateOnly() +⋮---- +// Validate batch orders without submitting them +⋮---- +validate: true, // Only validate, don't submit +⋮---- +// Uncomment the function you want to test: +⋮---- +// submitLimitOrder(); +// submitLimitOrderWithFlags(); +// submitBatchOrders(); +// submitBatchOrdersValidateOnly(); + +================ +File: examples/Spot/WebSockets/wsAPI.RAW.ts +================ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { + DefaultLogger, + LogParams, + WebsocketClient, + WS_KEY_MAP, +} from '../../../src/index.js'; +// normally you should install this module via npm: `npm install @siebly/kraken-api` and import the module: +// import { DefaultLogger, LogParams, WebsocketClient, WS_KEY_MAP } from '@siebly/kraken-api'; +⋮---- +// eslint-disable-next-line @typescript-eslint/no-unused-vars +⋮---- +// console.log('trace', ...params); +⋮---- +async function start() +⋮---- +/** + * The WebsocketClient is the core class to manage WebSocket subscriptions. Give it the topics you want to subscribe to, and it will handle the rest: + * - Connection management (connect, disconnect, reconnect) + * - Authentication for private topics + * - Subscription management (subscribe, unsubscribe, resubscribe on reconnect) + * - Message handling (dispatch messages to appropriate handlers) * + * All you need to do is provide the topics you want to subscribe to when calling `subscribe()`, and the client will take care of the rest. * + * Here we create a WebsocketClient instance with API key/secret for private topic subscriptions. * + * In terms of product groups such as Spot, Derivatives, etc., the WebsocketClient understand the product group from the WsKey you provide when subscribing. For example, using `WS_KEY_MAP.spotPrivateV2` indicates that the subscription is for Spot private topics, as shown below. * + * Refer to WS_KEY_MAP in the source code for all available WsKey options. */ ⋮---- -public connectWSAPI(wsKey: WSAPIWsKey) +// Data received ⋮---- -private setupDefaultEventListeners() +// Something happened, attempting to reconnect ⋮---- -/** - * General event handlers for monitoring the WebsocketClient - */ +// Reconnect successful ⋮---- -// Blind JSON.stringify can fail on circular references +// Connection closed. If unexpected, expect reconnect -> reconnected. ⋮---- -// JSON.stringify({ ...data, target: 'WebSocket' }), +// Reply to a request, e.g. "subscribe"/"unsubscribe"/"authenticate" +⋮---- +/** + * The below examples demonstrate how you can subscribe to private topics. + * + * Note: while the documentation specifies "token" as a required parameter, the SDK will automatically: + * - fetch the token using your API key/secret, + * - manage token caching/refreshing, + * - include the token in the request for you. + * + * So you do NOT need to manually fetch or provide the token when subscribing to private topics. + * + * Do note that all of these include the "spotPrivateV2" WsKey reference. This tells the WebsocketClient to use the private "wss://ws-auth.kraken.com/v2" endpoint for these private subscription requests. + */ ================ -File: docs/KRAKEN_SDK_QUICKSTART_GUIDE.md +File: examples/Spot/WebSockets/wsAPI.ts ================ -# Kraken API JavaScript Tutorial for Node.js and TypeScript - -Build Kraken integrations in JavaScript or TypeScript without hand-rolling raw HTTP requests, Kraken JWTs/request signing for authenticated APIs, WebSocket authentication, heartbeats, reconnects, or exchange-specific payload handling. - -This Kraken JavaScript tutorial uses [`@siebly/kraken-api`](https://www.npmjs.com/package/@siebly/kraken-api), the [Kraken JavaScript SDK by Siebly.io](https://siebly.io/sdk/kraken/javascript), to walk through the API surfaces most developers need: - -- Kraken Spot REST API -- Kraken Futures REST API -- Public and private Kraken WebSockets -- Spot trading over Kraken's event-driven WebSocket API -- Automatic handling for Kraken JWTs, request signing, and private-channel authentication - -Key Links - -- Kraken JavaScript & Node.js SDK by Siebly: [`@siebly/kraken-api`](https://www.npmjs.com/package/@siebly/kraken-api) -- GitHub Repository: [`sieblyio/kraken-api`](https://github.com/sieblyio/kraken-api) -- SDK function-endpoint map: [Kraken JavaScript Endpoint Reference](https://siebly.io/sdk/kraken/javascript#endpoint-reference) -- More SDKs: [Siebly.io](https://siebly.io) - -Topics covered in this guide - -- Why use a Kraken SDK -- Install and API keys -- Start building quickstart -- Spot REST APIs -- Spot WebSockets -- Spot trading over WebSocket API -- Futures REST APIs -- Futures WebSockets -- Production notes -- FAQ and next steps - ---- - -## Why use a Kraken SDK - -A stable Kraken API integration is not just "make a few HTTP requests". There's more to it than that. - -- Spot REST and Futures REST APIs use different authentication models and request shapes. -- Public & private WebSockets require connection lifecycle handling, authentication, and reconnection handling. -- Spot trading over Kraken's asynchronous WebSocket API can be complicated without JavaScript Promises to glue WebSocket API responses to the requests that triggered them. -- Production bots and trading tools need typed request schemas, consistent async behavior, resilient WebSockets, and a connectivity architecture that works. - -The `@siebly/kraken-api` gives you one JavaScript and TypeScript SDK for Kraken API integration in any Node.js or JavaScript-capable environment: - -- Complete API coverage with dedicated REST API clients for each product group, including Spot and Derivatives. -- One `WebsocketClient` for public and private streaming across all Kraken products. -- A `WebsocketAPIClient` for Spot trading over a persistent WebSocket connection, with the convenience of awaitable promise-wrapped WebSocket API requests. Each WebSocket API command can be awaited like a REST API request. -- Automatic heartbeats, reconnect and resubscribe handling for WebSockets. Stay connected, stay in sync. -- TypeScript-first request and response definitions for most SDK methods. -- ESM and CJS support. -- Browser-friendly HMAC signing and proxy support. - -The package also includes `InstitutionalClient` and `PartnerClient`, but this guide focuses on the flows most developers look for first: Spot, Futures, market data, account data, and order management. - ---- - -## What you can build with the [Kraken JavaScript SDK](https://siebly.io/sdk/kraken/javascript) - -This Kraken JavaScript SDK is relevant for any integration with Kraken's APIs and WebSockets, especially if you are building: - -- Trading bots and execution services -- Real-time market data dashboards -- Internal trader tooling -- Portfolio and balance monitors -- Alerting and signal pipelines -- Reconciliation or account state services -- AI-assisted engineering workflows that need a reliable & typed Kraken integration layer - ---- - -## Who this guide is for - -This guide is written for JavaScript developers (& LLMs) who: - -- Want to build with the Kraken API offering -- Want a quick, easy, predictable, up-to-date and heavily used (reliable) way to integrate with Kraken's APIs & WebSockets -- Care about typed requests and responses -- Are working with exchange REST APIs & WebSockets for the first time -- Are already using exchange APIs elsewhere and are looking to integrate Kraken -- Need dependable connectivity for systematic trading -- Are comparing raw Kraken integration against a maintained SDK - ---- - -## What this one-page course covers - -- Installing the Kraken JavaScript SDK by Siebly -- Creating Spot and Futures REST API clients -- Making your first public Spot REST API request -- Streaming public Spot market data over WebSockets -- Subscribing to private Spot account streams -- Placing Spot orders over Kraken's REST API -- Managing Spot orders in batches -- Trading Spot over Kraken's WebSocket API -- Pulling Kraken Futures market data -- Submitting Kraken Futures orders via REST API -- Using Kraken Futures WebSockets -- Production patterns for reconnects, idempotency, logging, and safer rollout - ---- - -## How to get started with the Kraken API in JavaScript? - -If you don't have Node.js installed yet, refer to the Node.js documentation on getting started with Node.js. The Kraken JavaScript SDK is published to both [GitHub](https://github.com/sieblyio/kraken-api) and [npm](https://www.npmjs.com/package/@siebly/kraken-api). - -Install the SDK with npm: - -```bash -npm install @siebly/kraken-api -``` - -Or, if preferred, use your favourite npm-compatible package manager: - -```bash -# or pnpm: -pnpm install @siebly/kraken-api -# or yarn: -yarn add @siebly/kraken-api -``` - -Create API keys where Kraken documents them: - -- Spot: [Kraken Spot API key instructions](https://support.kraken.com/articles/360000919966-how-to-create-an-api-key) -- Futures: [Kraken Futures API key instructions](https://pro.kraken.com/app/settings/api) - -> Use the minimum permissions needed for your scenario. Trading does not require withdrawal permissions. Analytics does not require trading permissions. - -Important auth difference: - -- Spot & futures have different API keys. -- Make sure the API keys you have created are for the correct product group. -- API keys for Spot will only work for Spot APIs. -- API keys for Futures will only work for Futures APIs. -- Most market data does not require API keys. - -Typical environment variables: - -```bash -export API_SPOT_KEY='your-spot-api-key' -export API_SPOT_SECRET='your-spot-api-secret' - -export API_FUTURES_KEY='your-futures-api-key' -export API_FUTURES_SECRET='your-futures-api-secret' -``` - -For local Node.js examples that use a `.env` file, make `.env` loading automatic before reading `process.env`. Prefer Node.js built-in `--env-file` or `--env-file-if-exists` in package scripts when supported; otherwise use `process.loadEnvFile`, `dotenv/config`, or the repo's existing loader. Real process environment variables should override `.env`. - -If you are only testing public endpoints, you do not need any keys at all. - ---- - -## Start building: first Kraken API calls in JavaScript - -If you only want the fastest path to a working integration, this is the section to start from. - -### 1. First Spot REST API request - -```typescript -import { SpotClient } from '@siebly/kraken-api'; - -const client = new SpotClient(); - -async function main() { - const serverTime = await client.getServerTime(); - const systemStatus = await client.getSystemStatus(); - const ticker = await client.getTicker({ pair: 'XBTUSD' }); - const orderBook = await client.getOrderBook({ pair: 'XBTUSD', count: 10 }); +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import { + DefaultLogger, + LogParams, + WebsocketAPIClient, +} from '../../../src/index.js'; +// normally you should install this module via npm: `npm install @siebly/kraken-api` and import the module: +// import { DefaultLogger, LogParams, WebsocketAPIClient, WS_KEY_MAP } from '@siebly/kraken-api'; +⋮---- +// eslint-disable-next-line @typescript-eslint/no-unused-vars +⋮---- +// console.log('trace', ...params); +⋮---- +async function start() +⋮---- +/** + * The WebsocketClient is the core class to manage WebSocket subscriptions. Give it the topics you want to subscribe to, and it will handle the rest: + * - Connection management (connect, disconnect, reconnect) + * - Authentication for private topics + * - Subscription management (subscribe, unsubscribe, resubscribe on reconnect) + * - Message handling (dispatch messages to appropriate handlers) + * + * All you need to do is provide the topics you want to subscribe to when calling `subscribe()`, and the client will take care of the rest. + * + * Here we create a WebsocketClient instance with API key/secret for private topic subscriptions. + * + * In terms of product groups such as Spot, Derivatives, etc., the WebsocketClient understand the product group from the WsKey you provide when subscribing. For example, using `WS_KEY_MAP.spotPrivateV2` indicates that the subscription is for Spot private topics, as shown below. + * + * Refer to WS_KEY_MAP in the source code for all available WsKey options. + */ +⋮---- +/** + * The below examples demonstrate how you can subscribe to private topics. + * + * Note: while the documentation specifies "token" as a required parameter, the SDK will automatically: + * - fetch the token using your API key/secret, + * - manage token caching/refreshing, + * - include the token in the request for you. + * + * So you do NOT need to manually fetch or provide the token when subscribing to private topics. + * + * Do note that all of these include the "spotPrivateV2" WsKey reference. This tells the WebsocketClient to use the private "wss://ws-auth.kraken.com/v2" endpoint for these private subscription requests. + */ - console.log({ - serverTime, - systemStatus, - ticker, - orderBook, - }); +================ +File: src/lib/websocket/websocket-util.ts +================ +import WebSocket from 'isomorphic-ws'; +⋮---- +import { WSAPIRequestOperationKrakenSpot } from '../../types/websockets/ws-api.js'; +import { WSTopic } from '../../types/websockets/ws-subscriptions.js'; +⋮---- +/** Should be one WS key per unique URL */ +⋮---- +/** + * Public WebSocket subscriptions for Kraken Spot products, via the V2 API + * + * - Ref: https://docs.kraken.com/api/docs/guides/spot-ws-intro + * - Channels: https://docs.kraken.com/api/docs/websocket-v2/add_order + * + * Note: Use spotPrivateV2 for private channels (requires API keys). + */ +⋮---- +/** + * Public WebSocket subscriptions for Kraken Derivatives products, via the V1 API: + * + * - Ref: https://docs.kraken.com/api/docs/guides/futures-websockets + * - Channels: https://docs.kraken.com/api/docs/futures-api/websocket/open_orders + * + * Note: While both Public and Private channels use the same WebSocket URL, we will actually maintain separate connections for easier management. Private channels require authentication and the connection is authenticated automatically. + */ +⋮---- +/** This is used to differentiate between each of the available websocket streams */ +export type WsKey = (typeof WS_KEY_MAP)[keyof typeof WS_KEY_MAP]; +⋮---- +export type WSOperation = 'subscribe' | 'unsubscribe'; +⋮---- +/** + * Normalised internal format for a request (subscribe/unsubscribe/etc) on a topic, with optional parameters. + * + * - Topic: the topic this event is for + * - Payload: the parameters to include, optional. E.g. auth requires key + sign. Some topics allow configurable parameters. + */ +export interface WSTopicRequest< + TWSTopic extends WSTopic = WSTopic, + TWSPayload = any, +> { + topic: TWSTopic; + payload?: TWSPayload; } - -// Since each of the above API calls is wrapped in an awaited promise, a high level catch will detect any exceptions: -main().catch(console.error); -``` - -This is the quickest way to verify that your Kraken API JavaScript integration is wired correctly for public REST API calls. - -See also: [Kraken JavaScript Example - How to query spot market data](https://siebly.io/examples/Kraken/Spot/Public/marketData) - -### 2. First public Spot WebSocket stream - -```typescript -import { WebsocketClient, WS_KEY_MAP } from '@siebly/kraken-api'; - -const ws = new WebsocketClient(); - -ws.on('open', (data) => console.log('connected', data?.wsKey)); -ws.on('response', (data) => console.log('response', JSON.stringify(data))); -ws.on('message', (data) => console.log('message', JSON.stringify(data))); -ws.on('reconnected', (data) => console.log('reconnected', data?.wsKey)); -ws.on('exception', console.error); - -ws.subscribe( - { - topic: 'ticker', - payload: { - symbol: ['BTC/USD', 'ETH/USD'], - }, - }, - WS_KEY_MAP.spotPublicV2, -); -``` - -This gets a public Kraken Spot WebSocket stream running in JavaScript. - -See also: [Kraken JavaScript Example - How to subscribe to spot market data WebSocket stream](https://siebly.io/examples/Kraken/Spot/WebSockets/publicWs) - -### 3. First private Spot WebSocket stream - -```typescript -import { WebsocketClient, WS_KEY_MAP } from '@siebly/kraken-api'; - -const ws = new WebsocketClient({ - apiKey: process.env.API_SPOT_KEY!, - apiSecret: process.env.API_SPOT_SECRET!, -}); - -ws.on('authenticated', (data) => console.log('authenticated', data?.wsKey)); -ws.on('response', (data) => console.log('response', JSON.stringify(data))); -ws.on('message', (data) => console.log('message', JSON.stringify(data))); -ws.on('reconnected', (data) => console.log('reconnected', data?.wsKey)); -ws.on('exception', console.error); - -ws.subscribe( - { - topic: 'executions', - payload: { - snap_trades: true, - snap_orders: true, - order_status: true, - }, - }, - WS_KEY_MAP.spotPrivateV2, -); - -ws.subscribe( - { - topic: 'balances', - payload: {}, - }, - WS_KEY_MAP.spotPrivateV2, -); -``` - -For private Spot v2 topics, the SDK can fetch and refresh the token for you. You do not need to manually fetch a token and inject it into every subscribe payload. - -See also: [Kraken JavaScript Example - How to subscribe to spot account change WebSocket events](https://siebly.io/examples/Kraken/Spot/WebSockets/privateWs) - -### 4. First Spot order over REST API - -```typescript -import { SpotClient } from '@siebly/kraken-api'; - -const client = new SpotClient({ - apiKey: process.env.API_SPOT_KEY!, - apiSecret: process.env.API_SPOT_SECRET!, -}); - -async function placeOrder() { - const result = await client.submitOrder({ - ordertype: 'limit', - type: 'buy', - pair: 'XBTUSD', - volume: '0.0001', - price: '10000', - validate: true, - cl_ord_id: client.generateNewOrderID(), - }); - - console.log(result); -} - -placeOrder().catch(console.error); -``` - -Use `validate: true` when you want to validate the request shape without sending the live order. Remove `validate: true` when you are ready to submit. - -See also: [Kraken JavaScript Example - How to submit spot orders](https://siebly.io/examples/Kraken/Spot/Private/submitOrder) - -### 5. First Futures order - -```typescript -import { DerivativesClient } from '@siebly/kraken-api'; - -const client = new DerivativesClient({ - apiKey: process.env.API_FUTURES_KEY!, - apiSecret: process.env.API_FUTURES_SECRET!, - // testnet: true, // optional: route Derivatives REST calls to Kraken's demo environment -}); - -async function placeFuturesOrder() { - const result = await client.submitOrder({ - orderType: 'lmt', - symbol: 'PF_ETHUSD', - side: 'buy', - size: 0.01, - limitPrice: 1000, - cliOrdId: client.generateNewOrderID(), - }); - - console.log(result); +⋮---- +/** + * Conveniently allow users to request a topic either as string topics or objects (containing string topic + params) + */ +export type WSTopicRequestOrStringTopic< + TWSTopic extends WSTopic, + TWSPayload = any, +> = WSTopicRequest | string; +⋮---- +export interface WSRequestOperationKraken< + TWSTopic extends string, + TWSParams extends object = any, +> { + // spot only + method?: WSOperation; + // futures only + event?: WSOperation; + params: + | { + channel: (TWSTopic | string | number)[]; + symbol?: string[]; + event_trigger?: string; + snapshot?: boolean; + } + | TWSParams; + req_id: number; + /** + * The following are needed for futures/derivatives requests + */ + feed?: TWSTopic; + api_key?: string; + original_challenge?: string; + signed_challenge?: string; } +⋮---- +// spot only +⋮---- +// futures only +⋮---- +/** + * The following are needed for futures/derivatives requests + */ +⋮---- +/** + * #305: ws.terminate() is undefined in browsers. + * This only works in node.js, not in browsers. + * Does nothing if `ws` is undefined. Does nothing in browsers. + */ +export function safeTerminateWs( + ws?: WebSocket | any, + fallbackToClose?: boolean, +): boolean +⋮---- +/** + * WS API promises are stored using a primary key. This key is constructed using + * properties found in every request & reply. + * + * The counterpart to this is in resolveEmittableEvents + */ +export function getPromiseRefForWSAPIRequest( + wsKey: WsKey, + requestEvent: WSAPIRequestOperationKrakenSpot, +): string +⋮---- +/** + * Users can conveniently pass topics as strings or objects (object has topic name + optional params). + * + * This method normalises topics into objects (object has topic name + optional params). + */ +export function getNormalisedTopicRequests( + wsTopicRequests: WSTopicRequestOrStringTopic[], +): WSTopicRequest[] +⋮---- +// passed as string, convert to object +⋮---- +// already a normalised object, thanks to user -placeFuturesOrder().catch(console.error); -``` - -See also: [Kraken JavaScript Example - How to submit futures/derivatives orders](https://siebly.io/examples/Kraken/Derivatives/Private/submitOrder) - ---- - -## Kraken Spot REST API in JavaScript and TypeScript - -Most integrations start with Spot REST APIs because it is one of the simplest ways to test basic connectivity, such as querying account state and submitting orders. - -### Create a public Spot client - -```typescript -import { SpotClient } from '@siebly/kraken-api'; - -const client = new SpotClient(); -``` - -Public calls do not require keys. - -### Create a private Spot client - -If you plan on making private API calls, include API keys when creating an instance of the SpotClient class: - -```typescript -import { SpotClient } from '@siebly/kraken-api'; - -const client = new SpotClient({ - apiKey: process.env.API_SPOT_KEY!, - apiSecret: process.env.API_SPOT_SECRET!, -}); -``` - -### Common public Spot market data calls - -```typescript -const serverTime = await client.getServerTime(); -const systemStatus = await client.getSystemStatus(); -const assetInfo = await client.getAssetInfo({ asset: 'XBT,ETH' }); -const assetPairs = await client.getAssetPairs({ pair: 'XBTUSD,ETHUSD' }); -const ticker = await client.getTicker({ pair: 'XBTUSD' }); -const orderBook = await client.getOrderBook({ pair: 'XBTUSD', count: 10 }); -const candles = await client.getCandles({ pair: 'XBTUSD', interval: 60 }); -const recentTrades = await client.getRecentTrades({ - pair: 'XBTUSD', - count: 10, -}); -const recentSpreads = await client.getRecentSpreads({ pair: 'XBTUSD' }); -``` - -### Common private Spot account calls - -```typescript -const balance = await client.getAccountBalance(); -const tradeBalance = await client.getTradeBalance(); -const openOrders = await client.getOpenOrders(); -const openOrdersWithTrades = await client.getOpenOrders({ trades: true }); -const closedOrders = await client.getClosedOrders({ - trades: true, - start: Math.floor(Date.now() / 1000) - 86400 * 7, // last 7 days -}); -``` - -See also: - -- [Kraken JavaScript Example - How to query spot market data](https://siebly.io/examples/Kraken/Spot/Public/marketData) -- [Kraken JavaScript Example - How to query Kraken spot account balances, orders & transactions](https://siebly.io/examples/Kraken/Spot/Private/account) -- [Kraken JavaScript Example - How to query, manage, amend & cancel spot orders](https://siebly.io/examples/Kraken/Spot/Private/orderManagement) +================ +File: src/lib/websocket/WsStore.ts +================ +import WebSocket from 'isomorphic-ws'; +⋮---- +import { DefaultLogger } from './logger.js'; +import { + DeferredPromise, + WSConnectedResult, + WsConnectionStateEnum, + WsStoredState, +} from './WsStore.types.js'; +⋮---- +/** + * Simple comparison of two objects, recursive for nested objects. Adoped from OKX SDK. + */ +export function isDeepObjectMatch(object1: any, object2: any): boolean +⋮---- +// console.log('not same key count', { keys1, keys2 }); +// not the same amount of keys or keys don't match +⋮---- +// console.log('not same key names: ', { keys1, keys2 }); +⋮---- +type DeferredPromiseRef = + (typeof DEFERRED_PROMISE_REF)[keyof typeof DEFERRED_PROMISE_REF]; +⋮---- +export class WsStore< +WsKey extends string, +⋮---- +constructor(logger: DefaultLogger) +⋮---- +/** Get WS stored state for key, optionally create if missing */ +get( + key: WsKey, + createIfMissing?: true, + ): WsStoredState; +⋮---- +get( + key: WsKey, + createIfMissing?: false, + ): WsStoredState | undefined; +⋮---- +get( + key: WsKey, + createIfMissing?: boolean, +): WsStoredState | undefined +⋮---- +getKeys(): WsKey[] +⋮---- +create(key: WsKey): WsStoredState | undefined +⋮---- +delete(key: WsKey): void +⋮---- +// TODO: should we allow this at all? Perhaps block this from happening... +⋮---- +/* connection websocket */ +⋮---- +hasExistingActiveConnection(key: WsKey): boolean +⋮---- +getWs(key: WsKey): WebSocket | undefined +⋮---- +setWs(key: WsKey, wsConnection: WebSocket): WebSocket +⋮---- +/** + * deferred promises + */ +⋮---- +getDeferredPromise( + wsKey: WsKey, + promiseRef: string | DeferredPromiseRef, +): DeferredPromise | undefined +⋮---- +createDeferredPromise( + wsKey: WsKey, + promiseRef: string | DeferredPromiseRef, + throwIfExists: boolean, +): DeferredPromise +⋮---- +// console.log('existing promise'); +⋮---- +// console.log('create promise'); +⋮---- +// TODO: Once stable, use Promise.withResolvers in future +⋮---- +resolveDeferredPromise( + wsKey: WsKey, + promiseRef: string | DeferredPromiseRef, + value: unknown, + removeAfter: boolean, +): void +⋮---- +rejectDeferredPromise( + wsKey: WsKey, + promiseRef: string | DeferredPromiseRef, + value: unknown, + removeAfter: boolean, +): void +⋮---- +removeDeferredPromise( + wsKey: WsKey, + promiseRef: string | DeferredPromiseRef, +): void +⋮---- +// Just in case it's pending +⋮---- +rejectAllDeferredPromises(wsKey: WsKey, reason: string): void +⋮---- +// Skip reserved keys, such as the connection promise +⋮---- +/** Get promise designed to track a connection attempt in progress. Resolves once connected. */ +getConnectionInProgressPromise( + wsKey: WsKey, +): DeferredPromise | undefined +⋮---- +getAuthenticationInProgressPromise( + wsKey: WsKey, +): DeferredPromise +⋮---- +createAuthenticationInProgressPromise( + wsKey: WsKey, + throwIfExists: boolean, +): DeferredPromise +⋮---- +getTopicsAsArray(key: WsKey): TWSTopicSubscribeEventArgs[] +⋮---- +getTopicsByKey(): Record> +⋮---- +/** + * Find matching "topic" request from the store + * @param key + * @param topic + * @returns + */ +getMatchingTopic(key: WsKey, topic: TWSTopicSubscribeEventArgs) +⋮---- +addTopic(key: WsKey, topic: TWSTopicSubscribeEventArgs) +⋮---- +// Check for duplicate topic. If already tracked, don't store this one +⋮---- +deleteTopic(key: WsKey, topic: TWSTopicSubscribeEventArgs) +⋮---- +// Check if we're subscribed to a topic like this -### Spot order examples +================ +File: docs/KRAKEN_SDK_QUICKSTART_GUIDE.md +================ +# Kraken API JavaScript Tutorial for Node.js and TypeScript -Market order: +Build Kraken integrations in JavaScript or TypeScript without hand-rolling raw HTTP requests, Kraken JWTs/request signing for authenticated APIs, WebSocket authentication, heartbeats, reconnects, or exchange-specific payload handling. -```typescript -await client.submitOrder({ - ordertype: 'market', - type: 'buy', - volume: '0.01', - pair: 'XBTUSD', -}); -``` +This Kraken JavaScript tutorial uses [`@siebly/kraken-api`](https://www.npmjs.com/package/@siebly/kraken-api), the [Kraken JavaScript SDK by Siebly.io](https://siebly.io/sdk/kraken/javascript), to walk through the API surfaces most developers need: -Limit order: +- Kraken Spot REST API +- Kraken Futures REST API +- Public and private Kraken WebSockets +- Spot trading over Kraken's event-driven WebSocket API +- Automatic handling for Kraken JWTs, request signing, and private-channel authentication -```typescript -await client.submitOrder({ - ordertype: 'limit', - type: 'buy', - volume: '0.0001', - pair: 'XBTUSD', - price: '10000', -}); -``` +Key Links -Post-only limit order: +- Kraken JavaScript & Node.js SDK by Siebly: [`@siebly/kraken-api`](https://www.npmjs.com/package/@siebly/kraken-api) +- GitHub Repository: [`sieblyio/kraken-api`](https://github.com/sieblyio/kraken-api) +- SDK function-endpoint map: [Kraken JavaScript Endpoint Reference](https://siebly.io/sdk/kraken/javascript#endpoint-reference) +- More SDKs: [Siebly.io](https://siebly.io) -```typescript -await client.submitOrder({ - ordertype: 'limit', - type: 'buy', - volume: '0.001', - pair: 'XBTEUR', - price: '1000.00', - oflags: 'post', - timeinforce: 'GTC', -}); -``` +Topics covered in this guide -### Spot batch order management +- Why use a Kraken SDK +- Install and API keys +- Start building quickstart +- Spot REST APIs +- Spot WebSockets +- Spot trading over WebSocket API +- Futures REST APIs +- Futures WebSockets +- Production notes +- FAQ and next steps -If you want to stage multiple orders on one pair, batch APIs are a better fit than serially sending single orders. +--- -```typescript -await client.submitBatchOrders({ - pair: 'XBTUSD', - orders: [ - { - ordertype: 'limit', - type: 'buy', - volume: '0.0001', - price: '10000.00', - timeinforce: 'GTC', - // cl_ord_id: client.generateNewOrderID(), // optional: include a custom order ID before placing your order, for easier tracking - }, - { - ordertype: 'limit', - type: 'sell', - volume: '0.0001', - price: '13000.00', - timeinforce: 'GTC', - // cl_ord_id: client.generateNewOrderID(), // optional: include a custom order ID before placing your order, for easier tracking - }, - ], -}); -``` +## Why use a Kraken SDK -Validate the batch without sending: +A stable Kraken API integration is not just "make a few HTTP requests". There's more to it than that. -```typescript -await client.submitBatchOrders({ - pair: 'XBTUSD', - validate: true, - orders: [ - { - ordertype: 'limit', - type: 'buy', - volume: '0.0001', - price: '45000.00', - }, - { - ordertype: 'limit', - type: 'sell', - volume: '0.0001', - price: '55000.00', - }, - ], -}); -``` +- Spot REST and Futures REST APIs use different authentication models and request shapes. +- Public & private WebSockets require connection lifecycle handling, authentication, and reconnection handling. +- Spot trading over Kraken's asynchronous WebSocket API can be complicated without JavaScript Promises to glue WebSocket API responses to the requests that triggered them. +- Production bots and trading tools need typed request schemas, consistent async behavior, resilient WebSockets, and a connectivity architecture that works. -See also: [Kraken JavaScript Example - How to submit spot orders via REST API](https://siebly.io/examples/Kraken/Spot/Private/submitOrder) +The `@siebly/kraken-api` gives you one JavaScript and TypeScript SDK for Kraken API integration in any Node.js or JavaScript-capable environment: ---- +- Complete API coverage with dedicated REST API clients for each product group, including Spot and Derivatives. +- One `WebsocketClient` for public and private streaming across all Kraken products. +- A `WebsocketAPIClient` for Spot trading over a persistent WebSocket connection, with the convenience of awaitable promise-wrapped WebSocket API requests. Each WebSocket API command can be awaited like a REST API request. +- Automatic heartbeats, reconnect and resubscribe handling for WebSockets. Stay connected, stay in sync. +- TypeScript-first request and response definitions for most SDK methods. +- ESM and CJS support. +- Browser-friendly HMAC signing and proxy support. -## Kraken WebSockets in JavaScript: public and private streaming +The package also includes `InstitutionalClient` and `PartnerClient`, but this guide focuses on the flows most developers look for first: Spot, Futures, market data, account data, and order management. -For long-running processes, WebSockets are key for staying in sync with market data & account state changes. Latency-sensitive systems should subscribe & react to event-driven market & account updates, rather than depending on REST API polling at regular intervals. +--- -> After subscribing to the topics needed by your system, persistent WebSocket connections will provide real-time updates on any changes to your subscribed topics. Stay informed on new market data as it becomes available. Immediately process and react to any account state changes, such as an order state change or fill. Integrating an event-driven design pattern with WebSockets will both reduce your latency and provide much higher capacity for making API calls within the available rate limits. +## What you can build with the [Kraken JavaScript SDK](https://siebly.io/sdk/kraken/javascript) -The Siebly Kraken JavaScript SDK's WebsocketClient handles most of the complexity of working with WebSockets for you. All you need to do is: +This Kraken JavaScript SDK is relevant for any integration with Kraken's APIs and WebSockets, especially if you are building: -- Create an instance of the WebsocketClient. -- Provide read-only API keys, if private topics are required. Market data does not require API keys. -- Ask the WebsocketClient to subscribe to the topics you're interested in. +- Trading bots and execution services +- Real-time market data dashboards +- Internal trader tooling +- Portfolio and balance monitors +- Alerting and signal pipelines +- Reconciliation or account state services +- AI-assisted engineering workflows that need a reliable & typed Kraken integration layer -The SDK handles the connection work for you: +--- -- Open WebSocket connections to the correct domains & endpoints. -- Use your provided proxy, if desired & configured. -- Prepare & dispatch events to authenticate, if needed. -- Prepare & dispatch events to subscribe to the topics you have requested. -- Monitor active WebSocket connections with regular heartbeats. As soon as a potential disconnect is detected (heartbeat timeout), the SDK will automatically: - - Emit a `reconnecting` event, informing you this process has started. - - This is a good time to pause any risky commands until the connection is restored (order management). - - Teardown the stale connection. - - Open a new WebSocket connection. - - Re-authenticate if needed. - - Re-subscribe to the topics you were subscribed to. - - Emit a `reconnected` event, informing you this process has completed. - - This is a good time to query the REST API for any changes you might have missed while disconnected. +## Who this guide is for -### `WebsocketClient` events you will actually care about +This guide is written for JavaScript developers (& LLMs) who: -| Event | Meaning | -| --------------- | ------------------------------------------------- | -| `open` | Connection established | -| `message` | Streaming data received | -| `response` | Subscribe, unsubscribe, and auth acknowledgements | -| `reconnecting` | Connection dropped and retrying | -| `reconnected` | Connection restored and subscriptions resynced | -| `close` | Socket closed | -| `authenticated` | Private auth succeeded | -| `exception` | Errors and unexpected conditions | +- Want to build with the Kraken API offering +- Want a quick, easy, predictable, up-to-date and heavily used (reliable) way to integrate with Kraken's APIs & WebSockets +- Care about typed requests and responses +- Are working with exchange REST APIs & WebSockets for the first time +- Are already using exchange APIs elsewhere and are looking to integrate Kraken +- Need dependable connectivity for systematic trading +- Are comparing raw Kraken integration against a maintained SDK -### Understanding `WS_KEY_MAP` +--- -[`WS_KEY_MAP`](/reference/glossary#ws-key) tells the SDK which Kraken WebSocket endpoint family to use: +## What this one-page course covers -- `spotPublicV2` -- `spotPrivateV2` -- `spotL3V2` -- `derivativesPublicV1` -- `derivativesPrivateV1` +- Installing the Kraken JavaScript SDK by Siebly +- Creating Spot and Futures REST API clients +- Making your first public Spot REST API request +- Streaming public Spot market data over WebSockets +- Subscribing to private Spot account streams +- Placing Spot orders over Kraken's REST API +- Managing Spot orders in batches +- Trading Spot over Kraken's WebSocket API +- Pulling Kraken Futures market data +- Submitting Kraken Futures orders via REST API +- Using Kraken Futures WebSockets +- Production patterns for reconnects, idempotency, logging, and safer rollout -> This matters because different product groups and topic families do not all live on the same connection endpoint. These keys act as primary keys, similar to a database, to uniquely identify a dedicated connection group. +--- -### Public Spot WebSocket topics +## How to get started with the Kraken API in JavaScript? -```typescript -ws.subscribe( - { - topic: 'ticker', - payload: { symbol: ['BTC/USD', 'ETH/USD'] }, - }, - WS_KEY_MAP.spotPublicV2, -); +If you don't have Node.js installed yet, refer to the Node.js documentation on getting started with Node.js. The Kraken JavaScript SDK is published to both [GitHub](https://github.com/sieblyio/kraken-api) and [npm](https://www.npmjs.com/package/@siebly/kraken-api). -ws.subscribe( - { - topic: 'trade', - payload: { symbol: ['BTC/USD'] }, - }, - WS_KEY_MAP.spotPublicV2, -); +Install the SDK with npm: -ws.subscribe( - { - topic: 'ohlc', - payload: { - symbol: ['BTC/USD'], - interval: 1, - }, - }, - WS_KEY_MAP.spotPublicV2, -); +```bash +npm install @siebly/kraken-api ``` -You can also batch multiple subscriptions that share the same `WsKey`, by sending an array of WebSocket topics: +Or, if preferred, use your favourite npm-compatible package manager: -```typescript -ws.subscribe( - [ - { topic: 'ticker', payload: { symbol: ['BTC/USD'] } }, - { topic: 'trade', payload: { symbol: ['BTC/USD'] } }, - { - topic: 'instrument', - payload: { - symbol: ['BTC/USD'], - include_tokenized_assets: true, - }, - }, - ], - WS_KEY_MAP.spotPublicV2, -); +```bash +# or pnpm: +pnpm install @siebly/kraken-api +# or yarn: +yarn add @siebly/kraken-api ``` -### Private Spot WebSocket topics +Create API keys where Kraken documents them: -The SDK can authenticate and manage private Spot streams for you: +- Spot: [Kraken Spot API key instructions](https://support.kraken.com/articles/360000919966-how-to-create-an-api-key) +- Futures: [Kraken Futures API key instructions](https://pro.kraken.com/app/settings/api) -```typescript -import { WebsocketClient, WS_KEY_MAP } from '@siebly/kraken-api'; +> Use the minimum permissions needed for your scenario. Trading does not require withdrawal permissions. Analytics does not require trading permissions. -const ws = new WebsocketClient({ - apiKey: process.env.API_SPOT_KEY!, - apiSecret: process.env.API_SPOT_SECRET!, -}); +Important auth difference: -ws.subscribe( - { - topic: 'executions', - payload: { - snap_trades: true, - snap_orders: true, - order_status: true, - ratecounter: true, - }, - }, - WS_KEY_MAP.spotPrivateV2, -); +- Spot & futures have different API keys. +- Make sure the API keys you have created are for the correct product group. +- API keys for Spot will only work for Spot APIs. +- API keys for Futures will only work for Futures APIs. +- Most market data does not require API keys. -ws.subscribe( - { - topic: 'balances', - payload: {}, - }, - WS_KEY_MAP.spotPrivateV2, -); +Typical environment variables: -ws.subscribe( - { - topic: 'level3', - payload: { - symbol: ['BTC/USD'], - }, - }, - WS_KEY_MAP.spotL3V2, -); -``` +```bash +export API_SPOT_KEY='your-spot-api-key' +export API_SPOT_SECRET='your-spot-api-secret' -The Level 3 order book is a special case. It uses the dedicated L3 endpoint, so `spotL3V2` matters. +export API_FUTURES_KEY='your-futures-api-key' +export API_FUTURES_SECRET='your-futures-api-secret' +``` -See also: +For local Node.js examples that use a `.env` file, make `.env` loading automatic before reading `process.env`. Prefer Node.js built-in `--env-file` or `--env-file-if-exists` in package scripts when supported; otherwise use `process.loadEnvFile`, `dotenv/config`, or the repo's existing loader. Real process environment variables should override `.env`. -- [Kraken JavaScript Example - How to subscribe to & consume spot market data events](https://siebly.io/examples/Kraken/Spot/WebSockets/publicWs) -- [Kraken JavaScript Example - How to subscribe to & consume private spot account events](https://siebly.io/examples/Kraken/Spot/WebSockets/privateWs) +If you are only testing public endpoints, you do not need any keys at all. --- -## Spot trading over Kraken's WebSocket API with `WebsocketAPIClient` - -Kraken supports Spot trading over a persistent WebSocket connection. While each REST API call requires a new connection to be opened & signed per API call, the WebSocket API allows a persistent WebSocket connection to be opened & authenticated once, and then reused for any WS-API commands sent by your system. This can significantly reduce latency for latency-sensitive and higher-frequency trading systems compared with using the REST API alone. - -If that model fits your system, `WebsocketAPIClient` gives you REST-like methods over the WebSocket API. +## Start building: first Kraken API calls in JavaScript -> This utility class is wrapped around the Siebly Kraken JavaScript SDK's WebsocketClient. A persistent WebSocket API connection is automatically opened and managed as needed. Any API calls made via the WebsocketAPIClient are conveniently wrapped in JavaScript promises. This allows for much simpler asynchronous design patterns that feel very much like a REST API, with all the benefits of a persistent WebSocket API connection. +If you only want the fastest path to a working integration, this is the section to start from. -Make a WebSocket API request via a simple function call. Await the result. All of the speed with significantly less complexity. +### 1. First Spot REST API request ```typescript -import { WebsocketAPIClient } from '@siebly/kraken-api'; - -const wsApi = new WebsocketAPIClient({ - apiKey: process.env.API_SPOT_KEY!, - apiSecret: process.env.API_SPOT_SECRET!, -}); +import { SpotClient } from '@siebly/kraken-api'; -wsApi.getWSClient().on('open', (data) => { - console.log('ws api open', data?.wsKey); -}); +const client = new SpotClient(); -wsApi.getWSClient().on('exception', console.error); +async function main() { + const serverTime = await client.getServerTime(); + const systemStatus = await client.getSystemStatus(); + const ticker = await client.getTicker({ pair: 'XBTUSD' }); + const orderBook = await client.getOrderBook({ pair: 'XBTUSD', count: 10 }); -const order = await wsApi.submitSpotOrder({ - order_type: 'limit', - side: 'buy', - limit_price: 26500.4, - order_qty: 1.2, - symbol: 'BTC/USD', -}); + console.log({ + serverTime, + systemStatus, + ticker, + orderBook, + }); +} -await wsApi.amendSpotOrder({ - order_id: 'TEST-ORDER-ID', - order_qty: 1.5, - limit_price: 27000, -}); +// Since each of the above API calls is wrapped in an awaited promise, a high level catch will detect any exceptions: +main().catch(console.error); +``` -await wsApi.cancelSpotOrder({ - order_id: ['TEST-ORDER-ID'], -}); +This is the quickest way to verify that your Kraken API JavaScript integration is wired correctly for public REST API calls. -await wsApi.cancelAllSpotOrders(); +See also: [Kraken JavaScript Example - How to query spot market data](https://siebly.io/examples/Kraken/Spot/Public/marketData) + +### 2. First public Spot WebSocket stream + +```typescript +import { WebsocketClient, WS_KEY_MAP } from '@siebly/kraken-api'; + +const ws = new WebsocketClient(); + +ws.on('open', (data) => console.log('connected', data?.wsKey)); +ws.on('response', (data) => console.log('response', JSON.stringify(data))); +ws.on('message', (data) => console.log('message', JSON.stringify(data))); +ws.on('reconnected', (data) => console.log('reconnected', data?.wsKey)); +ws.on('exception', console.error); + +ws.subscribe( + { + topic: 'ticker', + payload: { + symbol: ['BTC/USD', 'ETH/USD'], + }, + }, + WS_KEY_MAP.spotPublicV2, +); ``` -Other supported Spot WebSocket API flows include: +This gets a public Kraken Spot WebSocket stream running in JavaScript. -- conditional Spot orders -- trigger-style orders -- batch Spot order submission -- batch Spot order cancellation -- cancel-all-after timeout handling +See also: [Kraken JavaScript Example - How to subscribe to spot market data WebSocket stream](https://siebly.io/examples/Kraken/Spot/WebSockets/publicWs) -See also: [Kraken JavaScript Example - How to send/manage low-latency spot orders via the WebSocket API](https://siebly.io/examples/Kraken/Spot/WebSockets/wsAPI#L64) +### 3. First private Spot WebSocket stream -Refer to the Kraken API documentation for a detailed list of available WebSocket API capabilities. +```typescript +import { WebsocketClient, WS_KEY_MAP } from '@siebly/kraken-api'; ---- +const ws = new WebsocketClient({ + apiKey: process.env.API_SPOT_KEY!, + apiSecret: process.env.API_SPOT_SECRET!, +}); -## Kraken Futures API in Node.js and TypeScript +ws.on('authenticated', (data) => console.log('authenticated', data?.wsKey)); +ws.on('response', (data) => console.log('response', JSON.stringify(data))); +ws.on('message', (data) => console.log('message', JSON.stringify(data))); +ws.on('reconnected', (data) => console.log('reconnected', data?.wsKey)); +ws.on('exception', console.error); -While it looks & feels similar, Kraken's Derivatives use a different REST API surface and different request naming conventions than the Kraken Spot APIs. The [`@siebly/kraken-api` JavaScript Kraken SDK](https://www.npmjs.com/package/@siebly/kraken-api) manages this complexity for you, so you can focus on building & integrating your workflows. +ws.subscribe( + { + topic: 'executions', + payload: { + snap_trades: true, + snap_orders: true, + order_status: true, + }, + }, + WS_KEY_MAP.spotPrivateV2, +); -Usage is similar to Spot. Create an instance of the utility class dedicated to the Kraken Derivatives API, the DerivativesClient. Provide your API keys if private API calls are desired. Call & await functions corresponding to the REST API endpoint you would like to use. +ws.subscribe( + { + topic: 'balances', + payload: {}, + }, + WS_KEY_MAP.spotPrivateV2, +); +``` -Detailed request building, routing & authentication are all handled under the hood by the SDK. Below are curated examples for common scenarios. +For private Spot v2 topics, the SDK can fetch and refresh the token for you. You do not need to manually fetch a token and inject it into every subscribe payload. -### Create a public Futures client +See also: [Kraken JavaScript Example - How to subscribe to spot account change WebSocket events](https://siebly.io/examples/Kraken/Spot/WebSockets/privateWs) + +### 4. First Spot order over REST API ```typescript -import { DerivativesClient } from '@siebly/kraken-api'; +import { SpotClient } from '@siebly/kraken-api'; -const client = new DerivativesClient(); +const client = new SpotClient({ + apiKey: process.env.API_SPOT_KEY!, + apiSecret: process.env.API_SPOT_SECRET!, +}); + +async function placeOrder() { + const result = await client.submitOrder({ + ordertype: 'limit', + type: 'buy', + pair: 'XBTUSD', + volume: '0.0001', + price: '10000', + validate: true, + cl_ord_id: client.generateNewOrderID(), + }); + + console.log(result); +} + +placeOrder().catch(console.error); ``` -### Create a private Futures client +Use `validate: true` when you want to validate the request shape without sending the live order. Remove `validate: true` when you are ready to submit. + +See also: [Kraken JavaScript Example - How to submit spot orders](https://siebly.io/examples/Kraken/Spot/Private/submitOrder) + +### 5. First Futures order ```typescript import { DerivativesClient } from '@siebly/kraken-api'; @@ -8052,188 +8205,607 @@ import { DerivativesClient } from '@siebly/kraken-api'; const client = new DerivativesClient({ apiKey: process.env.API_FUTURES_KEY!, apiSecret: process.env.API_FUTURES_SECRET!, - // testnet: true, // optional: route Derivatives REST API calls to Kraken's demo environment + // testnet: true, // optional: route Derivatives REST calls to Kraken's demo environment }); + +async function placeFuturesOrder() { + const result = await client.submitOrder({ + orderType: 'lmt', + symbol: 'PF_ETHUSD', + side: 'buy', + size: 0.01, + limitPrice: 1000, + cliOrdId: client.generateNewOrderID(), + }); + + console.log(result); +} + +placeFuturesOrder().catch(console.error); ``` -### Common public Futures market data calls +See also: [Kraken JavaScript Example - How to submit futures/derivatives orders](https://siebly.io/examples/Kraken/Derivatives/Private/submitOrder) + +--- + +## Kraken Spot REST API in JavaScript and TypeScript + +Most integrations start with Spot REST APIs because it is one of the simplest ways to test basic connectivity, such as querying account state and submitting orders. + +### Create a public Spot client ```typescript -const allTickers = await client.getTickers(); -const ticker = await client.getTicker({ symbol: 'PF_ETHUSD' }); -const orderBook = await client.getOrderbook({ symbol: 'PF_ETHUSD' }); -const instruments = await client.getInstruments(); -const feeSchedules = await client.getFeeSchedules(); -const candles = await client.getCandles({ - tickType: 'trade', - symbol: 'PF_ETHUSD', - resolution: '1h', -}); +import { SpotClient } from '@siebly/kraken-api'; + +const client = new SpotClient(); ``` -You can also query recent public trade-style events: +Public calls do not require keys. + +### Create a private Spot client + +If you plan on making private API calls, include API keys when creating an instance of the SpotClient class: ```typescript -const executions = await client.getPublicExecutionEvents({ - tradeable: 'PF_ETHUSD', +import { SpotClient } from '@siebly/kraken-api'; + +const client = new SpotClient({ + apiKey: process.env.API_SPOT_KEY!, + apiSecret: process.env.API_SPOT_SECRET!, }); ``` -See also: [Kraken JavaScript Example - How to query derivatives market data](https://siebly.io/examples/Kraken/Derivatives/Public/marketData) +### Common public Spot market data calls -### Futures order examples +```typescript +const serverTime = await client.getServerTime(); +const systemStatus = await client.getSystemStatus(); +const assetInfo = await client.getAssetInfo({ asset: 'XBT,ETH' }); +const assetPairs = await client.getAssetPairs({ pair: 'XBTUSD,ETHUSD' }); +const ticker = await client.getTicker({ pair: 'XBTUSD' }); +const orderBook = await client.getOrderBook({ pair: 'XBTUSD', count: 10 }); +const candles = await client.getCandles({ pair: 'XBTUSD', interval: 60 }); +const recentTrades = await client.getRecentTrades({ + pair: 'XBTUSD', + count: 10, +}); +const recentSpreads = await client.getRecentSpreads({ pair: 'XBTUSD' }); +``` -Limit order: +### Common private Spot account calls ```typescript -await client.submitOrder({ - orderType: 'lmt', - symbol: 'PF_ETHUSD', - side: 'buy', - size: 0.01, - limitPrice: 1000, - cliOrdId: client.generateNewOrderID(), +const balance = await client.getAccountBalance(); +const tradeBalance = await client.getTradeBalance(); +const openOrders = await client.getOpenOrders(); +const openOrdersWithTrades = await client.getOpenOrders({ trades: true }); +const closedOrders = await client.getClosedOrders({ + trades: true, + start: Math.floor(Date.now() / 1000) - 86400 * 7, // last 7 days }); ``` +See also: + +- [Kraken JavaScript Example - How to query spot market data](https://siebly.io/examples/Kraken/Spot/Public/marketData) +- [Kraken JavaScript Example - How to query Kraken spot account balances, orders & transactions](https://siebly.io/examples/Kraken/Spot/Private/account) +- [Kraken JavaScript Example - How to query, manage, amend & cancel spot orders](https://siebly.io/examples/Kraken/Spot/Private/orderManagement) + +### Spot order examples + Market order: ```typescript await client.submitOrder({ - orderType: 'mkt', - symbol: 'PF_ETHUSD', - side: 'sell', - size: 0.01, + ordertype: 'market', + type: 'buy', + volume: '0.01', + pair: 'XBTUSD', }); ``` -Post-only and reduce-only: +Limit order: ```typescript await client.submitOrder({ - orderType: 'post', - symbol: 'PF_ETHUSD', - side: 'buy', - size: 0.01, - limitPrice: 1000, - cliOrdId: client.generateNewOrderID(), + ordertype: 'limit', + type: 'buy', + volume: '0.0001', + pair: 'XBTUSD', + price: '10000', }); +``` + +Post-only limit order: +```typescript await client.submitOrder({ - orderType: 'lmt', - symbol: 'PF_ETHUSD', - side: 'sell', - size: 1, - limitPrice: 1000, - reduceOnly: true, + ordertype: 'limit', + type: 'buy', + volume: '0.001', + pair: 'XBTEUR', + price: '1000.00', + oflags: 'post', + timeinforce: 'GTC', }); ``` -Batch order management: +### Spot batch order management + +If you want to stage multiple orders on one pair, batch APIs are a better fit than serially sending single orders. ```typescript -await client.batchOrderManagement({ - json: { - batchOrder: [ - { - order: 'send', - order_tag: 'order-1', - orderType: 'lmt', - symbol: 'PF_ETHUSD', - side: 'buy', - size: 0.01, - limitPrice: 1000, - cliOrdId: client.generateNewOrderID(), - }, - ], - }, +await client.submitBatchOrders({ + pair: 'XBTUSD', + orders: [ + { + ordertype: 'limit', + type: 'buy', + volume: '0.0001', + price: '10000.00', + timeinforce: 'GTC', + // cl_ord_id: client.generateNewOrderID(), // optional: include a custom order ID before placing your order, for easier tracking + }, + { + ordertype: 'limit', + type: 'sell', + volume: '0.0001', + price: '13000.00', + timeinforce: 'GTC', + // cl_ord_id: client.generateNewOrderID(), // optional: include a custom order ID before placing your order, for easier tracking + }, + ], }); ``` -See also: [Kraken JavaScript Example - How to submit derivatives/futures orders](https://siebly.io/examples/Kraken/Derivatives/Private/submitOrder) +Validate the batch without sending: + +```typescript +await client.submitBatchOrders({ + pair: 'XBTUSD', + validate: true, + orders: [ + { + ordertype: 'limit', + type: 'buy', + volume: '0.0001', + price: '45000.00', + }, + { + ordertype: 'limit', + type: 'sell', + volume: '0.0001', + price: '55000.00', + }, + ], +}); +``` + +See also: [Kraken JavaScript Example - How to submit spot orders via REST API](https://siebly.io/examples/Kraken/Spot/Private/submitOrder) --- -## Kraken Futures WebSockets in JavaScript +## Kraken WebSockets in JavaScript: public and private streaming -For subscribing to futures/derivatives market & account data in JavaScript (& Node.js), the SDK automatically handles this as well via the same `WebsocketClient` utility class. +For long-running processes, WebSockets are key for staying in sync with market data & account state changes. Latency-sensitive systems should subscribe & react to event-driven market & account updates, rather than depending on REST API polling at regular intervals. -```typescript -import { WebsocketClient, WS_KEY_MAP } from '@siebly/kraken-api'; +> After subscribing to the topics needed by your system, persistent WebSocket connections will provide real-time updates on any changes to your subscribed topics. Stay informed on new market data as it becomes available. Immediately process and react to any account state changes, such as an order state change or fill. Integrating an event-driven design pattern with WebSockets will both reduce your latency and provide much higher capacity for making API calls within the available rate limits. -const ws = new WebsocketClient(); +The Siebly Kraken JavaScript SDK's WebsocketClient handles most of the complexity of working with WebSockets for you. All you need to do is: -ws.on('open', (data) => console.log('connected', data?.wsKey)); -ws.on('message', (data) => console.log('message', JSON.stringify(data))); -ws.on('reconnected', (data) => console.log('reconnected', data?.wsKey)); -ws.on('exception', console.error); +- Create an instance of the WebsocketClient. +- Provide read-only API keys, if private topics are required. Market data does not require API keys. +- Ask the WebsocketClient to subscribe to the topics you're interested in. + +The SDK handles the connection work for you: + +- Open WebSocket connections to the correct domains & endpoints. +- Use your provided proxy, if desired & configured. +- Prepare & dispatch events to authenticate, if needed. +- Prepare & dispatch events to subscribe to the topics you have requested. +- Monitor active WebSocket connections with regular heartbeats. As soon as a potential disconnect is detected (heartbeat timeout), the SDK will automatically: + - Emit a `reconnecting` event, informing you this process has started. + - This is a good time to pause any risky commands until the connection is restored (order management). + - Teardown the stale connection. + - Open a new WebSocket connection. + - Re-authenticate if needed. + - Re-subscribe to the topics you were subscribed to. + - Emit a `reconnected` event, informing you this process has completed. + - This is a good time to query the REST API for any changes you might have missed while disconnected. + +### `WebsocketClient` events you will actually care about + +| Event | Meaning | +| --------------- | ------------------------------------------------- | +| `open` | Connection established | +| `message` | Streaming data received | +| `response` | Subscribe, unsubscribe, and auth acknowledgements | +| `reconnecting` | Connection dropped and retrying | +| `reconnected` | Connection restored and subscriptions resynced | +| `close` | Socket closed | +| `authenticated` | Private auth succeeded | +| `exception` | Errors and unexpected conditions | + +### Understanding `WS_KEY_MAP` + +[`WS_KEY_MAP`](/reference/glossary#ws-key) tells the SDK which Kraken WebSocket endpoint family to use: + +- `spotPublicV2` +- `spotPrivateV2` +- `spotL3V2` +- `derivativesPublicV1` +- `derivativesPrivateV1` + +> This matters because different product groups and topic families do not all live on the same connection endpoint. These keys act as primary keys, similar to a database, to uniquely identify a dedicated connection group. + +### Public Spot WebSocket topics + +```typescript +ws.subscribe( + { + topic: 'ticker', + payload: { symbol: ['BTC/USD', 'ETH/USD'] }, + }, + WS_KEY_MAP.spotPublicV2, +); ws.subscribe( { topic: 'trade', + payload: { symbol: ['BTC/USD'] }, + }, + WS_KEY_MAP.spotPublicV2, +); + +ws.subscribe( + { + topic: 'ohlc', payload: { - product_ids: ['PI_XBTUSD', 'PI_ETHUSD'], + symbol: ['BTC/USD'], + interval: 1, }, }, - WS_KEY_MAP.derivativesPublicV1, + WS_KEY_MAP.spotPublicV2, ); ``` -See also: - -- [Kraken JavaScript Example - How to subscribe to derivatives/futures account change WebSocket events](https://siebly.io/examples/Kraken/Derivatives/WebSockets/privateWs) -- [Kraken JavaScript Example - How to subscribe to derivatives/futures market data WebSocket events](https://siebly.io/examples/Kraken/Derivatives/WebSockets/publicWs) - ---- - -## Production notes for real trading systems +You can also batch multiple subscriptions that share the same `WsKey`, by sending an array of WebSocket topics: -This is where SDKs usually earn their keep. +```typescript +ws.subscribe( + [ + { topic: 'ticker', payload: { symbol: ['BTC/USD'] } }, + { topic: 'trade', payload: { symbol: ['BTC/USD'] } }, + { + topic: 'instrument', + payload: { + symbol: ['BTC/USD'], + include_tokenized_assets: true, + }, + }, + ], + WS_KEY_MAP.spotPublicV2, +); +``` -### 1. Use client-generated order IDs +### Private Spot WebSocket topics -For Spot, use `cl_ord_id`. For Futures, use `cliOrdId`. This makes retries and reconciliation safer. +The SDK can authenticate and manage private Spot streams for you: ```typescript -const orderIdForEntry1 = client.generateNewOrderID(); +import { WebsocketClient, WS_KEY_MAP } from '@siebly/kraken-api'; -const result = await client.submitOrder({ - ordertype: 'limit', - type: 'buy', - pair: 'XBTUSD', - volume: '0.0001', - price: '10000', - validate: true, - cl_ord_id: orderIdForEntry1, +const ws = new WebsocketClient({ + apiKey: process.env.API_SPOT_KEY!, + apiSecret: process.env.API_SPOT_SECRET!, }); -console.log(result); +ws.subscribe( + { + topic: 'executions', + payload: { + snap_trades: true, + snap_orders: true, + order_status: true, + ratecounter: true, + }, + }, + WS_KEY_MAP.spotPrivateV2, +); -// Detect entry 1 has filled, by looking for an order fill with cl_ord_id === orderIdForEntry1 either via REST API or async WebSocket updates. +ws.subscribe( + { + topic: 'balances', + payload: {}, + }, + WS_KEY_MAP.spotPrivateV2, +); + +ws.subscribe( + { + topic: 'level3', + payload: { + symbol: ['BTC/USD'], + }, + }, + WS_KEY_MAP.spotL3V2, +); ``` -### 2. Treat reconnects as a normal condition +The Level 3 order book is a special case. It uses the dedicated L3 endpoint, so `spotL3V2` matters. -Listen for `reconnecting` and `reconnected`. A dropped connection is not the exceptional case in production. Recovery behavior is part of the design. WebSockets can be unstable, especially during volatility. +See also: -The important part is detecting issues early (handled by SDK), promptly reconnecting (handled by SDK), and ensuring your system remains in sync when the SDK emits a `reconnected` event (up to your implementation). +- [Kraken JavaScript Example - How to subscribe to & consume spot market data events](https://siebly.io/examples/Kraken/Spot/WebSockets/publicWs) +- [Kraken JavaScript Example - How to subscribe to & consume private spot account events](https://siebly.io/examples/Kraken/Spot/WebSockets/privateWs) -### 3. Start public, then validate private, then trade tiny +--- -The lowest-friction rollout path is: +## Spot trading over Kraken's WebSocket API with `WebsocketAPIClient` -1. Public REST APIs -2. Public WebSockets -3. Private account streams -4. Small live trading tests +Kraken supports Spot trading over a persistent WebSocket connection. While each REST API call requires a new connection to be opened & signed per API call, the WebSocket API allows a persistent WebSocket connection to be opened & authenticated once, and then reused for any WS-API commands sent by your system. This can significantly reduce latency for latency-sensitive and higher-frequency trading systems compared with using the REST API alone. -If using WebSockets for updates, integrate a backfill workflow after connecting: +If that model fits your system, `WebsocketAPIClient` gives you REST-like methods over the WebSocket API. -1. Connect and subscribe to WebSocket topics, but pause processing incoming data (drop data as it arrives) -2. Backfill any missing data via REST API (hydrate internal state). -3. Once backfill is complete, enable processing incoming data. +> This utility class is wrapped around the Siebly Kraken JavaScript SDK's WebsocketClient. A persistent WebSocket API connection is automatically opened and managed as needed. Any API calls made via the WebsocketAPIClient are conveniently wrapped in JavaScript promises. This allows for much simpler asynchronous design patterns that feel very much like a REST API, with all the benefits of a persistent WebSocket API connection. -This ensures your system has the full history it needs before it starts processing new market & account updates. +Make a WebSocket API request via a simple function call. Await the result. All of the speed with significantly less complexity. + +```typescript +import { WebsocketAPIClient } from '@siebly/kraken-api'; + +const wsApi = new WebsocketAPIClient({ + apiKey: process.env.API_SPOT_KEY!, + apiSecret: process.env.API_SPOT_SECRET!, +}); + +wsApi.getWSClient().on('open', (data) => { + console.log('ws api open', data?.wsKey); +}); + +wsApi.getWSClient().on('exception', console.error); + +const order = await wsApi.submitSpotOrder({ + order_type: 'limit', + side: 'buy', + limit_price: 26500.4, + order_qty: 1.2, + symbol: 'BTC/USD', +}); + +await wsApi.amendSpotOrder({ + order_id: 'TEST-ORDER-ID', + order_qty: 1.5, + limit_price: 27000, +}); + +await wsApi.cancelSpotOrder({ + order_id: ['TEST-ORDER-ID'], +}); + +await wsApi.cancelAllSpotOrders(); +``` + +Other supported Spot WebSocket API flows include: + +- conditional Spot orders +- trigger-style orders +- batch Spot order submission +- batch Spot order cancellation +- cancel-all-after timeout handling + +See also: [Kraken JavaScript Example - How to send/manage low-latency spot orders via the WebSocket API](https://siebly.io/examples/Kraken/Spot/WebSockets/wsAPI#L64) + +Refer to the Kraken API documentation for a detailed list of available WebSocket API capabilities. + +--- + +## Kraken Futures API in Node.js and TypeScript + +While it looks & feels similar, Kraken's Derivatives use a different REST API surface and different request naming conventions than the Kraken Spot APIs. The [`@siebly/kraken-api` JavaScript Kraken SDK](https://www.npmjs.com/package/@siebly/kraken-api) manages this complexity for you, so you can focus on building & integrating your workflows. + +Usage is similar to Spot. Create an instance of the utility class dedicated to the Kraken Derivatives API, the DerivativesClient. Provide your API keys if private API calls are desired. Call & await functions corresponding to the REST API endpoint you would like to use. + +Detailed request building, routing & authentication are all handled under the hood by the SDK. Below are curated examples for common scenarios. + +### Create a public Futures client + +```typescript +import { DerivativesClient } from '@siebly/kraken-api'; + +const client = new DerivativesClient(); +``` + +### Create a private Futures client + +```typescript +import { DerivativesClient } from '@siebly/kraken-api'; + +const client = new DerivativesClient({ + apiKey: process.env.API_FUTURES_KEY!, + apiSecret: process.env.API_FUTURES_SECRET!, + // testnet: true, // optional: route Derivatives REST API calls to Kraken's demo environment +}); +``` + +### Common public Futures market data calls + +```typescript +const allTickers = await client.getTickers(); +const ticker = await client.getTicker({ symbol: 'PF_ETHUSD' }); +const orderBook = await client.getOrderbook({ symbol: 'PF_ETHUSD' }); +const instruments = await client.getInstruments(); +const feeSchedules = await client.getFeeSchedules(); +const candles = await client.getCandles({ + tickType: 'trade', + symbol: 'PF_ETHUSD', + resolution: '1h', +}); +``` + +You can also query recent public trade-style events: + +```typescript +const executions = await client.getPublicExecutionEvents({ + tradeable: 'PF_ETHUSD', +}); +``` + +See also: [Kraken JavaScript Example - How to query derivatives market data](https://siebly.io/examples/Kraken/Derivatives/Public/marketData) + +### Futures order examples + +Limit order: + +```typescript +await client.submitOrder({ + orderType: 'lmt', + symbol: 'PF_ETHUSD', + side: 'buy', + size: 0.01, + limitPrice: 1000, + cliOrdId: client.generateNewOrderID(), +}); +``` + +Market order: + +```typescript +await client.submitOrder({ + orderType: 'mkt', + symbol: 'PF_ETHUSD', + side: 'sell', + size: 0.01, +}); +``` + +Post-only and reduce-only: + +```typescript +await client.submitOrder({ + orderType: 'post', + symbol: 'PF_ETHUSD', + side: 'buy', + size: 0.01, + limitPrice: 1000, + cliOrdId: client.generateNewOrderID(), +}); + +await client.submitOrder({ + orderType: 'lmt', + symbol: 'PF_ETHUSD', + side: 'sell', + size: 1, + limitPrice: 1000, + reduceOnly: true, +}); +``` + +Batch order management: + +```typescript +await client.batchOrderManagement({ + json: { + batchOrder: [ + { + order: 'send', + order_tag: 'order-1', + orderType: 'lmt', + symbol: 'PF_ETHUSD', + side: 'buy', + size: 0.01, + limitPrice: 1000, + cliOrdId: client.generateNewOrderID(), + }, + ], + }, +}); +``` + +See also: [Kraken JavaScript Example - How to submit derivatives/futures orders](https://siebly.io/examples/Kraken/Derivatives/Private/submitOrder) + +--- + +## Kraken Futures WebSockets in JavaScript + +For subscribing to futures/derivatives market & account data in JavaScript (& Node.js), the SDK automatically handles this as well via the same `WebsocketClient` utility class. + +```typescript +import { WebsocketClient, WS_KEY_MAP } from '@siebly/kraken-api'; + +const ws = new WebsocketClient(); + +ws.on('open', (data) => console.log('connected', data?.wsKey)); +ws.on('message', (data) => console.log('message', JSON.stringify(data))); +ws.on('reconnected', (data) => console.log('reconnected', data?.wsKey)); +ws.on('exception', console.error); + +ws.subscribe( + { + topic: 'trade', + payload: { + product_ids: ['PI_XBTUSD', 'PI_ETHUSD'], + }, + }, + WS_KEY_MAP.derivativesPublicV1, +); +``` + +See also: + +- [Kraken JavaScript Example - How to subscribe to derivatives/futures account change WebSocket events](https://siebly.io/examples/Kraken/Derivatives/WebSockets/privateWs) +- [Kraken JavaScript Example - How to subscribe to derivatives/futures market data WebSocket events](https://siebly.io/examples/Kraken/Derivatives/WebSockets/publicWs) + +--- + +## Production notes for real trading systems + +This is where SDKs usually earn their keep. + +### 1. Use client-generated order IDs + +For Spot, use `cl_ord_id`. For Futures, use `cliOrdId`. This makes retries and reconciliation safer. + +```typescript +const orderIdForEntry1 = client.generateNewOrderID(); + +const result = await client.submitOrder({ + ordertype: 'limit', + type: 'buy', + pair: 'XBTUSD', + volume: '0.0001', + price: '10000', + validate: true, + cl_ord_id: orderIdForEntry1, +}); + +console.log(result); + +// Detect entry 1 has filled, by looking for an order fill with cl_ord_id === orderIdForEntry1 either via REST API or async WebSocket updates. +``` + +### 2. Treat reconnects as a normal condition + +Listen for `reconnecting` and `reconnected`. A dropped connection is not the exceptional case in production. Recovery behavior is part of the design. WebSockets can be unstable, especially during volatility. + +The important part is detecting issues early (handled by SDK), promptly reconnecting (handled by SDK), and ensuring your system remains in sync when the SDK emits a `reconnected` event (up to your implementation). + +### 3. Start public, then validate private, then trade tiny + +The lowest-friction rollout path is: + +1. Public REST APIs +2. Public WebSockets +3. Private account streams +4. Small live trading tests + +If using WebSockets for updates, integrate a backfill workflow after connecting: + +1. Connect and subscribe to WebSocket topics, but pause processing incoming data (drop data as it arrives) +2. Backfill any missing data via REST API (hydrate internal state). +3. Once backfill is complete, enable processing incoming data. + +This ensures your system has the full history it needs before it starts processing new market & account updates. ### 4. Keep Spot and Futures credentials separate @@ -8905,2242 +9477,2195 @@ include_tokenized_assets: true, // default: false */ ================ -File: src/lib/websocket/websocket-util.ts +File: src/lib/requestUtils.ts ================ -import WebSocket from 'isomorphic-ws'; +/** + * Used to switch how authentication/requests work under the hood + */ ⋮---- -import { WSAPIRequestOperationKrakenSpot } from '../../types/websockets/ws-api.js'; -import { WSTopic } from '../../types/websockets/ws-subscriptions.js'; +/** Spot */ ⋮---- -/** Should be one WS key per unique URL */ +/** Futures */ ⋮---- -/** - * Public WebSocket subscriptions for Kraken Spot products, via the V2 API +/** Futures Demo */ +⋮---- +/** Institutional */ +⋮---- +/** Partner */ +⋮---- +export type RestClientType = + (typeof REST_CLIENT_TYPE_ENUM)[keyof typeof REST_CLIENT_TYPE_ENUM]; +⋮---- +export interface RestClientOptions { + /** Your API key */ + apiKey?: string; + + /** Your API secret */ + apiSecret?: string; + + /** + * Set to `true` to connect to testnet (Kraken's demo environment). The live environment is used by default. * - * - Ref: https://docs.kraken.com/api/docs/guides/spot-ws-intro - * - Channels: https://docs.kraken.com/api/docs/websocket-v2/add_order + * Note: as of November 2025, only the DerivativesClient supports testnet connections. Kraken refer to this as the "Demo" environment, but it is effectively a testnet. + * This is a place to test your API integration. It is not a good place to test strategy performance, as the liquidity and orderbook dynamics are very different to the live environment. * - * Note: Use spotPrivateV2 for private channels (requires API keys). + * Refer to the following for more information: + * https://github.com/tiagosiebler/awesome-crypto-examples/wiki/CEX-Testnets */ -⋮---- -/** - * Public WebSocket subscriptions for Kraken Derivatives products, via the V1 API: - * - * - Ref: https://docs.kraken.com/api/docs/guides/futures-websockets - * - Channels: https://docs.kraken.com/api/docs/futures-api/websocket/open_orders + testnet?: boolean; + + /** + * Use access token instead of sign, if this is provided. + * For guidance refer to: https://github.com/tiagosiebler/kucoin-api/issues/2 + */ + apiAccessToken?: string; + + /** Default: false. If true, we'll throw errors if any params are undefined */ + strictParamValidation?: boolean; + + /** + * Optionally override API protocol + domain + * e.g baseUrl: 'https://api.kraken.com' + **/ + baseUrl?: string; + + /** Default: true. whether to try and post-process request exceptions (and throw them). */ + parseExceptions?: boolean; + + customTimestampFn?: () => number; + + /** + * Enable keep alive for REST API requests (via axios). + */ + keepAlive?: boolean; + + /** + * When using HTTP KeepAlive, how often to send TCP KeepAlive packets over sockets being kept alive. Default = 1000. + * Only relevant if keepAlive is set to true. + * Default: 1000 (defaults comes from https agent) + */ + keepAliveMsecs?: number; + + /** + * Allows you to provide a custom "signMessage" function, e.g. to use node's much faster createHmac method * - * Note: While both Public and Private channels use the same WebSocket URL, we will actually maintain separate connections for easier management. Private channels require authentication and the connection is authenticated automatically. + * Look in the examples folder for a demonstration on using node's createHmac instead. */ + customSignMessageFn?: (message: string, secret: string) => Promise; +} ⋮---- -/** This is used to differentiate between each of the available websocket streams */ -export type WsKey = (typeof WS_KEY_MAP)[keyof typeof WS_KEY_MAP]; +/** Your API key */ ⋮---- -export type WSOperation = 'subscribe' | 'unsubscribe'; +/** Your API secret */ ⋮---- /** - * Normalised internal format for a request (subscribe/unsubscribe/etc) on a topic, with optional parameters. - * - * - Topic: the topic this event is for - * - Payload: the parameters to include, optional. E.g. auth requires key + sign. Some topics allow configurable parameters. - */ -export interface WSTopicRequest< - TWSTopic extends WSTopic = WSTopic, - TWSPayload = any, -> { - topic: TWSTopic; - payload?: TWSPayload; -} + * Set to `true` to connect to testnet (Kraken's demo environment). The live environment is used by default. + * + * Note: as of November 2025, only the DerivativesClient supports testnet connections. Kraken refer to this as the "Demo" environment, but it is effectively a testnet. + * This is a place to test your API integration. It is not a good place to test strategy performance, as the liquidity and orderbook dynamics are very different to the live environment. + * + * Refer to the following for more information: + * https://github.com/tiagosiebler/awesome-crypto-examples/wiki/CEX-Testnets + */ ⋮---- /** - * Conveniently allow users to request a topic either as string topics or objects (containing string topic + params) - */ -export type WSTopicRequestOrStringTopic< - TWSTopic extends WSTopic, - TWSPayload = any, -> = WSTopicRequest | string; -⋮---- -export interface WSRequestOperationKraken< - TWSTopic extends string, - TWSParams extends object = any, -> { - // spot only - method?: WSOperation; - // futures only - event?: WSOperation; - params: - | { - channel: (TWSTopic | string | number)[]; - symbol?: string[]; - event_trigger?: string; - snapshot?: boolean; - } - | TWSParams; - req_id: number; - /** - * The following are needed for futures/derivatives requests + * Use access token instead of sign, if this is provided. + * For guidance refer to: https://github.com/tiagosiebler/kucoin-api/issues/2 */ - feed?: TWSTopic; - api_key?: string; - original_challenge?: string; - signed_challenge?: string; -} ⋮---- -// spot only +/** Default: false. If true, we'll throw errors if any params are undefined */ ⋮---- -// futures only +/** + * Optionally override API protocol + domain + * e.g baseUrl: 'https://api.kraken.com' + **/ +⋮---- +/** Default: true. whether to try and post-process request exceptions (and throw them). */ ⋮---- /** - * The following are needed for futures/derivatives requests + * Enable keep alive for REST API requests (via axios). */ ⋮---- /** - * #305: ws.terminate() is undefined in browsers. - * This only works in node.js, not in browsers. - * Does nothing if `ws` is undefined. Does nothing in browsers. - */ -export function safeTerminateWs( - ws?: WebSocket | any, - fallbackToClose?: boolean, -): boolean + * When using HTTP KeepAlive, how often to send TCP KeepAlive packets over sockets being kept alive. Default = 1000. + * Only relevant if keepAlive is set to true. + * Default: 1000 (defaults comes from https agent) + */ ⋮---- /** - * WS API promises are stored using a primary key. This key is constructed using - * properties found in every request & reply. - * - * The counterpart to this is in resolveEmittableEvents - */ -export function getPromiseRefForWSAPIRequest( - wsKey: WsKey, - requestEvent: WSAPIRequestOperationKrakenSpot, + * Allows you to provide a custom "signMessage" function, e.g. to use node's much faster createHmac method + * + * Look in the examples folder for a demonstration on using node's createHmac instead. + */ +⋮---- +export function serializeParams | undefined = {}>( + params: T, + strict_validation: boolean | undefined, + encodeValues: boolean, + prefixWith: string, + repeatArrayValuesAsKVPairs: boolean, ): string ⋮---- -/** - * Users can conveniently pass topics as strings or objects (object has topic name + optional params). - * - * This method normalises topics into objects (object has topic name + optional params). - */ -export function getNormalisedTopicRequests( - wsTopicRequests: WSTopicRequestOrStringTopic[], -): WSTopicRequest[] +// Only prefix if there's a value ⋮---- -// passed as string, convert to object +export function isEmptyObject(obj: any, acceptStringIfNotEmpty: boolean) ⋮---- -// already a normalised object, thanks to user +export function getRestBaseUrl( + restClientOptions: RestClientOptions, + restClientType: RestClientType, +): string ================ -File: src/lib/BaseWSClient.ts +File: src/types/request/derivatives.types.ts ================ -import { EventEmitter } from 'events'; -import WebSocket from 'isomorphic-ws'; -⋮---- -import { - isMessageEvent, - MessageEventLike, -} from '../types/websockets/ws-events.js'; -import { - WebsocketClientOptions, - WSClientConfigurableOptions, - WsEventInternalSrc, -} from '../types/websockets/ws-general.js'; -import { WSTopic } from '../types/websockets/ws-subscriptions.js'; -import { checkWebCryptoAPISupported } from './webCryptoAPI.js'; -import { DefaultLogger } from './websocket/logger.js'; -import { - getNormalisedTopicRequests, - safeTerminateWs, - WSOperation, - WSTopicRequest, - WSTopicRequestOrStringTopic, -} from './websocket/websocket-util.js'; -import { WsStore } from './websocket/WsStore.js'; -import { - WSConnectedResult, - WsConnectionStateEnum, -} from './websocket/WsStore.types.js'; +/** + * Order Management + */ ⋮---- -type UseTheExceptionEventInstead = never; +export interface FuturesBatchOrderSend { + order: 'send'; + order_tag: string; + orderType: + | 'lmt' + | 'post' + | 'ioc' + | 'mkt' + | 'stp' + | 'take_profit' + | 'trailing_stop' + | 'fok'; + symbol: string; + side: 'buy' | 'sell'; + size: number; + limitPrice?: number; + stopPrice?: number; + cliOrdId?: string; + triggerSignal?: 'mark' | 'index' | 'last'; + reduceOnly?: boolean; + trailingStopMaxDeviation?: number; + trailingStopDeviationUnit?: 'PERCENT' | 'QUOTE_CURRENCY'; +} ⋮---- -interface WSClientEventMap { - /** Connection opened. If this connection was previously opened and reconnected, expect the reconnected event instead */ - open: (evt: { - wsKey: WsKey; - event: any; - wsUrl: string; - ws: WebSocket; - }) => void; - - /** Reconnecting a dropped connection */ - reconnecting: (evt: { wsKey: WsKey; event: any }) => void; - - /** Successfully reconnected a connection that dropped */ - reconnected: (evt: { - wsKey: WsKey; - event: any; - wsUrl: string; - ws: WebSocket; - }) => void; - - /** Connection closed */ - close: (evt: { wsKey: WsKey; event: any }) => void; - - /** Received reply to websocket command (e.g. after subscribing to topics) */ - response: (response: any & { wsKey: WsKey }) => void; - - /** Received data for topic */ - message: (response: any & { wsKey: WsKey }) => void; - - /** Exception from ws client OR custom listeners (e.g. if you throw inside your event handler) */ - exception: (response: any & { wsKey: WsKey }) => void; - - /** - * See for more information: https://github.com/tiagosiebler/bybit-api/issues/413 - * @deprecated Use the 'exception' event instead. The 'error' event had the unintended consequence of throwing an unhandled promise rejection. - */ - error: UseTheExceptionEventInstead; - - /** Confirmation that a connection successfully authenticated */ - authenticated: (event: { wsKey: WsKey; event: any }) => void; +export interface FuturesBatchOrderEdit { + order: 'edit'; + order_id: string; + cliOrdId?: string | null; + size?: number; + limitPrice?: number; + stopPrice?: number; + trailingStopMaxDeviation?: number; + trailingStopDeviationUnit?: 'PERCENT' | 'QUOTE_CURRENCY'; + qtyMode?: 'ABSOLUTE' | 'RELATIVE'; } ⋮---- -/** Connection opened. If this connection was previously opened and reconnected, expect the reconnected event instead */ -⋮---- -/** Reconnecting a dropped connection */ -⋮---- -/** Successfully reconnected a connection that dropped */ -⋮---- -/** Connection closed */ -⋮---- -/** Received reply to websocket command (e.g. after subscribing to topics) */ -⋮---- -/** Received data for topic */ -⋮---- -/** Exception from ws client OR custom listeners (e.g. if you throw inside your event handler) */ -⋮---- -/** - * See for more information: https://github.com/tiagosiebler/bybit-api/issues/413 - * @deprecated Use the 'exception' event instead. The 'error' event had the unintended consequence of throwing an unhandled promise rejection. - */ +export interface FuturesBatchOrderCancel { + order: 'cancel'; + order_id?: string; + cliOrdId?: string; +} ⋮---- -/** Confirmation that a connection successfully authenticated */ +export interface FuturesBatchOrderParams { + ProcessBefore?: string; + json: { + batchOrder: ( + | FuturesBatchOrderSend + | FuturesBatchOrderEdit + | FuturesBatchOrderCancel + )[]; + }; +} ⋮---- -export interface EmittableEvent< - TEventType extends - keyof WSClientEventMap = keyof WSClientEventMap, -> { - eventType: - | TEventType - | 'pong' - | 'connectionReady' // tied to "requireConnectionReadyConfirmation"; - | 'connectionReadyForAuth'; // tied to specific events we need to wait for, before we can begin post-connect auth - event: Parameters[TEventType]>[0]; - isWSAPIResponse?: boolean; +export interface FuturesCancelOrderParams { + processBefore?: string; + order_id?: string; + cliOrdId?: string; } ⋮---- -| 'connectionReady' // tied to "requireConnectionReadyConfirmation"; -| 'connectionReadyForAuth'; // tied to specific events we need to wait for, before we can begin post-connect auth +export interface FuturesEditOrderParams { + processBefore?: string; + orderId?: string; + cliOrdId?: string; + size?: number; + limitPrice?: number; + stopPrice?: number; + trailingStopMaxDeviation?: number; + trailingStopDeviationUnit?: 'PERCENT' | 'QUOTE_CURRENCY'; + qtyMode?: 'ABSOLUTE' | 'RELATIVE'; +} ⋮---- -// Type safety for on and emit handlers: https://stackoverflow.com/a/61609010/880837 -export interface BaseWebsocketClient< - TWSKey extends string, - TWSRequestEvent extends object, -> { - on>( - event: U, - listener: WSClientEventMap[U], - ): this; - - emit>( - event: U, - ...args: Parameters[U]> - ): boolean; +export interface FuturesSendOrderParams { + processBefore?: string; + orderType: + | 'lmt' + | 'post' + | 'ioc' + | 'mkt' + | 'stp' + | 'take_profit' + | 'trailing_stop' + | 'fok'; + symbol: string; + side: 'buy' | 'sell'; + size: number; + limitPrice?: number; + stopPrice?: number; + cliOrdId?: string; + triggerSignal?: 'mark' | 'index' | 'last'; + reduceOnly?: boolean; + trailingStopMaxDeviation?: number; + trailingStopDeviationUnit?: 'PERCENT' | 'QUOTE_CURRENCY'; + limitPriceOffsetValue?: number; + limitPriceOffsetUnit?: 'QUOTE_CURRENCY' | 'PERCENT'; + broker?: string; } ⋮---- -on>( - event: U, - listener: WSClientEventMap[U], - ): this; +/** + * Assignment Program + */ ⋮---- -emit>( - event: U, - ...args: Parameters[U]> - ): boolean; +export interface FuturesAddAssignmentPreferenceParams { + contractType: string; + contract?: string; + maxSize?: number; + maxPosition?: number; + acceptLong: boolean; + acceptShort: boolean; + timeFrame: 'all' | 'weekdays' | 'weekends'; + enabled: boolean; +} ⋮---- /** - * A midflight WS request event (e.g. subscribe to these topics). - * - * - requestKey: unique identifier for this request, if available. Can be anything as a string. - * - requestEvent: the raw request, as an object, that will be sent on the ws connection. This may contain multiple topics/requests in one object, if the exchange supports it. + * Trading Settings */ -export interface MidflightWsRequestEvent { - requestKey: string | number; - requestEvent: TEvent; +⋮---- +export interface FuturesUpdateSelfTradeStrategyParams { + strategy: + | 'REJECT_TAKER' + | 'CANCEL_MAKER_SELF' + | 'CANCEL_MAKER_CHILD' + | 'CANCEL_MAKER_ANY'; } ⋮---- /** - * Appends wsKey and isWSAPIResponse to all events. - * Some events are arrays, this handles that nested scenario too. + * Transfers */ -function getFinalEmittable( - emittable: EmittableEvent | EmittableEvent[], - wsKey: any, - isWSAPIResponse?: boolean, -): any -⋮---- -// Some topics just emit an array. -// This is consistent with how it was before the WS API upgrade: ⋮---- -// const { event, ...others } = emittable; -// return { -// ...others, -// event: event.map((subEvent) => -// getFinalEmittable(subEvent, wsKey, isWSAPIResponse), -// ), -// }; +export interface FuturesInitiateWalletTransferParams { + fromAccount: string; + toAccount: string; + unit: string; + amount: number; +} ⋮---- -// eslint-disable-next-line @typescript-eslint/no-unsafe-declaration-merging -export abstract class BaseWebsocketClient< -TWSKey extends string, +export interface FuturesInitiateSubaccountTransferParams { + fromUser: string; + toUser: string; + fromAccount: string; + toAccount: string; + unit: string; + amount: string; +} ⋮---- -constructor( - options?: WSClientConfigurableOptions & { wsLoggerCategory: string }, - logger?: DefaultLogger, -) +export interface FuturesSubmitToSpotParams { + currency: string; + amount: string; + sourceWallet?: string; +} ⋮---- -// Requires a confirmation "response" from the ws connection before assuming it is ready +/** + * Account History + */ ⋮---- -// Automatically auth after opening a connection? +export interface FuturesHistoryBaseParams { + since?: number; // Timestamp in milliseconds + before?: number; // Timestamp in milliseconds + sort?: 'asc' | 'desc'; + continuation_token?: string; // base64 + count?: number; + tradeable?: string; +} ⋮---- -// Automatically include auth/sign/token with every WS request. -// Automatically handled during getWsRequestEvents. +since?: number; // Timestamp in milliseconds +before?: number; // Timestamp in milliseconds ⋮---- -// Automatically re-auth WS API, if we were auth'd before and get reconnected +continuation_token?: string; // base64 ⋮---- -// Whether to use native heartbeats (depends on the exchange) +export interface FuturesGetOrderEventsParams extends FuturesHistoryBaseParams { + opened?: boolean; + closed?: boolean; +} ⋮---- -// Check Web Crypto API support when credentials are provided and no custom sign function is used +export interface FuturesGetTriggerEventsParams + extends FuturesHistoryBaseParams { + opened?: boolean; + closed?: boolean; +} ⋮---- -/** - * Return true if this wsKey connection should automatically authenticate immediately after connecting - */ -protected abstract isAuthOnConnectWsKey(wsKey: TWSKey): boolean; +export interface FuturesGetPositionEventsParams + extends FuturesHistoryBaseParams { + opened?: boolean; + closed?: boolean; + increased?: boolean; + decreased?: boolean; + reversed?: boolean; + no_change?: boolean; + trades?: boolean; + funding_realization?: boolean; + settlement?: boolean; +} ⋮---- -protected abstract isCustomReconnectionNeeded(wsKey: TWSKey): boolean; +export interface FuturesGetAccountLogParams { + since?: number; // Timestamp in milliseconds + before?: number; // Timestamp in milliseconds + from?: number; // ID of the first entry (inclusive) + to?: number; // ID of the last entry (inclusive) + sort?: 'asc' | 'desc'; + info?: string[]; // Types of entry to filter by + count?: number; + conversion_details?: boolean; +} ⋮---- -protected abstract triggerCustomReconnectionWorkflow( - wsKey: TWSKey, - ): Promise; +since?: number; // Timestamp in milliseconds +before?: number; // Timestamp in milliseconds +from?: number; // ID of the first entry (inclusive) +to?: number; // ID of the last entry (inclusive) ⋮---- -protected abstract sendPingEvent(wsKey: TWSKey, ws: WebSocket): void; +info?: string[]; // Types of entry to filter by ⋮---- -protected abstract sendPongEvent(wsKey: TWSKey, ws: WebSocket): void; +/** + * Market History + */ ⋮---- -protected abstract isWsPing(data: any): boolean; +export interface FuturesMarketHistoryBaseParams { + tradeable: string; // Symbol of the contract + since?: number; // Timestamp in milliseconds + before?: number; // Timestamp in milliseconds + sort?: 'asc' | 'desc'; + continuation_token?: string; // base64 + count?: number; +} ⋮---- -protected abstract isWsPong(data: any): boolean; +tradeable: string; // Symbol of the contract +since?: number; // Timestamp in milliseconds +before?: number; // Timestamp in milliseconds ⋮---- -protected abstract authPrivateConnectionsOnConnect(_wsKey: TWSKey): boolean; +continuation_token?: string; // base64 ⋮---- /** - * Return the event sent to the server to trigger authentication. If the event requires waiting for another event first (e.g. a challenge), return 'waitForEvent' and the library will wait for that event before calling this method again. - * - * Usually only called once per connection, unless the connection drops/is reset. - */ -protected abstract getWsAuthRequestEvent( - wsKey: TWSKey, - eventToAuth?: object, - ): Promise; + * Charts - Candles + */ ⋮---- -protected abstract isPrivateTopicRequest( - request: WSTopicRequest, - wsKey: TWSKey, - ): boolean; +export interface FuturesGetCandlesParams { + tickType: 'spot' | 'mark' | 'trade'; + symbol: string; + resolution: '1m' | '5m' | '15m' | '30m' | '1h' | '4h' | '12h' | '1d' | '1w'; + from?: number; // From date in epoch seconds + to?: number; // To date in epoch seconds + count?: number; // Number of candles to return +} +⋮---- +from?: number; // From date in epoch seconds +to?: number; // To date in epoch seconds +count?: number; // Number of candles to return ⋮---- /** - * Returns a list of string events that can be individually sent upstream to complete subscribing/unsubscribing/etc to these topics - */ -// protected abstract getWsOperationEventsForTopics( -// topics: WsTopicRequest[], -// wsKey: TWSKey, -// operation: WsOperation, -// ): Promise; + * Charts - Analytics + */ ⋮---- -protected abstract getPrivateWSKeys(): TWSKey[]; +export interface FuturesGetAnalyticsParams { + symbol: string; + analyticsType: string; + since: number; // Epoch time in seconds (required) + interval: 60 | 300 | 900 | 1800 | 3600 | 14400 | 43200 | 86400 | 604800; // Resolution in seconds (required) + to?: number; // Epoch time in seconds, default now +} ⋮---- -protected abstract getWsUrl(wsKey: TWSKey): Promise; +since: number; // Epoch time in seconds (required) +interval: 60 | 300 | 900 | 1800 | 3600 | 14400 | 43200 | 86400 | 604800; // Resolution in seconds (required) +to?: number; // Epoch time in seconds, default now + +================ +File: src/types/websockets/ws-general.ts +================ +import { AxiosRequestConfig } from 'axios'; +import type { ClientRequestArgs } from 'http'; +import WebSocket from 'isomorphic-ws'; ⋮---- -protected abstract getMaxTopicsPerSubscribeEvent( - wsKey: TWSKey, - ): number | null; +import { RestClientOptions } from '../../lib/requestUtils.js'; ⋮---- -/** - * @returns one or more correctly structured request events for performing a operations over WS. This can vary per exchange spec. +/** General configuration for the WebsocketClient */ +export interface WSClientConfigurableOptions { + /** Your API key */ + apiKey?: string; + + /** Your API secret */ + apiSecret?: string; + + /** + * Set to `true` to connect to testnet (Kraken's demo environment). The live environment is used by default. + * + * Note: as of November 2025, only the derivatives environment supports testnet connections. Kraken refer to this as the "Demo" environment, but it is effectively a testnet. + * This is a place to test your API integration. It is not a good place to test strategy performance, as the liquidity and orderbook dynamics are very different to the live environment. + * + * Refer to the following for more information: + * https://github.com/tiagosiebler/awesome-crypto-examples/wiki/CEX-Testnets */ -protected abstract getWsRequestEvents( - wsKey: TWSKey, - operation: WSOperation, - requests: WSTopicRequest[], - ): Promise[]>; -⋮---- -/** - * Abstraction called to sort ws events into emittable event types (response to a request, data update, etc) + testnet?: boolean; + + /** Define a recv window when preparing a private websocket signature. This is in milliseconds, so 5000 == 5 seconds */ + recvWindow?: number; + + /** How often to check if the connection is alive */ + pingInterval?: number; + + /** How long to wait for a pong (heartbeat reply) before assuming the connection is dead */ + pongTimeout?: number; + + /** Delay in milliseconds before respawning the connection */ + reconnectTimeout?: number; + + restOptions?: RestClientOptions; + requestOptions?: AxiosRequestConfig; + + wsOptions?: { + protocols?: string[]; + agent?: any; + } & Partial; + + wsUrl?: string; + + /** + * Allows you to provide a custom "signMessage" function, e.g. to use node's much faster createHmac method + * + * Look in the examples folder for a demonstration on using node's createHmac instead. */ -protected abstract resolveEmittableEvents( - wsKey: TWSKey, - event: MessageEventLike, - ): EmittableEvent[]; -⋮---- -/** - * Request connection of all dependent (public & private) websockets, instead of waiting for automatic connection by library + customSignMessageFn?: (message: string, secret: string) => Promise; + + /** + * If you authenticated the WS API before, automatically try to re-authenticate the WS API if you're disconnected/reconnected for any reason. */ -protected abstract connectAll(): Promise[]; -⋮---- -protected isPrivateWsKey(wsKey: TWSKey): boolean -⋮---- -/** Returns auto-incrementing request ID, used to track promise references for async requests */ -protected getNewRequestId(): number -⋮---- -protected abstract sendWSAPIRequest( - wsKey: TWSKey, - operation: string, - params?: any, - ): Promise; -⋮---- -protected abstract sendWSAPIRequest( - wsKey: TWSKey, - channel: string, - params: any, - ): Promise; + reauthWSAPIOnReconnect?: boolean; +} ⋮---- -public getTimeOffsetMs() +/** Your API key */ ⋮---- -public setTimeOffsetMs(newOffset: number) +/** Your API secret */ ⋮---- /** - * Don't call directly! Use subscribe() instead! - * - * Subscribe to one or more topics on a WS connection (identified by WS Key). + * Set to `true` to connect to testnet (Kraken's demo environment). The live environment is used by default. * - * - Topics are automatically cached - * - Connections are automatically opened, if not yet connected - * - Authentication is automatically handled - * - Topics are automatically resubscribed to, if something happens to the connection, unless you call unsubsribeTopicsForWsKey(topics, key). + * Note: as of November 2025, only the derivatives environment supports testnet connections. Kraken refer to this as the "Demo" environment, but it is effectively a testnet. + * This is a place to test your API integration. It is not a good place to test strategy performance, as the liquidity and orderbook dynamics are very different to the live environment. * - * @param wsTopicRequests array of topics to subscribe to - * @param wsKey ws key referring to the ws connection these topics should be subscribed on + * Refer to the following for more information: + * https://github.com/tiagosiebler/awesome-crypto-examples/wiki/CEX-Testnets */ -protected async subscribeTopicsForWsKey( - wsTopicRequests: WSTopicRequestOrStringTopic[], - wsKey: TWSKey, -) ⋮---- -// Store topics, so future automation (post-auth, post-reconnect) has everything needed to resubscribe automatically -⋮---- -// start connection process if it hasn't yet begun. Topics are automatically subscribed to on-connect +/** Define a recv window when preparing a private websocket signature. This is in milliseconds, so 5000 == 5 seconds */ ⋮---- -// Subscribe should happen automatically once connected, nothing to do here after topics are added to wsStore. +/** How often to check if the connection is alive */ ⋮---- -/** - * Are we in the process of connection? Nothing to send yet. - */ +/** How long to wait for a pong (heartbeat reply) before assuming the connection is dead */ ⋮---- -// We're connected. Check if auth is needed and if already authenticated +/** Delay in milliseconds before respawning the connection */ ⋮---- /** - * If not authenticated yet and auth is required, don't request topics yet. - * - * Auth should already automatically be in progress, so no action needed from here. Topics will automatically subscribe post-auth success. - */ -⋮---- -// Finally, request subscription to topics if the connection is healthy and ready -⋮---- -protected async unsubscribeTopicsForWsKey( - wsTopicRequests: WSTopicRequestOrStringTopic[], - wsKey: TWSKey, -): Promise -⋮---- -// Store topics, so future automation (post-auth, post-reconnect) has everything needed to resubscribe automatically -⋮---- -// If not connected, don't need to do anything. -// Removing the topic from the store is enough to stop it from being resubscribed to on reconnect. + * Allows you to provide a custom "signMessage" function, e.g. to use node's much faster createHmac method + * + * Look in the examples folder for a demonstration on using node's createHmac instead. + */ ⋮---- -// We're connected. Check if auth is needed and if already authenticated +/** + * If you authenticated the WS API before, automatically try to re-authenticate the WS API if you're disconnected/reconnected for any reason. + */ ⋮---- /** - * If not authenticated yet and auth is required, don't need to do anything. - * We don't subscribe to topics until auth is complete anyway. - */ -⋮---- -// Finally, request subscription to topics if the connection is healthy and ready -⋮---- -/** - * Splits topic requests into two groups, public & private topic requests + * WS configuration that's always defined, regardless of user configuration + * (usually comes from defaults if there's no user-provided values) + */ +export interface WebsocketClientOptions extends WSClientConfigurableOptions { + pingInterval: number; + pongTimeout: number; + reconnectTimeout: number; + recvWindow: number; + + /** + * If true, require a "receipt" that the connection is ready for use (e.g. a specific event type) */ -private sortTopicRequestsIntoPublicPrivate( - wsTopicRequests: WSTopicRequest[], - wsKey: TWSKey, -): -⋮---- -/** Get the WsStore that tracks websockets & topics */ -public getWsStore(): WsStore> -⋮---- -public close(wsKey: TWSKey, force?: boolean) -⋮---- -public closeAll(force?: boolean) -⋮---- -public isConnected(wsKey: TWSKey): boolean + requireConnectionReadyConfirmation: boolean; + authPrivateConnectionsOnConnect: boolean; + authPrivateRequests: boolean; + reauthWSAPIOnReconnect: boolean; + + /** + * Whether to use native WebSocket ping/pong frames for heartbeats + */ + useNativeHeartbeats: boolean; +} ⋮---- /** - * Request connection to a specific websocket, instead of waiting for automatic connection. + * If true, require a "receipt" that the connection is ready for use (e.g. a specific event type) */ -public async connect( - wsKey: TWSKey, - customUrl?: string | undefined, - throwOnError?: boolean, -): Promise -⋮---- -// Important: don't check for RECONNECTING here, or this clashes with reconnectWithDelay()! -⋮---- -private connectToWsUrl(url: string, wsKey: TWSKey): WebSocket -⋮---- -// -⋮---- -private parseWsError(context: string, error: any, wsKey: TWSKey): boolean -⋮---- -// Allow retry by default (in some places that call this). Prevent deadloop in hard failure (401) -⋮---- -/** Get a signature, build the auth request and send it */ -private async sendAuthRequest( - wsKey: TWSKey, - eventToAuth?: object, -): Promise -⋮---- -// If not required, this won't return anything -⋮---- -// Short-circuit this for the next time it's called -⋮---- -private reconnectWithDelay(wsKey: TWSKey, connectionDelayMs: number) -⋮---- -// Some streams need a specialist reconnection workflow. -// E.g. the user data stream can't just be reconnected as is. -⋮---- -private ping(wsKey: TWSKey) ⋮---- /** - * Closes a connection, if it's even open. If open, this will trigger a reconnect asynchronously. - * If closed, trigger a reconnect immediately + * Whether to use native WebSocket ping/pong frames for heartbeats */ -protected executeReconnectableClose(wsKey: TWSKey, reason: string) ⋮---- -private clearTimers(wsKey: TWSKey) -⋮---- -// Send a ping at intervals -private clearPingTimer(wsKey: TWSKey) -⋮---- -// Expect a pong within a time limit -private clearPongTimer(wsKey: TWSKey) +export type WsMarket = 'spot' | 'futures'; ⋮---- -// this.logger.trace(`Cleared pong timeout for "${wsKey}"`); +export type WsEventInternalSrc = 'event' | 'function' | 'frame'; + +================ +File: src/PartnerClient.ts +================ +import { BaseRestClient } from './lib/BaseRestClient.js'; +import { REST_CLIENT_TYPE_ENUM, RestClientType } from './lib/requestUtils.js'; +import { + PartnerCancelCustomOrderParams, + PartnerCreateCustomOrderParams, + PartnerCreateUserParams, + PartnerExecuteQuoteParams, + PartnerGetAssetParams, + PartnerGetCustomOrderParams, + PartnerGetEarnSummaryParams, + PartnerGetPortfolioHistoryParams, + PartnerGetPortfolioSummaryParams, + PartnerGetQuoteLimitsParams, + PartnerGetQuoteParams, + PartnerGetRampCheckoutUrlParams, + PartnerGetRampLimitsParams, + PartnerGetRampProspectiveQuoteParams, + PartnerGetSettlementReportParams, + PartnerListAssetRatesParams, + PartnerListAssetsParams, + PartnerListCustomOrdersParams, + PartnerListEarnAssetsParams, + PartnerListFundingTransactionsParams, + PartnerListPortfolioDetailsParams, + PartnerListPortfolioTransactionsParams, + PartnerListSettlementReportsParams, + PartnerRequestProspectiveQuoteParams, + PartnerRequestQuoteParams, + PartnerSubmitVerificationParams, + PartnerToggleAutoEarnParams, + PartnerUpdateUserParams, + PartnerWithdrawFundsParams, +} from './types/request/partner.types.js'; +import { + PartnerCancelCustomOrderResponse, + PartnerCreateCustomOrderResponse, + PartnerCreateUserResponse, + PartnerExecuteQuoteResponse, + PartnerGetAssetResponse, + PartnerGetCustomOrderResponse, + PartnerGetEarnSummaryResponse, + PartnerGetPortfolioHistoryResponse, + PartnerGetPortfolioSummaryResponse, + PartnerGetQuoteLimitsResponse, + PartnerGetQuoteResponse, + PartnerGetRampCheckoutUrlResponse, + PartnerGetRampLimitsResponse, + PartnerGetRampProspectiveQuoteResponse, + PartnerGetSettlementReportResponse, + PartnerGetUserResponse, + PartnerListAssetRatesResponse, + PartnerListAssetsResponse, + PartnerListCustomOrdersResponse, + PartnerListEarnAssetsResponse, + PartnerListFundingTransactionsResponse, + PartnerListPortfolioDetailsResponse, + PartnerListPortfolioTransactionsResponse, + PartnerListRampBuyCryptoAssetsResponse, + PartnerListRampCountriesResponse, + PartnerListRampFiatCurrenciesResponse, + PartnerListRampPaymentMethodsResponse, + PartnerListSettlementReportsResponse, + PartnerRequestProspectiveQuoteResponse, + PartnerRequestQuoteResponse, + PartnerSubmitVerificationResponse, + PartnerToggleAutoEarnResponse, + PartnerUpdateUserResponse, + PartnerWithdrawFundsResponse, +} from './types/response/partner.types.js'; ⋮---- -// this.logger.trace(`No active pong timer for "${wsKey}"`); +/** + * The PartnerClient provides integration to the Kraken Partner API. + * + * Docs: + * - https://docs.kraken.com/api/docs/embed-api + * - https://docs.kraken.com/api/docs/ramp-api + */ +export class PartnerClient extends BaseRestClient ⋮---- -private clearReconnectTimer(wsKey: TWSKey) +getClientType(): RestClientType ⋮---- /** - * Returns a list of string events that can be individually sent upstream to complete subscribing/unsubscribing/etc to these topics * - * If events are an object, these should be stringified (`return JSON.stringify(event);`) - * Each event returned by this will be sent one at a time + * Partner REST API - Embed API - Users * - * Events are automatically split into smaller batches, by this method, if needed. */ -protected async getWsOperationEventsForTopics( - topics: WSTopicRequest[], - wsKey: TWSKey, - operation: WSOperation, -): Promise[]> -⋮---- -// Events that are ready to send (usually stringified JSON) ⋮---- /** - * Simply builds and sends subscribe events for a list of topics for a ws key + * Create User * - * @private Use the `subscribe(topics)` or `subscribeTopicsForWsKey(topics, wsKey)` method to subscribe to topics. Send WS message to subscribe to topics. + * Create a new user in the Kraken system. */ -private async requestSubscribeTopics( - wsKey: TWSKey, - wsTopicRequests: WSTopicRequest[], -) -⋮---- -// Automatically splits requests into smaller batches, if needed -⋮---- -`Subscribing to ${wsTopicRequests.length} "${wsKey}" topics in ${subscribeWsMessages.length} batches.`, // Events: "${JSON.stringify(topics)}" -⋮---- -// eslint-disable-next-line @typescript-eslint/no-unused-vars +createEmbedUser( + params: PartnerCreateUserParams, +): Promise ⋮---- /** - * Simply builds and sends unsubscribe events for a list of topics for a ws key + * Get User * - * @private Use the `unsubscribe(topics)` method to unsubscribe from topics. Send WS message to unsubscribe from topics. + * Get a previously created user. */ -private async requestUnsubscribeTopics( - wsKey: TWSKey, - wsTopicRequests: WSTopicRequest[], -) -⋮---- -// eslint-disable-next-line @typescript-eslint/no-unused-vars +getEmbedUser(params: ⋮---- /** - * Try sending a string event on a WS connection (identified by the WS Key) + * Update User + * + * Update an existing user's profile. */ -public tryWsSend( - wsKey: TWSKey, - wsMessage: string, - throwExceptions?: boolean, -) -⋮---- -private async onWsOpen( - event: WebSocket.Event, - wsKey: TWSKey, - url: string, - ws: WebSocket, -) -⋮---- -private resolveConnectionInProgressPromise(wsKey: TWSKey) -⋮---- -// Resolve & cleanup deferred "connection attempt in progress" promise +updateEmbedUser( + params: PartnerUpdateUserParams, +): Promise ⋮---- /** - * Called automatically once a connection is ready. - * - Some exchanges are ready immediately after the connections open. - * - Some exchanges send an event to confirm the connection is ready for us. * - * This method is called to act when the connection is ready. Use `requireConnectionReadyConfirmation` to control how this is called. + * Partner REST API - Embed API - Verifications + * */ -private async onWsReadyForEvents(wsKey: TWSKey) -⋮---- -// Some websockets require an auth packet to be sent after opening the connection -⋮---- -// Reconnect to topics known before it connected -⋮---- -// Request sub to public topics, if any -⋮---- -// Request sub to private topics, if auth on connect isn't needed ⋮---- /** - * Handle subscription to private topics _after_ authentication successfully completes asynchronously. + * Submit Verification * - * Only used for exchanges that require auth before sending private topic subscription requests - */ -private onWsAuthenticated( - wsKey: TWSKey, - event: { isWSAPI?: boolean; WSAPIAuthChannel?: string }, -) -⋮---- -// Resolve & cleanup deferred "auth attempt in progress" promise -⋮---- -// Remove before continuing, in case there's more requests queued -⋮---- -private onWsPing( - event: any, - wsKey: TWSKey, - ws: WebSocket, - source: WsEventInternalSrc, -) -⋮---- -private onWsPong(event: any, wsKey: TWSKey, source: WsEventInternalSrc) -⋮---- -// Necessary when native heartbeats are used -⋮---- -private onWsMessage(event: unknown, wsKey: TWSKey, ws: WebSocket) -⋮---- -// console.log('onMessageRaw: ', (event as any).data); -// any message can clear the pong timer - wouldn't get a message if the ws wasn't working -⋮---- -// console.log(`raw event: `, { data, dataType, emittableEvents }); -⋮---- -// Not used for kraken. At least for spot, auth is included per req during subscribe -⋮---- -// Not used for kraken. At least for spot, auth is included per req during subscribe -⋮---- -// Other event types are automatically emitted here -⋮---- -// this.logger.trace( -// `onWsMessage().emit(${emittable.eventType}).done()`, -// emittableFinalEvent, -// ); -⋮---- -private onWsClose(event: unknown, wsKey: TWSKey) -⋮---- -// unintentional close, attempt recovery -⋮---- -// clean up any pending promises for this connection -⋮---- -// this.clearTopicsPendingSubscriptions(wsKey, true, 'WS Closed'); -⋮---- -// intentional close - clean up -// clean up any pending promises for this connection -⋮---- -// This was an intentional close, delete all state for this connection, as if it never existed: -⋮---- -private getWs(wsKey: TWSKey) -⋮---- -private setWsState(wsKey: TWSKey, state: WsConnectionStateEnum) + * Submit a verification for a user with documents and details. + * A verification is defined as a check that has been performed on a user to verify information provided by the user. + * Note: This endpoint uses multipart/form-data for file uploads. + */ +submitEmbedVerification( + params: PartnerSubmitVerificationParams, +): Promise ⋮---- /** - * Promise-driven method to assert that a ws has successfully connected (will await until connection is open) + * + * Partner REST API - Embed API - Assets + * */ -protected async assertIsConnected(wsKey: TWSKey): Promise -⋮---- -// Already in progress? Await shared promise and retry -⋮---- -// Start connection, it should automatically store/return a promise. ⋮---- /** - * Promise-driven method to assert that a ws has been successfully authenticated (will await until auth is confirmed) + * List Assets + * + * List all assets available on the platform. + * This endpoint returns a list of all assets available on the platform. */ -public async assertIsAuthenticated(wsKey: TWSKey): Promise -⋮---- -// Already in progress? Await shared promise and retry +listEmbedAssets( + params?: PartnerListAssetsParams, +): Promise ⋮---- -// Start authentication, it should automatically store/return a promise. - -================ -File: src/lib/requestUtils.ts -================ /** - * Used to switch how authentication/requests work under the hood - */ -⋮---- -/** Spot */ -⋮---- -/** Futures */ -⋮---- -/** Futures Demo */ -⋮---- -/** Institutional */ -⋮---- -/** Partner */ + * Get Asset + * + * Get information about a specific asset. + */ +getEmbedAsset( + params: PartnerGetAssetParams, +): Promise ⋮---- -export type RestClientType = - (typeof REST_CLIENT_TYPE_ENUM)[keyof typeof REST_CLIENT_TYPE_ENUM]; +/** + * List Asset Rates + * + * Returns historical rates for a given asset. + * This endpoint returns historical rates for a given asset with timestamp and median price for each period. + */ +listEmbedAssetRates( + params: PartnerListAssetRatesParams, +): Promise ⋮---- -export interface RestClientOptions { - /** Your API key */ - apiKey?: string; - - /** Your API secret */ - apiSecret?: string; - - /** - * Set to `true` to connect to testnet (Kraken's demo environment). The live environment is used by default. +/** * - * Note: as of November 2025, only the DerivativesClient supports testnet connections. Kraken refer to this as the "Demo" environment, but it is effectively a testnet. - * This is a place to test your API integration. It is not a good place to test strategy performance, as the liquidity and orderbook dynamics are very different to the live environment. + * Partner REST API - Embed API - Quotes * - * Refer to the following for more information: - * https://github.com/tiagosiebler/awesome-crypto-examples/wiki/CEX-Testnets - */ - testnet?: boolean; - - /** - * Use access token instead of sign, if this is provided. - * For guidance refer to: https://github.com/tiagosiebler/kucoin-api/issues/2 - */ - apiAccessToken?: string; - - /** Default: false. If true, we'll throw errors if any params are undefined */ - strictParamValidation?: boolean; - - /** - * Optionally override API protocol + domain - * e.g baseUrl: 'https://api.kraken.com' - **/ - baseUrl?: string; - - /** Default: true. whether to try and post-process request exceptions (and throw them). */ - parseExceptions?: boolean; - - customTimestampFn?: () => number; - - /** - * Enable keep alive for REST API requests (via axios). - */ - keepAlive?: boolean; - - /** - * When using HTTP KeepAlive, how often to send TCP KeepAlive packets over sockets being kept alive. Default = 1000. - * Only relevant if keepAlive is set to true. - * Default: 1000 (defaults comes from https agent) */ - keepAliveMsecs?: number; - - /** - * Allows you to provide a custom "signMessage" function, e.g. to use node's much faster createHmac method +⋮---- +/** + * Request Quote * - * Look in the examples folder for a demonstration on using node's createHmac instead. + * Request a price quote for an asset, that may be used to execute a trade later on. */ - customSignMessageFn?: (message: string, secret: string) => Promise; -} -⋮---- -/** Your API key */ -⋮---- -/** Your API secret */ +requestEmbedQuote( + params: PartnerRequestQuoteParams, +): Promise ⋮---- /** - * Set to `true` to connect to testnet (Kraken's demo environment). The live environment is used by default. + * Get Quote * - * Note: as of November 2025, only the DerivativesClient supports testnet connections. Kraken refer to this as the "Demo" environment, but it is effectively a testnet. - * This is a place to test your API integration. It is not a good place to test strategy performance, as the liquidity and orderbook dynamics are very different to the live environment. + * Gets the status of a quote that was previously requested. + */ +getEmbedQuote( + params: PartnerGetQuoteParams, +): Promise +⋮---- +/** + * Execute Quote * - * Refer to the following for more information: - * https://github.com/tiagosiebler/awesome-crypto-examples/wiki/CEX-Testnets + * Executes a quote that was previously requested. */ +executeEmbedQuote( + params: PartnerExecuteQuoteParams, +): Promise ⋮---- /** - * Use access token instead of sign, if this is provided. - * For guidance refer to: https://github.com/tiagosiebler/kucoin-api/issues/2 + * Get Quote Limits (RFQ) + * + * Request minimum, maximum and precision for trade using a given asset pair. */ +getEmbedQuoteLimits( + params: PartnerGetQuoteLimitsParams, +): Promise ⋮---- -/** Default: false. If true, we'll throw errors if any params are undefined */ +/** + * Request Prospective Quote (RFQ) + * + * Request a prospective quote for an asset pair, to receive an indicative price and fee. + */ +requestEmbedProspectiveQuote( + params: PartnerRequestProspectiveQuoteParams, +): Promise ⋮---- /** - * Optionally override API protocol + domain - * e.g baseUrl: 'https://api.kraken.com' - **/ + * + * Partner REST API - Embed API - Custom Orders + * + */ ⋮---- -/** Default: true. whether to try and post-process request exceptions (and throw them). */ +/** + * Create Custom Order + * + * Submit a custom order with a specified trigger condition (e.g. price-triggered). + */ +createEmbedCustomOrder( + params: PartnerCreateCustomOrderParams, +): Promise ⋮---- /** - * Enable keep alive for REST API requests (via axios). + * List Custom Orders + * + * Get a list of custom orders that were previously submitted. */ +listEmbedCustomOrders( + params: PartnerListCustomOrdersParams, +): Promise ⋮---- /** - * When using HTTP KeepAlive, how often to send TCP KeepAlive packets over sockets being kept alive. Default = 1000. - * Only relevant if keepAlive is set to true. - * Default: 1000 (defaults comes from https agent) + * Get Custom Order + * + * Get a single custom order by ID. */ +getEmbedCustomOrder( + params: PartnerGetCustomOrderParams, +): Promise ⋮---- /** - * Allows you to provide a custom "signMessage" function, e.g. to use node's much faster createHmac method + * Cancel Custom Order * - * Look in the examples folder for a demonstration on using node's createHmac instead. + * Cancels a custom order that was previously submitted but not yet completed. */ +cancelEmbedCustomOrder( + params: PartnerCancelCustomOrderParams, +): Promise ⋮---- -export function serializeParams | undefined = {}>( - params: T, - strict_validation: boolean | undefined, - encodeValues: boolean, - prefixWith: string, - repeatArrayValuesAsKVPairs: boolean, -): string +/** + * + * Partner REST API - Embed API - Portfolios + * + */ ⋮---- -// Only prefix if there's a value +/** + * Get Portfolio Summary + * + * Get the portfolio summary for a user. + */ +getEmbedPortfolioSummary( + params: PartnerGetPortfolioSummaryParams, +): Promise ⋮---- -export function isEmptyObject(obj: any, acceptStringIfNotEmpty: boolean) +/** + * Get Portfolio History + * + * Gets a portfolio's historical balances and valuations over time. + * Note: Balance for the last day shows up at UTC + 5h due to processing times. + */ +getEmbedPortfolioHistory( + params: PartnerGetPortfolioHistoryParams, +): Promise ⋮---- -export function getRestBaseUrl( - restClientOptions: RestClientOptions, - restClientType: RestClientType, -): string - -================ -File: src/types/websockets/ws-general.ts -================ -import { AxiosRequestConfig } from 'axios'; -import type { ClientRequestArgs } from 'http'; -import WebSocket from 'isomorphic-ws'; +/** + * List Portfolio Details + * + * Lists owned assets in a user's portfolio. + */ +listEmbedPortfolioDetails( + params: PartnerListPortfolioDetailsParams, +): Promise ⋮---- -import { RestClientOptions } from '../../lib/requestUtils.js'; +/** + * List Portfolio Transactions + * + * Lists the user's trades and transactions. + */ +listEmbedPortfolioTransactions( + params: PartnerListPortfolioTransactionsParams, +): Promise ⋮---- -/** General configuration for the WebsocketClient */ -export interface WSClientConfigurableOptions { - /** Your API key */ - apiKey?: string; - - /** Your API secret */ - apiSecret?: string; - - /** - * Set to `true` to connect to testnet (Kraken's demo environment). The live environment is used by default. +/** * - * Note: as of November 2025, only the derivatives environment supports testnet connections. Kraken refer to this as the "Demo" environment, but it is effectively a testnet. - * This is a place to test your API integration. It is not a good place to test strategy performance, as the liquidity and orderbook dynamics are very different to the live environment. + * Partner REST API - Embed API - Earn * - * Refer to the following for more information: - * https://github.com/tiagosiebler/awesome-crypto-examples/wiki/CEX-Testnets */ - testnet?: boolean; - - /** Define a recv window when preparing a private websocket signature. This is in milliseconds, so 5000 == 5 seconds */ - recvWindow?: number; - - /** How often to check if the connection is alive */ - pingInterval?: number; - - /** How long to wait for a pong (heartbeat reply) before assuming the connection is dead */ - pongTimeout?: number; - - /** Delay in milliseconds before respawning the connection */ - reconnectTimeout?: number; - - restOptions?: RestClientOptions; - requestOptions?: AxiosRequestConfig; - - wsOptions?: { - protocols?: string[]; - agent?: any; - } & Partial; - - wsUrl?: string; - - /** - * Allows you to provide a custom "signMessage" function, e.g. to use node's much faster createHmac method +⋮---- +/** + * Get Earn Summary * - * Look in the examples folder for a demonstration on using node's createHmac instead. - */ - customSignMessageFn?: (message: string, secret: string) => Promise; - - /** - * If you authenticated the WS API before, automatically try to re-authenticate the WS API if you're disconnected/reconnected for any reason. + * Get Earn summary of a user. + * Response holds total amounts (all-time). For per-asset granularity, use listEarnAssets(). */ - reauthWSAPIOnReconnect?: boolean; -} +getEmbedEarnSummary( + params: PartnerGetEarnSummaryParams, +): Promise ⋮---- -/** Your API key */ +/** + * List Earn Assets + * + * List Earn Assets. + * The user can optionally be passed in the request, which shows active asset allocations of the user in the response. + */ +listEmbedEarnAssets( + params?: PartnerListEarnAssetsParams, +): Promise ⋮---- -/** Your API secret */ +/** + * Toggle Auto-Earn + * + * Toggle Auto-Earn of a user. + * Toggling Auto-Earn is an async operation. The response is empty on success. + * To fetch the user's current Auto-Earn status, use getEarnSummary(). + */ +toggleEmbedAutoEarn( + params: PartnerToggleAutoEarnParams, +): Promise ⋮---- /** - * Set to `true` to connect to testnet (Kraken's demo environment). The live environment is used by default. * - * Note: as of November 2025, only the derivatives environment supports testnet connections. Kraken refer to this as the "Demo" environment, but it is effectively a testnet. - * This is a place to test your API integration. It is not a good place to test strategy performance, as the liquidity and orderbook dynamics are very different to the live environment. + * Partner REST API - Embed API - Transfers * - * Refer to the following for more information: - * https://github.com/tiagosiebler/awesome-crypto-examples/wiki/CEX-Testnets */ ⋮---- -/** Define a recv window when preparing a private websocket signature. This is in milliseconds, so 5000 == 5 seconds */ +/** + * Withdraw Funds + * + * Withdraw funds. + * Note: Currently, this is a master-only operation. No User parameter exists. + */ +withdrawEmbedFunds( + params: PartnerWithdrawFundsParams, +): Promise ⋮---- -/** How often to check if the connection is alive */ +/** + * List Funding Transactions + * + * List Funding transactions. + * Funding transactions can be of type withdrawal or deposit. + * Note: Currently, this is a master-only operation. No User parameter exists. + */ +listEmbedFundingTransactions( + params: PartnerListFundingTransactionsParams, +): Promise ⋮---- -/** How long to wait for a pong (heartbeat reply) before assuming the connection is dead */ +/** + * + * Partner REST API - Embed API - Reports + * + */ ⋮---- -/** Delay in milliseconds before respawning the connection */ +/** + * List Settlement Reports + * + * Retrieves a paginated list of settlement reports available to the authenticated master user, + * with optional filters for date range and report type. + */ +listEmbedSettlementReports( + params?: PartnerListSettlementReportsParams, +): Promise ⋮---- /** - * Allows you to provide a custom "signMessage" function, e.g. to use node's much faster createHmac method + * Get Settlement Report * - * Look in the examples folder for a demonstration on using node's createHmac instead. + * Retrieves a settlement report and provides a secure download URL for the authenticated master user. */ +getEmbedSettlementReport( + params: PartnerGetSettlementReportParams, +): Promise ⋮---- /** - * If you authenticated the WS API before, automatically try to re-authenticate the WS API if you're disconnected/reconnected for any reason. + * + * Partner REST API - Ramp API - Supported Options + * */ ⋮---- /** - * WS configuration that's always defined, regardless of user configuration - * (usually comes from defaults if there's no user-provided values) - */ -export interface WebsocketClientOptions extends WSClientConfigurableOptions { - pingInterval: number; - pongTimeout: number; - reconnectTimeout: number; - recvWindow: number; - - /** - * If true, require a "receipt" that the connection is ready for use (e.g. a specific event type) + * List Buy Crypto Assets + * + * List cryptocurrency assets available for Ramp buy transactions, + * including the networks, withdrawal methods, and provider-specific identifiers. */ - requireConnectionReadyConfirmation: boolean; - authPrivateConnectionsOnConnect: boolean; - authPrivateRequests: boolean; - reauthWSAPIOnReconnect: boolean; - - /** - * Whether to use native WebSocket ping/pong frames for heartbeats +listRampBuyCryptoAssets(): Promise +⋮---- +/** + * List Fiat Currencies + * + * List fiat currencies supported for funding Ramp transactions. */ - useNativeHeartbeats: boolean; -} +listRampFiatCurrencies(): Promise ⋮---- /** - * If true, require a "receipt" that the connection is ready for use (e.g. a specific event type) + * List Payment Methods + * + * List fiat payment methods supported for Ramp deposits, + * including optional mapping to provider-specific identifiers. */ +listRampPaymentMethods(): Promise ⋮---- /** - * Whether to use native WebSocket ping/pong frames for heartbeats + * List Countries + * + * List countries and regions where Ramp is available. + * Depending on regulatory rules, availability may be scoped to specific states, provinces, or regions. */ +listRampCountries(): Promise ⋮---- -export type WsMarket = 'spot' | 'futures'; +/** + * + * Partner REST API - Ramp API - Quotes + * + */ ⋮---- -export type WsEventInternalSrc = 'event' | 'function' | 'frame'; - -================ -File: src/PartnerClient.ts -================ -import { BaseRestClient } from './lib/BaseRestClient.js'; -import { REST_CLIENT_TYPE_ENUM, RestClientType } from './lib/requestUtils.js'; -import { - PartnerCancelCustomOrderParams, - PartnerCreateCustomOrderParams, - PartnerCreateUserParams, - PartnerExecuteQuoteParams, - PartnerGetAssetParams, - PartnerGetCustomOrderParams, - PartnerGetEarnSummaryParams, - PartnerGetPortfolioHistoryParams, - PartnerGetPortfolioSummaryParams, - PartnerGetQuoteLimitsParams, - PartnerGetQuoteParams, - PartnerGetRampCheckoutUrlParams, - PartnerGetRampLimitsParams, - PartnerGetRampProspectiveQuoteParams, - PartnerGetSettlementReportParams, - PartnerListAssetRatesParams, - PartnerListAssetsParams, - PartnerListCustomOrdersParams, - PartnerListEarnAssetsParams, - PartnerListFundingTransactionsParams, - PartnerListPortfolioDetailsParams, - PartnerListPortfolioTransactionsParams, - PartnerListSettlementReportsParams, - PartnerRequestProspectiveQuoteParams, - PartnerRequestQuoteParams, - PartnerSubmitVerificationParams, - PartnerToggleAutoEarnParams, - PartnerUpdateUserParams, - PartnerWithdrawFundsParams, -} from './types/request/partner.types.js'; +/** + * Get Limits + * + * Retrieve combined min/max limits for a Ramp transaction configuration. + */ +getRampLimits( + params: PartnerGetRampLimitsParams, +): Promise +⋮---- +/** + * Get Prospective Quote + * + * Retrieve a prospective quote for a Ramp transaction without reserving liquidity. + * Use this to preview spend/receive amounts before creating a checkout URL. + */ +getRampProspectiveQuote( + params: PartnerGetRampProspectiveQuoteParams, +): Promise +⋮---- +/** + * + * Partner REST API - Ramp API - Checkout + * + */ +⋮---- +/** + * Get Checkout URL + * + * Generate a hosted Ramp checkout URL for the provided transaction configuration. + * The response echoes the request parameters so the Ramp partner can confirm what was submitted. + */ +getRampCheckoutUrl( + params: PartnerGetRampCheckoutUrlParams, +): Promise + +================ +File: src/SpotClient.ts +================ +import { BaseRestClient } from './lib/BaseRestClient.js'; +import { REST_CLIENT_TYPE_ENUM, RestClientType } from './lib/requestUtils.js'; import { - PartnerCancelCustomOrderResponse, - PartnerCreateCustomOrderResponse, - PartnerCreateUserResponse, - PartnerExecuteQuoteResponse, - PartnerGetAssetResponse, - PartnerGetCustomOrderResponse, - PartnerGetEarnSummaryResponse, - PartnerGetPortfolioHistoryResponse, - PartnerGetPortfolioSummaryResponse, - PartnerGetQuoteLimitsResponse, - PartnerGetQuoteResponse, - PartnerGetRampCheckoutUrlResponse, - PartnerGetRampLimitsResponse, - PartnerGetRampProspectiveQuoteResponse, - PartnerGetSettlementReportResponse, - PartnerGetUserResponse, - PartnerListAssetRatesResponse, - PartnerListAssetsResponse, - PartnerListCustomOrdersResponse, - PartnerListEarnAssetsResponse, - PartnerListFundingTransactionsResponse, - PartnerListPortfolioDetailsResponse, - PartnerListPortfolioTransactionsResponse, - PartnerListRampBuyCryptoAssetsResponse, - PartnerListRampCountriesResponse, - PartnerListRampFiatCurrenciesResponse, - PartnerListRampPaymentMethodsResponse, - PartnerListSettlementReportsResponse, - PartnerRequestProspectiveQuoteResponse, - PartnerRequestQuoteResponse, - PartnerSubmitVerificationResponse, - PartnerToggleAutoEarnResponse, - PartnerUpdateUserResponse, - PartnerWithdrawFundsResponse, -} from './types/response/partner.types.js'; + OauthCreateFastApiKeyParams, + OauthGetAccessTokenParams, + OauthUpdateFastApiKeyParams, + SpotAccountTransferParams, + SpotAmendOrderParams, + SpotGetApiKeyInfoParams, + SpotGetAssetPairsParams, + SpotGetClosedOrdersParams, + SpotGetDepositAddressesParams, + SpotGetDepositMethodsParams, + SpotGetDepositStatusParams, + SpotGetGroupedBookParams, + SpotGetLedgersInfoParams, + SpotGetLevel3Params, + SpotGetOHLCParams, + SpotGetOpenOrdersParams, + SpotGetOpenPositionsParams, + SpotGetOrderBookParams, + SpotGetPostTradeDataParams, + SpotGetRecentSpreadsParams, + SpotGetRecentTradesParams, + SpotGetTradesHistoryParams, + SpotGetTradingVolumeParams, + SpotGetWithdrawalAddressesParams, + SpotGetWithdrawalInfoParams, + SpotGetWithdrawalMethodsParams, + SpotGetWithdrawalsStatusParams, + SpotListEarnAllocationsParams, + SpotListEarnStrategiesParams, + SpotQueryLedgersParams, + SpotQueryOrdersParams, + SpotQueryTradesParams, + SpotRequestExportReportParams, + SpotSubmitOrderBatchParams, + SpotSubmitOrderParams, + SpotWalletTransferParams, + SpotWithdrawFundsParams, +} from './types/request/spot.types.js'; +import { SpotAPISuccessResponse } from './types/response/shared.types.js'; +import { + OauthCreateFastApiKeyResponse, + OauthFastApiKey, + OauthGetAccessTokenResponse, + OauthGetUserInfoResponse, + SpotAccountBalance, + SpotAccountTransferResponse, + SpotApiKeyInfo, + SpotAssetInfo, + SpotAssetPair, + SpotAssetTickerInfo, + SpotBatchOrderResult, + SpotClosedOrdersResponse, + SpotCreditLines, + SpotDeleteExportReportResponse, + SpotDepositAddress, + SpotDepositMethod, + SpotDepositStatusResponse, + SpotEarnStrategy, + SpotExportReportStatus, + SpotExtendedBalance, + SpotGroupedBookResponse, + SpotLedgersInfoResponse, + SpotLevel3OrderBookResponse, + SpotListEarnAllocationsResponse, + SpotOHLCResponse, + SpotOpenOrdersResponse, + SpotOpenPositionsResponse, + SpotOrderAmendsResponse, + SpotOrderBookResponse, + SpotPostTradeDataResponse, + SpotPreTradeData, + SpotQueryLedgersResponse, + SpotQueryOrdersResponse, + SpotQueryTradesResponse, + SpotRecentSpreadsResponse, + SpotRecentTradesResponse, + SpotRequestExportReportResponse, + SpotSubmitOrderResponse, + SpotSystemStatus, + SpotTradeBalance, + SpotTradesHistoryResponse, + SpotTradeVolume, + SpotWebSocketsTokenResponse, + SpotWithdrawalAddress, + SpotWithdrawalInfo, + SpotWithdrawalMethod, + SpotWithdrawalStatus, +} from './types/response/spot.types.js'; ⋮---- /** - * The PartnerClient provides integration to the Kraken Partner API. + * The SpotClient provides integration to the Kraken Spot API. * * Docs: - * - https://docs.kraken.com/api/docs/embed-api - * - https://docs.kraken.com/api/docs/ramp-api + * - https://docs.kraken.com/api/docs/guides/spot-rest-intro/ + * - https://docs.kraken.com/api/docs/rest-api/get-server-time */ -export class PartnerClient extends BaseRestClient +export class SpotClient extends BaseRestClient ⋮---- getClientType(): RestClientType ⋮---- +// Points to api.kraken.com +⋮---- /** * - * Partner REST API - Embed API - Users + * Misc Utility Methods * */ ⋮---- +generateNewOrderID(): string +⋮---- +// Generate a short UUID format (32 hex characters without dashes) +// Compatible with Kraken's cl_ord_id parameter +⋮---- /** - * Create User * - * Create a new user in the Kraken system. + * Spot REST API - Market Data + * */ -createEmbedUser( - params: PartnerCreateUserParams, -): Promise ⋮---- /** - * Get User + * Get Server Time * - * Get a previously created user. + * Get the server's time. */ -getEmbedUser(params: +getServerTime(): Promise< + SpotAPISuccessResponse<{ + unixtime: number; + rfc1123: string; + }> + > { + return this.get('0/public/Time'); ⋮---- /** - * Update User + * Get System Status * - * Update an existing user's profile. + * Get the current system status or trading mode. */ -updateEmbedUser( - params: PartnerUpdateUserParams, -): Promise +getSystemStatus(): Promise> ⋮---- /** + * Get Asset Info * - * Partner REST API - Embed API - Verifications - * + * Get information about the assets that are available for deposit, withdrawal, trading and earn. */ +getAssetInfo(params?: { + asset?: string; + aclass?: 'currency' | 'tokenized_asset'; +}): Promise>> ⋮---- /** - * Submit Verification + * Get Tradable Asset Pairs * - * Submit a verification for a user with documents and details. - * A verification is defined as a check that has been performed on a user to verify information provided by the user. - * Note: This endpoint uses multipart/form-data for file uploads. + * Get tradable asset pairs */ -submitEmbedVerification( - params: PartnerSubmitVerificationParams, -): Promise +getAssetPairs( + params?: SpotGetAssetPairsParams, +): Promise>> ⋮---- /** + * Get Ticker Information * - * Partner REST API - Embed API - Assets - * + * Get ticker information for all or requested markets. + * Note: Today's prices start at midnight UTC. + * Leaving the pair parameter blank will return tickers for all tradeable assets on Kraken. */ +getTicker(params?: { + pair?: string; + asset_class?: 'tokenized_asset' | 'forex'; +}): Promise>> ⋮---- /** - * List Assets + * Get OHLC Data * - * List all assets available on the platform. - * This endpoint returns a list of all assets available on the platform. + * Retrieve OHLC market data. The last entry in the OHLC array is for the current, not-yet-committed timeframe, + * and will always be present, regardless of the value of since. Returns up to 720 of the most recent entries + * (older data cannot be retrieved, regardless of the value of since). */ -listEmbedAssets( - params?: PartnerListAssetsParams, -): Promise +getCandles( + params: SpotGetOHLCParams, +): Promise> ⋮---- /** - * Get Asset + * Get Order Book * - * Get information about a specific asset. + * Returns level 2 (L2) order book, which describes the individual price levels in the book with aggregated + * order quantities at each level. */ -getEmbedAsset( - params: PartnerGetAssetParams, -): Promise +getOrderBook( + params: SpotGetOrderBookParams, +): Promise> ⋮---- /** - * List Asset Rates + * Get Grouped Order Book * - * Returns historical rates for a given asset. - * This endpoint returns historical rates for a given asset with timestamp and median price for each period. + * Aggregates order book volume over a configurable tick grouping. */ -listEmbedAssetRates( - params: PartnerListAssetRatesParams, -): Promise +getGroupedBook( + params: SpotGetGroupedBookParams, +): Promise> ⋮---- /** + * Get Level 3 Order Book * - * Partner REST API - Embed API - Quotes - * + * Individual order-level book data. Requires authentication. */ +getLevel3OrderBook( + params: SpotGetLevel3Params, +): Promise> ⋮---- /** - * Request Quote + * Get Recent Trades * - * Request a price quote for an asset, that may be used to execute a trade later on. + * Returns the last 1000 trades by default */ -requestEmbedQuote( - params: PartnerRequestQuoteParams, -): Promise +getRecentTrades( + params: SpotGetRecentTradesParams, +): Promise> ⋮---- /** - * Get Quote + * Get Recent Spreads * - * Gets the status of a quote that was previously requested. + * Returns the last ~200 top-of-book spreads for a given pair */ -getEmbedQuote( - params: PartnerGetQuoteParams, -): Promise +getRecentSpreads( + params: SpotGetRecentSpreadsParams, +): Promise> ⋮---- /** - * Execute Quote * - * Executes a quote that was previously requested. + * Spot REST API - Account Data + * */ -executeEmbedQuote( - params: PartnerExecuteQuoteParams, -): Promise ⋮---- /** - * Get Quote Limits (RFQ) + * Get Account Balance * - * Request minimum, maximum and precision for trade using a given asset pair. + * Retrieve all cash balances, net of pending withdrawals. */ -getEmbedQuoteLimits( - params: PartnerGetQuoteLimitsParams, -): Promise +getAccountBalance(params?: { + rebase_multiplier?: 'rebased' | 'base'; +}): Promise> ⋮---- /** - * Request Prospective Quote (RFQ) + * Get API Key Info * - * Request a prospective quote for an asset pair, to receive an indicative price and fee. + * Retrieve configuration and usage details for the API key used in the request. */ -requestEmbedProspectiveQuote( - params: PartnerRequestProspectiveQuoteParams, -): Promise +getApiKeyInfo( + params?: SpotGetApiKeyInfoParams, +): Promise> ⋮---- /** + * Get Extended Balance * - * Partner REST API - Embed API - Custom Orders - * + * Retrieve all extended account balances, including credits and held amounts. + * Balance available for trading is calculated as: available balance = balance + credit - credit_used - hold_trade */ +getExtendedBalance(params?: { + rebase_multiplier?: 'rebased' | 'base'; +}): Promise> ⋮---- /** - * Create Custom Order + * Get Credit Lines * - * Submit a custom order with a specified trigger condition (e.g. price-triggered). + * Retrieve all credit line details for VIPs with this functionality. */ -createEmbedCustomOrder( - params: PartnerCreateCustomOrderParams, -): Promise +getCreditLines(params?: { + rebase_multiplier?: 'rebased' | 'base'; +}): Promise> ⋮---- /** - * List Custom Orders + * Get Trade Balance * - * Get a list of custom orders that were previously submitted. + * Retrieve a summary of collateral balances, margin position valuations, equity and margin level. */ -listEmbedCustomOrders( - params: PartnerListCustomOrdersParams, -): Promise +getTradeBalance(params?: { + rebase_multiplier?: 'rebased' | 'base'; +}): Promise> ⋮---- /** - * Get Custom Order + * Get Open Orders * - * Get a single custom order by ID. + * Retrieve information about currently open orders. */ -getEmbedCustomOrder( - params: PartnerGetCustomOrderParams, -): Promise +getOpenOrders( + params?: SpotGetOpenOrdersParams, +): Promise> ⋮---- /** - * Cancel Custom Order + * Get Closed Orders * - * Cancels a custom order that was previously submitted but not yet completed. + * Retrieve information about orders that have been closed (filled or cancelled). + * 50 results are returned at a time, the most recent by default. */ -cancelEmbedCustomOrder( - params: PartnerCancelCustomOrderParams, -): Promise +getClosedOrders( + params?: SpotGetClosedOrdersParams, +): Promise> ⋮---- /** + * Query Orders Info * - * Partner REST API - Embed API - Portfolios - * + * Retrieve information about specific orders. */ +getOrders( + params: SpotQueryOrdersParams, +): Promise> ⋮---- /** - * Get Portfolio Summary + * Get Order Amends * - * Get the portfolio summary for a user. + * Retrieves an audit trail of amend transactions on the specified order. + * The list is ordered by ascending amend timestamp. */ -getEmbedPortfolioSummary( - params: PartnerGetPortfolioSummaryParams, -): Promise +getOrderAmends(params: { + order_id: string; + rebase_multiplier?: 'rebased' | 'base'; +}): Promise> ⋮---- /** - * Get Portfolio History + * Get Trades History * - * Gets a portfolio's historical balances and valuations over time. - * Note: Balance for the last day shows up at UTC + 5h due to processing times. + * Retrieve information about trades/fills. 50 results are returned at a time, the most recent by default. */ -getEmbedPortfolioHistory( - params: PartnerGetPortfolioHistoryParams, -): Promise +getTradesHistory( + params?: SpotGetTradesHistoryParams, +): Promise> ⋮---- /** - * List Portfolio Details + * Query Trades Info * - * Lists owned assets in a user's portfolio. + * Retrieve information about specific trades/fills. */ -listEmbedPortfolioDetails( - params: PartnerListPortfolioDetailsParams, -): Promise +getTrades( + params: SpotQueryTradesParams, +): Promise> ⋮---- /** - * List Portfolio Transactions + * Get Open Positions * - * Lists the user's trades and transactions. + * Get information about open margin positions. */ -listEmbedPortfolioTransactions( - params: PartnerListPortfolioTransactionsParams, -): Promise +getOpenPositions( + params?: SpotGetOpenPositionsParams, +): Promise> ⋮---- /** + * Get Ledgers Info * - * Partner REST API - Embed API - Earn - * + * Retrieve information about ledger entries. 50 results are returned at a time, the most recent by default. */ +getLedgersInfo( + params?: SpotGetLedgersInfoParams, +): Promise> ⋮---- /** - * Get Earn Summary + * Query Ledgers * - * Get Earn summary of a user. - * Response holds total amounts (all-time). For per-asset granularity, use listEarnAssets(). + * Retrieve information about specific ledger entries. */ -getEmbedEarnSummary( - params: PartnerGetEarnSummaryParams, -): Promise +getLedgers( + params: SpotQueryLedgersParams, +): Promise> ⋮---- /** - * List Earn Assets + * Get Trade Volume * - * List Earn Assets. - * The user can optionally be passed in the request, which shows active asset allocations of the user in the response. + * Returns 30 day USD trading volume and resulting fee schedule for any asset pair(s) provided. + * Also use this endpoint (with a Spot API key) to determine Futures fee rates as of 2026-06-22. */ -listEmbedEarnAssets( - params?: PartnerListEarnAssetsParams, -): Promise +getTradingVolume( + params?: SpotGetTradingVolumeParams, +): Promise> ⋮---- /** - * Toggle Auto-Earn + * Request Export Report * - * Toggle Auto-Earn of a user. - * Toggling Auto-Earn is an async operation. The response is empty on success. - * To fetch the user's current Auto-Earn status, use getEarnSummary(). + * Request export of trades or ledgers. */ -toggleEmbedAutoEarn( - params: PartnerToggleAutoEarnParams, -): Promise +requestLedgersExport( + params: SpotRequestExportReportParams, +): Promise> ⋮---- /** + * Get Export Report Status * - * Partner REST API - Embed API - Transfers - * + * Get status of requested data exports. */ +getLedgersExportStatus(params: { + report: 'trades' | 'ledgers'; +}): Promise> ⋮---- /** - * Withdraw Funds + * Retrieve Data Export * - * Withdraw funds. - * Note: Currently, this is a master-only operation. No User parameter exists. + * Retrieve a processed data export (binary zip archive). */ -withdrawEmbedFunds( - params: PartnerWithdrawFundsParams, -): Promise +getLedgersExport(params: ⋮---- /** - * List Funding Transactions + * Delete Export Report * - * List Funding transactions. - * Funding transactions can be of type withdrawal or deposit. - * Note: Currently, this is a master-only operation. No User parameter exists. + * Delete or cancel exported trades/ledgers report. */ -listEmbedFundingTransactions( - params: PartnerListFundingTransactionsParams, -): Promise +deleteLedgersExport(params: { + id: string; + type: 'cancel' | 'delete'; +}): Promise> ⋮---- /** * - * Partner REST API - Embed API - Reports + * Spot REST API - Trading * */ ⋮---- /** - * List Settlement Reports + * Add Order * - * Retrieves a paginated list of settlement reports available to the authenticated master user, - * with optional filters for date range and report type. + * Place a new order. + * Note: See the getAssetPairs() endpoint for details on the available trading pairs, their price and quantity precisions, + * order minimums, available leverage, etc. */ -listEmbedSettlementReports( - params?: PartnerListSettlementReportsParams, -): Promise +submitOrder( + params: SpotSubmitOrderParams, +): Promise> ⋮---- /** - * Get Settlement Report + * Amend Order * - * Retrieves a settlement report and provides a secure download URL for the authenticated master user. - */ -getEmbedSettlementReport( - params: PartnerGetSettlementReportParams, -): Promise + * Amend an existing order. The order identifiers assigned by Kraken and/or client will stay the same. + * Queue priority in the order book will be maintained where possible. + */ +amendOrder(params: SpotAmendOrderParams): Promise< + SpotAPISuccessResponse<{ + amend_id: string; + }> + > { + return this.postPrivate('0/private/AmendOrder', { + body: params, + }); ⋮---- /** + * Cancel Order * - * Partner REST API - Ramp API - Supported Options - * + * Cancel a particular open order (or set of open orders) by txid, userref or cl_ord_id. */ +cancelOrder(params: { txid?: string | number; cl_ord_id?: string }): Promise< + SpotAPISuccessResponse<{ + count: number; + pending?: boolean; + }> + > { + return this.postPrivate('0/private/CancelOrder', { + body: params, + }); ⋮---- /** - * List Buy Crypto Assets + * Cancel All Orders * - * List cryptocurrency assets available for Ramp buy transactions, - * including the networks, withdrawal methods, and provider-specific identifiers. + * Cancel all open orders. */ -listRampBuyCryptoAssets(): Promise +cancelAllOrders(): Promise< + SpotAPISuccessResponse<{ + count: number; + pending: boolean; + }> + > { +return this.postPrivate('0/private/CancelAll', ⋮---- /** - * List Fiat Currencies + * Cancel All Orders After X * - * List fiat currencies supported for funding Ramp transactions. + * CancelAllOrdersAfter provides a "Dead Man's Switch" mechanism to protect the client from network malfunction, + * extreme latency or unexpected matching engine downtime. The client can send a request with a timeout (in seconds), + * that will start a countdown timer which will cancel all client orders when the timer expires. */ -listRampFiatCurrencies(): Promise +cancelAllOrdersAfter(params: { timeout: number }): Promise< + SpotAPISuccessResponse<{ + currentTime: string; + triggerTime: string; + }> + > { + return this.postPrivate('0/private/CancelAllOrdersAfter', { + body: params, + }); ⋮---- /** - * List Payment Methods + * Get Websockets Token * - * List fiat payment methods supported for Ramp deposits, - * including optional mapping to provider-specific identifiers. + * An authentication token must be requested via this REST API endpoint in order to connect to and authenticate + * with the Websockets API. The token should be used within 15 minutes of creation. */ -listRampPaymentMethods(): Promise +getWebSocketsToken(): Promise< + SpotAPISuccessResponse + > { +return this.postPrivate('0/private/GetWebSocketsToken', ⋮---- /** - * List Countries + * Add Order Batch * - * List countries and regions where Ramp is available. - * Depending on regulatory rules, availability may be scoped to specific states, provinces, or regions. + * Sends a collection of orders (minimum of 2 and maximum 15). All orders in batch are limited to a single pair. + * Validation is performed on the whole batch prior to submission. If an order fails validation, the whole batch will be rejected. */ -listRampCountries(): Promise +submitBatchOrders(params: SpotSubmitOrderBatchParams): Promise< + SpotAPISuccessResponse<{ + orders: SpotBatchOrderResult[]; + }> + > { + return this.postPrivate('0/private/AddOrderBatch', { + body: params, + }); ⋮---- /** + * Cancel Order Batch * - * Partner REST API - Ramp API - Quotes - * + * Cancel multiple open orders by txid, userref or cl_ord_id (maximum 50 total unique IDs/references). */ +cancelBatchOrders(params: { + orders?: Array; + cl_ord_ids?: string[]; + }): Promise< + SpotAPISuccessResponse<{ + count: number; + }> + > { + return this.postPrivate('0/private/CancelOrderBatch', { + body: params, + }); ⋮---- /** - * Get Limits * - * Retrieve combined min/max limits for a Ramp transaction configuration. + * Spot REST API - Funding + * */ -getRampLimits( - params: PartnerGetRampLimitsParams, -): Promise ⋮---- /** - * Get Prospective Quote + * Get Deposit Methods * - * Retrieve a prospective quote for a Ramp transaction without reserving liquidity. - * Use this to preview spend/receive amounts before creating a checkout URL. + * Retrieve methods available for depositing a particular asset. */ -getRampProspectiveQuote( - params: PartnerGetRampProspectiveQuoteParams, -): Promise +getDepositMethods( + params: SpotGetDepositMethodsParams, +): Promise> ⋮---- /** + * Get Deposit Addresses * - * Partner REST API - Ramp API - Checkout - * + * Retrieve (or generate a new) deposit addresses for a particular asset and method. */ +getDepositAddresses( + params: SpotGetDepositAddressesParams, +): Promise> ⋮---- /** - * Get Checkout URL + * Get Status of Recent Deposits * - * Generate a hosted Ramp checkout URL for the provided transaction configuration. - * The response echoes the request parameters so the Ramp partner can confirm what was submitted. + * Retrieve information about recent deposits. Results are sorted by recency. */ -getRampCheckoutUrl( - params: PartnerGetRampCheckoutUrlParams, -): Promise - -================ -File: src/SpotClient.ts -================ -import { BaseRestClient } from './lib/BaseRestClient.js'; -import { REST_CLIENT_TYPE_ENUM, RestClientType } from './lib/requestUtils.js'; -import { - OauthCreateFastApiKeyParams, - OauthGetAccessTokenParams, - OauthUpdateFastApiKeyParams, - SpotAccountTransferParams, - SpotAmendOrderParams, - SpotGetAssetPairsParams, - SpotGetClosedOrdersParams, - SpotGetDepositAddressesParams, - SpotGetDepositMethodsParams, - SpotGetDepositStatusParams, - SpotGetLedgersInfoParams, - SpotGetOHLCParams, - SpotGetOpenOrdersParams, - SpotGetOpenPositionsParams, - SpotGetOrderBookParams, - SpotGetPostTradeDataParams, - SpotGetRecentSpreadsParams, - SpotGetRecentTradesParams, - SpotGetTradesHistoryParams, - SpotGetWithdrawalAddressesParams, - SpotGetWithdrawalInfoParams, - SpotGetWithdrawalMethodsParams, - SpotGetWithdrawalsStatusParams, - SpotListEarnAllocationsParams, - SpotListEarnStrategiesParams, - SpotQueryLedgersParams, - SpotQueryOrdersParams, - SpotQueryTradesParams, - SpotRequestExportReportParams, - SpotSubmitOrderBatchParams, - SpotSubmitOrderParams, - SpotWalletTransferParams, - SpotWithdrawFundsParams, -} from './types/request/spot.types.js'; -import { SpotAPISuccessResponse } from './types/response/shared.types.js'; -import { - OauthCreateFastApiKeyResponse, - OauthFastApiKey, - OauthGetAccessTokenResponse, - OauthGetUserInfoResponse, - SpotAccountBalance, - SpotAccountTransferResponse, - SpotAssetInfo, - SpotAssetPair, - SpotAssetTickerInfo, - SpotBatchOrderResult, - SpotClosedOrdersResponse, - SpotCreditLines, - SpotDeleteExportReportResponse, - SpotDepositAddress, - SpotDepositMethod, - SpotDepositStatusResponse, - SpotEarnStrategy, - SpotExportReportStatus, - SpotExtendedBalance, - SpotLedgersInfoResponse, - SpotListEarnAllocationsResponse, - SpotOHLCResponse, - SpotOpenOrdersResponse, - SpotOpenPositionsResponse, - SpotOrderAmendsResponse, - SpotOrderBookResponse, - SpotPostTradeDataResponse, - SpotPreTradeData, - SpotQueryLedgersResponse, - SpotQueryOrdersResponse, - SpotQueryTradesResponse, - SpotRecentSpreadsResponse, - SpotRecentTradesResponse, - SpotRequestExportReportResponse, - SpotSubmitOrderResponse, - SpotSystemStatus, - SpotTradeBalance, - SpotTradesHistoryResponse, - SpotTradeVolume, - SpotWebSocketsTokenResponse, - SpotWithdrawalAddress, - SpotWithdrawalInfo, - SpotWithdrawalMethod, - SpotWithdrawalStatus, -} from './types/response/spot.types.js'; -⋮---- -/** - * The SpotClient provides integration to the Kraken Spot API. - * - * Docs: - * - https://docs.kraken.com/api/docs/guides/spot-rest-intro/ - * - https://docs.kraken.com/api/docs/rest-api/get-server-time - */ -export class SpotClient extends BaseRestClient -⋮---- -getClientType(): RestClientType -⋮---- -// Points to api.kraken.com +getDepositsStatus( + params?: SpotGetDepositStatusParams, +): Promise> ⋮---- /** + * Get Withdrawal Methods * - * Misc Utility Methods - * + * Retrieve a list of withdrawal methods available for the user. */ -⋮---- -generateNewOrderID(): string -⋮---- -// Generate a short UUID format (32 hex characters without dashes) -// Compatible with Kraken's cl_ord_id parameter +getWithdrawalMethods( + params?: SpotGetWithdrawalMethodsParams, +): Promise> ⋮---- /** + * Get Withdrawal Addresses * - * Spot REST API - Market Data - * + * Retrieve a list of withdrawal addresses available for the user. */ +getWithdrawalAddresses( + params?: SpotGetWithdrawalAddressesParams, +): Promise> ⋮---- /** - * Get Server Time + * Get Withdrawal Information * - * Get the server's time. + * Retrieve fee information about potential withdrawals for a particular asset, key and amount. */ -getServerTime(): Promise< +getWithdrawalInfo( + params: SpotGetWithdrawalInfoParams, +): Promise> +⋮---- +/** + * Withdraw Funds + * + * Make a withdrawal request. + */ +submitWithdrawal(params: SpotWithdrawFundsParams): Promise< SpotAPISuccessResponse<{ - unixtime: number; - rfc1123: string; + refid: string; }> > { - return this.get('0/public/Time'); +return this.postPrivate('0/private/Withdraw', ⋮---- /** - * Get System Status + * Get Status of Recent Withdrawals * - * Get the current system status or trading mode. + * Retrieve information about recent withdrawals. Results are sorted by recency. */ -getSystemStatus(): Promise> +getWithdrawalsStatus( + params?: SpotGetWithdrawalsStatusParams, +): Promise> ⋮---- /** - * Get Asset Info + * Request Withdrawal Cancellation * - * Get information about the assets that are available for deposit, withdrawal, trading and earn. + * Cancel a recently requested withdrawal, if it has not already been successfully processed. */ -getAssetInfo(params?: { - asset?: string; - aclass?: 'currency' | 'tokenized_asset'; -}): Promise>> +cancelWithdrawal(params: { + asset: string; + refid: string; +}): Promise> ⋮---- /** - * Get Tradable Asset Pairs + * Request Wallet Transfer * - * Get tradable asset pairs + * Transfer from a Kraken spot wallet to a Kraken Futures wallet. + * Note: Transfer in the other direction must be requested via the Kraken Futures API. */ -getAssetPairs( - params?: SpotGetAssetPairsParams, -): Promise>> +submitTransferToFutures(params: SpotWalletTransferParams): Promise< + SpotAPISuccessResponse<{ + refid: string; + }> + > { +return this.postPrivate('0/private/WalletTransfer', ⋮---- /** - * Get Ticker Information * - * Get ticker information for all or requested markets. - * Note: Today's prices start at midnight UTC. - * Leaving the pair parameter blank will return tickers for all tradeable assets on Kraken. + * Subaccounts + * */ -getTicker(params?: { - pair?: string; - asset_class?: 'tokenized_asset' | 'forex'; -}): Promise>> ⋮---- /** - * Get OHLC Data + * Create Subaccount * - * Retrieve OHLC market data. The last entry in the OHLC array is for the current, not-yet-committed timeframe, - * and will always be present, regardless of the value of since. Returns up to 720 of the most recent entries - * (older data cannot be retrieved, regardless of the value of since). + * Create a trading subaccount. + * Note: CreateSubaccount must be called using an API key from the master account. */ -getCandles( - params: SpotGetOHLCParams, -): Promise> +createSubaccount(params: { + username: string; + email: string; +}): Promise> ⋮---- /** - * Get Order Book + * Account Transfer * - * Returns level 2 (L2) order book, which describes the individual price levels in the book with aggregated - * order quantities at each level. + * Transfer funds to and from master and subaccounts. + * Note: AccountTransfer must be called using an API key from the master account. */ -getOrderBook( - params: SpotGetOrderBookParams, -): Promise> +submitSubaccountTransfer( + params: SpotAccountTransferParams, +): Promise> ⋮---- /** - * Get Recent Trades * - * Returns the last 1000 trades by default + * Earn + * */ -getRecentTrades( - params: SpotGetRecentTradesParams, -): Promise> ⋮---- /** - * Get Recent Spreads + * Allocate Earn Funds * - * Returns the last ~200 top-of-book spreads for a given pair + * Allocate funds to the Strategy. + * This method is asynchronous. Use getAllocationStatus() to poll the result. */ -getRecentSpreads( - params: SpotGetRecentSpreadsParams, -): Promise> +allocateEarnFunds(params: { + amount: string; + strategy_id: string; +}): Promise> ⋮---- /** + * Deallocate Earn Funds * - * Spot REST API - Account Data - * + * Deallocate funds from a strategy. + * This method is asynchronous. Use getDeallocationStatus() to poll the result. */ +deallocateEarnFunds(params: { + amount: string; + strategy_id: string; +}): Promise> ⋮---- /** - * Get Account Balance + * Get Allocation Status * - * Retrieve all cash balances, net of pending withdrawals. + * Get the status of the last allocation request. */ -getAccountBalance(params?: { - rebase_multiplier?: 'rebased' | 'base'; -}): Promise> +getEarnAllocationStatus(params: { strategy_id: string }): Promise< + SpotAPISuccessResponse<{ + pending: boolean; + }> + > { +return this.postPrivate('0/private/Earn/AllocateStatus', ⋮---- /** - * Get Extended Balance + * Get Deallocation Status * - * Retrieve all extended account balances, including credits and held amounts. - * Balance available for trading is calculated as: available balance = balance + credit - credit_used - hold_trade + * Get the status of the last deallocation request. */ -getExtendedBalance(params?: { - rebase_multiplier?: 'rebased' | 'base'; -}): Promise> +getEarnDeallocationStatus(params: { strategy_id: string }): Promise< + SpotAPISuccessResponse<{ + pending: boolean; + }> + > { + return this.postPrivate('0/private/Earn/DeallocateStatus', { + body: params, + }); ⋮---- /** - * Get Credit Lines + * List Earn Strategies * - * Retrieve all credit line details for VIPs with this functionality. + * List earn strategies along with their parameters. + * Returns only strategies that are available to the user based on geographic region. */ -getCreditLines(params?: { - rebase_multiplier?: 'rebased' | 'base'; -}): Promise> +getEarnStrategies(params?: SpotListEarnStrategiesParams): Promise< + SpotAPISuccessResponse<{ + items: SpotEarnStrategy[]; + next_cursor?: string; + }> + > { +return this.postPrivate('0/private/Earn/Strategies', ⋮---- /** - * Get Trade Balance + * List Earn Allocations * - * Retrieve a summary of collateral balances, margin position valuations, equity and margin level. + * List all allocations for the user. + * By default all allocations are returned, even for strategies that have been used in the past and have zero balance now. */ -getTradeBalance(params?: { - rebase_multiplier?: 'rebased' | 'base'; -}): Promise> +getEarnAllocations( + params?: SpotListEarnAllocationsParams, +): Promise> ⋮---- /** - * Get Open Orders * - * Retrieve information about currently open orders. + * Transparency + * */ -getOpenOrders( - params?: SpotGetOpenOrdersParams, -): Promise> ⋮---- /** - * Get Closed Orders + * Pre-Trade Data * - * Retrieve information about orders that have been closed (filled or cancelled). - * 50 results are returned at a time, the most recent by default. + * Returns the price levels in the order book with aggregated order quantities at each price level. + * The top 10 levels are returned for each trading pair. */ -getClosedOrders( - params?: SpotGetClosedOrdersParams, -): Promise> +getPreTradeData(params: { + symbol: string; +}): Promise> ⋮---- /** - * Query Orders Info + * Post-Trade Data * - * Retrieve information about specific orders. + * Returns a list of trades on the spot exchange. + * If no filter parameters are specified, the last 1000 trades for all pairs are received. */ -getOrders( - params: SpotQueryOrdersParams, -): Promise> +getPostTradeData( + params?: SpotGetPostTradeDataParams, +): Promise> ⋮---- /** - * Get Order Amends * - * Retrieves an audit trail of amend transactions on the specified order. - * The list is ordered by ascending amend timestamp. + * Spot REST API - OAuth + * */ -getOrderAmends(params: { - order_id: string; - rebase_multiplier?: 'rebased' | 'base'; -}): Promise> ⋮---- /** - * Get Trades History + * Get Access Token * - * Retrieve information about trades/fills. 50 results are returned at a time, the most recent by default. + * Retrieve the access token. + * Note: This endpoint uses Basic authentication (Authorization header with base64-encoded client credentials). */ -getTradesHistory( - params?: SpotGetTradesHistoryParams, -): Promise> +getOAuthAccessToken( + params: OauthGetAccessTokenParams, +): Promise ⋮---- /** - * Query Trades Info + * Get User Info * - * Retrieve information about specific trades/fills. + * Returns the email address and IIBAN of the user. + * Note: Requires OAuth2 Bearer token. Scopes required: account.info:basic */ -getTrades( - params: SpotQueryTradesParams, -): Promise> +getOAuthUserInfo(): Promise ⋮---- /** - * Get Open Positions + * Create Fast API Key * - * Get information about open margin positions. + * Creates a Fast API key. + * Note: Requires OAuth2 Bearer token. Scopes required: account.fast-api-key:write */ -getOpenPositions( - params?: SpotGetOpenPositionsParams, -): Promise> +createOAuthFastApiKey( + params: OauthCreateFastApiKeyParams, +): Promise ⋮---- /** - * Get Ledgers Info + * Delete Fast API Key * - * Retrieve information about ledger entries. 50 results are returned at a time, the most recent by default. + * Deletes a Fast API key. + * Note: Requires OAuth2 Bearer token. Scopes required: account.fast-api-key:write */ -getLedgersInfo( - params?: SpotGetLedgersInfoParams, -): Promise> +deleteOAuthFastApiKey(params: { + api_key_name: string; // max 32 chars +}): Promise< +⋮---- +api_key_name: string; // max 32 chars ⋮---- /** - * Query Ledgers + * Update Fast API Key * - * Retrieve information about specific ledger entries. + * Updates a Fast API key. + * Note: Requires OAuth2 Bearer token. Scopes required: account.fast-api-key:write */ -getLedgers( - params: SpotQueryLedgersParams, -): Promise> +updateOAuthFastApiKey(params: OauthUpdateFastApiKeyParams): Promise< ⋮---- /** - * Get Trade Volume + * List Fast API Keys * - * Returns 30 day USD trading volume and resulting fee schedule for any asset pair(s) provided. - * Also use this endpoint (with a Spot API key) to determine Futures fee rates as of 2026-06-22. + * List all Fast API keys. + * Note: Requires OAuth2 Bearer token. Scopes required: account.fast-api-key:read */ -getTradingVolume(params?: { - pair?: string; - rebase_multiplier?: 'rebased' | 'base'; -}): Promise> +listOAuthFastApiKeys(): Promise< + +================ +File: src/WebsocketClient.ts +================ +import { + BaseWebsocketClient, + EmittableEvent, + MidflightWsRequestEvent, +} from './lib/BaseWSClient.js'; +import { neverGuard } from './lib/misc-util.js'; +import { RestClientOptions } from './lib/requestUtils.js'; +import { + hashMessage, + SignAlgorithm, + SignEncodeMethod, + signMessage, + SignMessageOptions, +} from './lib/webCryptoAPI.js'; +import { DefaultLogger } from './lib/websocket/logger.js'; +import { RestClientCache } from './lib/websocket/rest-client-cache.js'; +import { + getPromiseRefForWSAPIRequest, + WS_KEY_MAP, + WsKey, + WSOperation, + WSRequestOperationKraken, + WSTopicRequest, +} from './lib/websocket/websocket-util.js'; +import { WSConnectedResult } from './lib/websocket/WsStore.types.js'; +import { + Exact, + WS_API_Operations, + WSAPIAuthenticationRequestFromServer, + WSAPIRequestOperationKrakenSpot, + WSAPITopicRequestParamMap, + WSAPITopicResponseMap, + WSAPIWsKey, + WSAPIWsKeyTopicMap, +} from './types/websockets/ws-api.js'; +import { MessageEventLike } from './types/websockets/ws-events.js'; +import { + WSClientConfigurableOptions, + WsMarket, +} from './types/websockets/ws-general.js'; +import { + WS_DERIVATIVES_PRIVATE_TOPICS, + WS_SPOT_PRIVATE_TOPICS, + WSTopic, +} from './types/websockets/ws-subscriptions.js'; ⋮---- -/** - * Request Export Report - * - * Request export of trades or ledgers. - */ -requestLedgersExport( - params: SpotRequestExportReportParams, -): Promise> +export interface WSAPIRequestFlags { + /** If true, will skip auth requirement for WS API connection */ + authIsOptional?: boolean | undefined; +} ⋮---- -/** - * Get Export Report Status - * - * Get status of requested data exports. - */ -getLedgersExportStatus(params: { - report: 'trades' | 'ledgers'; -}): Promise> +/** If true, will skip auth requirement for WS API connection */ ⋮---- -/** - * Retrieve Data Export - * - * Retrieve a processed data export (binary zip archive). - */ -getLedgersExport(params: +export class WebsocketClient extends BaseWebsocketClient ⋮---- -/** - * Delete Export Report - * - * Delete or cancel exported trades/ledgers report. - */ -deleteLedgersExport(params: { - id: string; - type: 'cancel' | 'delete'; -}): Promise> +constructor(options?: WSClientConfigurableOptions, logger?: DefaultLogger) ⋮---- /** + * Request connection of all dependent (public & private) websockets, instead of waiting for automatic connection by library. * - * Spot REST API - Trading - * + * Returns array of promises that individually resolve when each connection is successfully opened. */ +public connectAll(): Promise[] ⋮---- /** - * Add Order + * Ensures the WS API connection is active and ready. * - * Place a new order. - * Note: See the getAssetPairs() endpoint for details on the available trading pairs, their price and quantity precisions, - * order minimums, available leverage, etc. + * You do not need to call this, but if you call this before making any WS API requests, + * it can accelerate the first request (by preparing the connection in advance). */ -submitOrder( - params: SpotSubmitOrderParams, -): Promise> +public connectWSAPI(wsKey: WSAPIWsKey, skipAuth?: boolean): Promise ⋮---- -/** - * Amend Order - * - * Amend an existing order. The order identifiers assigned by Kraken and/or client will stay the same. - * Queue priority in the order book will be maintained where possible. - */ -amendOrder(params: SpotAmendOrderParams): Promise< - SpotAPISuccessResponse<{ - amend_id: string; - }> - > { - return this.postPrivate('0/private/AmendOrder', { - body: params, - }); +/** This call automatically ensures the connection is active AND authenticated before resolving */ ⋮---- /** - * Cancel Order + * Request subscription to one or more topics. Pass topics as either an array of strings, or array of objects (if the topic has parameters). + * Objects should be formatted as {topic: string, params: object}. * - * Cancel a particular open order (or set of open orders) by txid, userref or cl_ord_id. - */ -cancelOrder(params: { txid?: string | number; cl_ord_id?: string }): Promise< - SpotAPISuccessResponse<{ - count: number; - pending?: boolean; - }> - > { - return this.postPrivate('0/private/CancelOrder', { - body: params, - }); -⋮---- -/** - * Cancel All Orders + * - Subscriptions are automatically routed to the correct websocket connection. + * - Authentication/connection is automatic. + * - Resubscribe after network issues is automatic. * - * Cancel all open orders. + * Call `unsubscribe(topics)` to remove topics */ -cancelAllOrders(): Promise< - SpotAPISuccessResponse<{ - count: number; - pending: boolean; - }> - > { -return this.postPrivate('0/private/CancelAll', +public subscribe( + requests: + | (WSTopicRequest | WSTopic) + | (WSTopicRequest | WSTopic)[], + wsKey: WsKey, +) ⋮---- /** - * Cancel All Orders After X + * Unsubscribe from one or more topics. Similar to subscribe() but in reverse. * - * CancelAllOrdersAfter provides a "Dead Man's Switch" mechanism to protect the client from network malfunction, - * extreme latency or unexpected matching engine downtime. The client can send a request with a timeout (in seconds), - * that will start a countdown timer which will cancel all client orders when the timer expires. + * - Requests are automatically routed to the correct websocket connection. + * - These topics will be removed from the topic cache, so they won't be subscribed to again. */ -cancelAllOrdersAfter(params: { timeout: number }): Promise< - SpotAPISuccessResponse<{ - currentTime: string; - triggerTime: string; - }> - > { - return this.postPrivate('0/private/CancelAllOrdersAfter', { - body: params, - }); +public unsubscribe( + requests: + | (WSTopicRequest | WSTopic) + | (WSTopicRequest | WSTopic)[], + wsKey: WsKey, +) ⋮---- /** - * Get Websockets Token - * - * An authentication token must be requested via this REST API endpoint in order to connect to and authenticate - * with the Websockets API. The token should be used within 15 minutes of creation. + * WS API Methods - similar to the REST API, but via WebSockets */ -getWebSocketsToken(): Promise< - SpotAPISuccessResponse - > { -return this.postPrivate('0/private/GetWebSocketsToken', ⋮---- /** - * Add Order Batch + * Send a Websocket API event on a connection. Returns a promise that resolves on reply. * - * Sends a collection of orders (minimum of 2 and maximum 15). All orders in batch are limited to a single pair. - * Validation is performed on the whole batch prior to submission. If an order fails validation, the whole batch will be rejected. - */ -submitBatchOrders(params: SpotSubmitOrderBatchParams): Promise< - SpotAPISuccessResponse<{ - orders: SpotBatchOrderResult[]; - }> - > { - return this.postPrivate('0/private/AddOrderBatch', { - body: params, - }); -⋮---- -/** - * Cancel Order Batch + * Returned promise is rejected if an exception is detected in the reply OR the connection disconnects for any reason (even if automatic reconnect will happen). * - * Cancel multiple open orders by txid, userref or cl_ord_id (maximum 50 total unique IDs/references). - */ -cancelBatchOrders(params: { - orders?: Array; - cl_ord_ids?: string[]; - }): Promise< - SpotAPISuccessResponse<{ - count: number; - }> - > { - return this.postPrivate('0/private/CancelOrderBatch', { - body: params, - }); -⋮---- -/** + * After a fresh connection, you should always send a login request first. * - * Spot REST API - Funding + * If you authenticated once and you're reconnected later (e.g. connection temporarily lost), the SDK will by default automatically: + * - Detect you were authenticated to the WS API before + * - Try to re-authenticate (up to 5 times, in case something (bad timestamp) goes wrong) + * - If it succeeds, it will emit the 'authenticated' event. + * - If it fails and gives up, it will emit an 'exception' event (type: 'wsapi.auth', reason: detailed text). * - */ -⋮---- -/** - * Get Deposit Methods + * You can turn off the automatic re-auth WS API logic using `reauthWSAPIOnReconnect: false` in the WSClient config. * - * Retrieve methods available for depositing a particular asset. + * @param wsKey - The connection this event is for (e.g. "spotV4" | "perpFuturesUSDTV4" | "perpFuturesBTCV4" | "deliveryFuturesUSDTV4" | "deliveryFuturesBTCV4" | "optionsV4") + * @param channel - The channel this event is for (e.g. "spot.login" to authenticate) + * @param params - Any request parameters for the payload (contents of req_param in the docs). Signature generation is automatic, only send parameters such as order ID as per the docs. + * @returns Promise - tries to resolve with async WS API response. Rejects if disconnected or exception is seen in async WS API response */ -getDepositMethods( - params: SpotGetDepositMethodsParams, -): Promise> ⋮---- -/** - * Get Deposit Addresses - * - * Retrieve (or generate a new) deposit addresses for a particular asset and method. - */ -getDepositAddresses( - params: SpotGetDepositAddressesParams, -): Promise> +// This overload allows the caller to omit the 3rd param, if it isn't required (e.g. for the login call) +async sendWSAPIRequest< + TWSKey extends keyof WSAPIWsKeyTopicMap, + TWSOperation extends WSAPIWsKeyTopicMap[TWSKey], + TWSParams extends Exact, + TWSAPIResponse extends + | WSAPITopicResponseMap[TWSOperation] + | object = WSAPITopicResponseMap[TWSOperation], + >( + wsKey: TWSKey, + operation: TWSOperation, + params?: TWSParams extends void | never ? undefined : TWSParams, + requestFlags?: WSAPIRequestFlags, + ): Promise; ⋮---- -/** - * Get Status of Recent Deposits - * - * Retrieve information about recent deposits. Results are sorted by recency. - */ -getDepositsStatus( - params?: SpotGetDepositStatusParams, -): Promise> +async sendWSAPIRequest< + TWSKey extends keyof WSAPIWsKeyTopicMap, + TWSOperation extends WSAPIWsKeyTopicMap[TWSKey], + // if this throws a type error, probably forgot to add a new operation to WsAPITopicRequestParamMap + TWSParams extends Exact, + TWSAPIResponse extends + | WSAPITopicResponseMap[TWSOperation] + | object = WSAPITopicResponseMap[TWSOperation], + >( + wsKey: TWSKey, + operation: TWSOperation, + params: TWSParams & { signRequest?: boolean }, + requestFlags?: WSAPIRequestFlags, +): Promise ⋮---- -/** - * Get Withdrawal Methods - * - * Retrieve a list of withdrawal methods available for the user. - */ -getWithdrawalMethods( - params?: SpotGetWithdrawalMethodsParams, -): Promise> +// if this throws a type error, probably forgot to add a new operation to WsAPITopicRequestParamMap ⋮---- /** - * Get Withdrawal Addresses - * - * Retrieve a list of withdrawal addresses available for the user. - */ -getWithdrawalAddresses( - params?: SpotGetWithdrawalAddressesParams, -): Promise> + * Base Info: + * - https://docs.kraken.com/api/docs/websocket-v2/add_order + * + * Currently only supported for Spot markets + */ ⋮---- -/** - * Get Withdrawal Information - * - * Retrieve fee information about potential withdrawals for a particular asset, key and amount. - */ -getWithdrawalInfo( - params: SpotGetWithdrawalInfoParams, -): Promise> +// Some commands don't require authentication. ⋮---- -/** - * Withdraw Funds - * - * Make a withdrawal request. - */ -submitWithdrawal(params: SpotWithdrawFundsParams): Promise< - SpotAPISuccessResponse<{ - refid: string; - }> - > { -return this.postPrivate('0/private/Withdraw', +// Sign request ⋮---- -/** - * Get Status of Recent Withdrawals - * - * Retrieve information about recent withdrawals. Results are sorted by recency. - */ -getWithdrawalsStatus( - params?: SpotGetWithdrawalsStatusParams, -): Promise> +// Store deferred promise ⋮---- -/** - * Request Withdrawal Cancellation - * - * Cancel a recently requested withdrawal, if it has not already been successfully processed. - */ -cancelWithdrawal(params: { - asset: string; - refid: string; -}): Promise> +// Enrich returned promise with request context for easier debugging ⋮---- -/** - * Request Wallet Transfer - * - * Transfer from a Kraken spot wallet to a Kraken Futures wallet. - * Note: Transfer in the other direction must be requested via the Kraken Futures API. - */ -submitTransferToFutures(params: SpotWalletTransferParams): Promise< - SpotAPISuccessResponse<{ - refid: string; - }> - > { -return this.postPrivate('0/private/WalletTransfer', +// Send event +⋮---- +// Return deferred promise, so caller can await this call ⋮---- /** * - * Subaccounts + * Internal methods - not intended for public use * */ ⋮---- +private getRestClientOptions(): RestClientOptions +⋮---- /** - * Create Subaccount - * - * Create a trading subaccount. - * Note: CreateSubaccount must be called using an API key from the master account. + * Note: implementing this method will wipe the WsStore state for this WsKey, once this method returns */ -createSubaccount(params: { - username: string; - email: string; -}): Promise> +protected isCustomReconnectionNeeded(): boolean +⋮---- +protected async triggerCustomReconnectionWorkflow(): Promise +⋮---- +protected async getWsUrl(wsKey: WsKey): Promise ⋮---- /** - * Account Transfer - * - * Transfer funds to and from master and subaccounts. - * Note: AccountTransfer must be called using an API key from the master account. - */ -submitSubaccountTransfer( - params: SpotAccountTransferParams, -): Promise> + * https://docs.kraken.com/api/docs/guides/spot-ws-intro/ + * + * Note: Kraken's v2 WebSockets clean up a number idiosyncrasies and ambiguities from v1 with the overall aim to enable easier integration with applications. It is intended that v1 will be maintained but future enhancements will be developed in v2. + * + * Given the above, we are only integrating with V2 for now. + * + * V2 SpotWebSocket Reference: https://docs.kraken.com/api/docs/websocket-v2/add_order/ + */ +⋮---- +// Uses the same URL, but we maintain separate connections for easier management +⋮---- +protected sendPingEvent(wsKey: WsKey) +⋮---- +// let pingChannel: WsRequestPing['channel']; +⋮---- +// Spot: https://docs.kraken.com/api/docs/websocket-v2/ping +⋮---- +protected sendPongEvent(wsKey: WsKey) +⋮---- +// Send a protocol layer pong +⋮---- +// NOT IN USE for kraken +// eslint-disable-next-line @typescript-eslint/no-unused-vars +protected isWsPing(_msg: any): boolean +⋮---- +protected isWsPong(msg: any): boolean +⋮---- +// Pre-parsed in resolveEmittableEvents into "pong" eventType: ⋮---- /** - * - * Earn - * + * Parse incoming events into categories, before emitting to the user */ +protected resolveEmittableEvents( + wsKey: WsKey, + event: MessageEventLike, +): EmittableEvent[] +⋮---- +// derivatives sends 'challenge' on successful auth-init (used for sign during subscribe) +⋮---- +// spot confirmation for subscription success +⋮---- +// derivatives confirmation for subscription success +⋮---- +// WS API +⋮---- +// WS API Exception +⋮---- +// WS API Success +⋮---- +} // end of WS API response processing +⋮---- +// exceptions with derivatives v1 WS. E.g. { event: 'alert', message: 'Bad websocket message' } +⋮---- +// Most events use event: "update" or "snapshot" for topic updates +⋮---- +// These are request/reply pattern events (e.g. after subscribing to topics or authenticating) +// e.g. "method":"subscribe" +⋮---- +// derivatives events include the "feed" property to identify the channel name +⋮---- +// Request/reply pattern for authentication success ⋮---- /** - * Allocate Earn Funds - * - * Allocate funds to the Strategy. - * This method is asynchronous. Use getAllocationStatus() to poll the result. + * Determines if a topic is for a private channel, using a hardcoded list of strings */ -allocateEarnFunds(params: { - amount: string; - strategy_id: string; -}): Promise> +protected isPrivateTopicRequest(request: WSTopicRequest): boolean ⋮---- /** - * Deallocate Earn Funds - * - * Deallocate funds from a strategy. - * This method is asynchronous. Use getDeallocationStatus() to poll the result. + * Not in use for Kraken */ -deallocateEarnFunds(params: { - amount: string; - strategy_id: string; -}): Promise> +⋮---- +// eslint-disable-next-line @typescript-eslint/no-unused-vars +protected getWsMarketForWsKey(_wsKey: WsKey): WsMarket ⋮---- /** - * Get Allocation Status - * - * Get the status of the last allocation request. + * Whether key represents a private connection. Feeds into automatic auth on connect. */ -getEarnAllocationStatus(params: { strategy_id: string }): Promise< - SpotAPISuccessResponse<{ - pending: boolean; - }> - > { -return this.postPrivate('0/private/Earn/AllocateStatus', +protected getPrivateWSKeys(): WsKey[] +⋮---- +protected isAuthOnConnectWsKey(wsKey: WsKey): boolean +⋮---- +/** Force subscription requests to be sent in smaller batches, if a number is returned */ +// eslint-disable-next-line @typescript-eslint/no-unused-vars +protected getMaxTopicsPerSubscribeEvent(_wsKey: WsKey): number | null +⋮---- +protected authPrivateConnectionsOnConnect(wsKey: WsKey): boolean +⋮---- +// derivatives require you to send a challenge on connect ⋮---- /** - * Get Deallocation Status - * - * Get the status of the last deallocation request. + * @returns one or more correctly structured request events for performing a operations over WS. This can vary per exchange spec. */ -getEarnDeallocationStatus(params: { strategy_id: string }): Promise< - SpotAPISuccessResponse<{ - pending: boolean; - }> - > { - return this.postPrivate('0/private/Earn/DeallocateStatus', { - body: params, - }); +protected async getWsRequestEvents( + wsKey: WsKey, + operation: WSOperation, + requests: WSTopicRequest[], +): Promise>[]> ⋮---- -/** - * List Earn Strategies - * - * List earn strategies along with their parameters. - * Returns only strategies that are available to the user based on geographic region. - */ -getEarnStrategies(params?: SpotListEarnStrategiesParams): Promise< - SpotAPISuccessResponse<{ - items: SpotEarnStrategy[]; - next_cursor?: string; - }> - > { -return this.postPrivate('0/private/Earn/Strategies', +// Previously used to track topics in a request. Keeping this for subscribe/unsubscribe requests, no need for incremental values ⋮---- -/** - * List Earn Allocations - * - * List all allocations for the user. - * By default all allocations are returned, even for strategies that have been used in the past and have zero balance now. - */ -getEarnAllocations( - params?: SpotListEarnAllocationsParams, -): Promise> +// Get token from REST client cache ⋮---- -/** - * - * Transparency - * - */ +// Cache midflight subs on the req ID +// Enrich response with subs for that req ID ⋮---- -/** - * Pre-Trade Data - * - * Returns the price levels in the order book with aggregated order quantities at each price level. - * The top 10 levels are returned for each trading pair. - */ -getPreTradeData(params: { - symbol: string; -}): Promise> +// No auth needed, it's public topics only here ⋮---- -/** - * Post-Trade Data - * - * Returns a list of trades on the spot exchange. - * If no filter parameters are specified, the last 1000 trades for all pairs are received. - */ -getPostTradeData( - params?: SpotGetPostTradeDataParams, -): Promise> +// Cache midflight subs on the req ID +// Enrich response with subs for that req ID ⋮---- -/** - * - * Spot REST API - OAuth - * - */ +// https://docs.kraken.com/api/docs/guides/futures-websockets +// Authenticated requests must include both the original challenge message (original_challenge) and the signed (signed_challenge) in JSON format. ⋮---- -/** - * Get Access Token - * - * Retrieve the access token. - * Note: This endpoint uses Basic authentication (Authorization header with base64-encoded client credentials). - */ -getOAuthAccessToken( - params: OauthGetAccessTokenParams, -): Promise +// Cache midflight subs on the req ID +// Enrich response with subs for that req ID ⋮---- -/** - * Get User Info - * - * Returns the email address and IIBAN of the user. - * Note: Requires OAuth2 Bearer token. Scopes required: account.info:basic - */ -getOAuthUserInfo(): Promise +private async signMessage( + paramsStr: string, + secret: string, + method: SignEncodeMethod, + algorithm: SignAlgorithm, + options?: SignMessageOptions, +): Promise ⋮---- -/** - * Create Fast API Key - * - * Creates a Fast API key. - * Note: Requires OAuth2 Bearer token. Scopes required: account.fast-api-key:write - */ -createOAuthFastApiKey( - params: OauthCreateFastApiKeyParams, -): Promise +protected async getWsAuthRequestEvent( + wsKey: WsKey, + eventToAuth?: WSAPIAuthenticationRequestFromServer, +): Promise ⋮---- -/** - * Delete Fast API Key - * - * Deletes a Fast API key. - * Note: Requires OAuth2 Bearer token. Scopes required: account.fast-api-key:write - */ -deleteOAuthFastApiKey(params: { - api_key_name: string; // max 32 chars -}): Promise< +// Not needed here, handled automatically with request during subscribe ⋮---- -api_key_name: string; // max 32 chars +// Public WS - no auth ⋮---- -/** - * Update Fast API Key - * - * Updates a Fast API key. - * Note: Requires OAuth2 Bearer token. Scopes required: account.fast-api-key:write - */ -updateOAuthFastApiKey(params: OauthUpdateFastApiKeyParams): Promise< +// cleanup old challenge key (in case we were reconnected) +⋮---- +// https://docs.kraken.com/api/docs/futures-api/websocket/challenge/ ⋮---- /** - * List Fast API Keys * - * List all Fast API keys. - * Note: Requires OAuth2 Bearer token. Scopes required: account.fast-api-key:read + * @param requestEvent + * @returns A signed updated WS API request object, ready to be sent */ -listOAuthFastApiKeys(): Promise< +private async signWSAPIRequest( + requestEvent: WSAPIRequestOperationKrakenSpot, +): Promise +⋮---- +// Get token from REST client cache +⋮---- +// authParams.broker = APIIDMain; ================ File: .gitignore @@ -11515,6 +12040,7 @@ File: README.md [![npm downloads](https://img.shields.io/npm/dt/@siebly/kraken-api)][1] [![last commit](https://img.shields.io/github/last-commit/sieblyio/kraken-api)][1] [![Telegram](https://img.shields.io/badge/chat-on%20telegram-blue.svg)](https://t.me/nodetraders) +[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/sieblyio/kraken-api)

@@ -12162,357 +12688,6 @@ Contributions are encouraged, I will review any incoming pull requests. See the -================ -File: src/WebsocketClient.ts -================ -import { - BaseWebsocketClient, - EmittableEvent, - MidflightWsRequestEvent, -} from './lib/BaseWSClient.js'; -import { neverGuard } from './lib/misc-util.js'; -import { RestClientOptions } from './lib/requestUtils.js'; -import { - hashMessage, - SignAlgorithm, - SignEncodeMethod, - signMessage, - SignMessageOptions, -} from './lib/webCryptoAPI.js'; -import { DefaultLogger } from './lib/websocket/logger.js'; -import { RestClientCache } from './lib/websocket/rest-client-cache.js'; -import { - getPromiseRefForWSAPIRequest, - WS_KEY_MAP, - WsKey, - WSOperation, - WSRequestOperationKraken, - WSTopicRequest, -} from './lib/websocket/websocket-util.js'; -import { WSConnectedResult } from './lib/websocket/WsStore.types.js'; -import { - Exact, - WS_API_Operations, - WSAPIAuthenticationRequestFromServer, - WSAPIRequestOperationKrakenSpot, - WSAPITopicRequestParamMap, - WSAPITopicResponseMap, - WSAPIWsKey, - WSAPIWsKeyTopicMap, -} from './types/websockets/ws-api.js'; -import { MessageEventLike } from './types/websockets/ws-events.js'; -import { - WSClientConfigurableOptions, - WsMarket, -} from './types/websockets/ws-general.js'; -import { - WS_DERIVATIVES_PRIVATE_TOPICS, - WS_SPOT_PRIVATE_TOPICS, - WSTopic, -} from './types/websockets/ws-subscriptions.js'; -⋮---- -export interface WSAPIRequestFlags { - /** If true, will skip auth requirement for WS API connection */ - authIsOptional?: boolean | undefined; -} -⋮---- -/** If true, will skip auth requirement for WS API connection */ -⋮---- -export class WebsocketClient extends BaseWebsocketClient -⋮---- -constructor(options?: WSClientConfigurableOptions, logger?: DefaultLogger) -⋮---- -/** - * Request connection of all dependent (public & private) websockets, instead of waiting for automatic connection by library. - * - * Returns array of promises that individually resolve when each connection is successfully opened. - */ -public connectAll(): Promise[] -⋮---- -/** - * Ensures the WS API connection is active and ready. - * - * You do not need to call this, but if you call this before making any WS API requests, - * it can accelerate the first request (by preparing the connection in advance). - */ -public connectWSAPI(wsKey: WSAPIWsKey, skipAuth?: boolean): Promise -⋮---- -/** This call automatically ensures the connection is active AND authenticated before resolving */ -⋮---- -/** - * Request subscription to one or more topics. Pass topics as either an array of strings, or array of objects (if the topic has parameters). - * Objects should be formatted as {topic: string, params: object}. - * - * - Subscriptions are automatically routed to the correct websocket connection. - * - Authentication/connection is automatic. - * - Resubscribe after network issues is automatic. - * - * Call `unsubscribe(topics)` to remove topics - */ -public subscribe( - requests: - | (WSTopicRequest | WSTopic) - | (WSTopicRequest | WSTopic)[], - wsKey: WsKey, -) -⋮---- -/** - * Unsubscribe from one or more topics. Similar to subscribe() but in reverse. - * - * - Requests are automatically routed to the correct websocket connection. - * - These topics will be removed from the topic cache, so they won't be subscribed to again. - */ -public unsubscribe( - requests: - | (WSTopicRequest | WSTopic) - | (WSTopicRequest | WSTopic)[], - wsKey: WsKey, -) -⋮---- -/** - * WS API Methods - similar to the REST API, but via WebSockets - */ -⋮---- -/** - * Send a Websocket API event on a connection. Returns a promise that resolves on reply. - * - * Returned promise is rejected if an exception is detected in the reply OR the connection disconnects for any reason (even if automatic reconnect will happen). - * - * After a fresh connection, you should always send a login request first. - * - * If you authenticated once and you're reconnected later (e.g. connection temporarily lost), the SDK will by default automatically: - * - Detect you were authenticated to the WS API before - * - Try to re-authenticate (up to 5 times, in case something (bad timestamp) goes wrong) - * - If it succeeds, it will emit the 'authenticated' event. - * - If it fails and gives up, it will emit an 'exception' event (type: 'wsapi.auth', reason: detailed text). - * - * You can turn off the automatic re-auth WS API logic using `reauthWSAPIOnReconnect: false` in the WSClient config. - * - * @param wsKey - The connection this event is for (e.g. "spotV4" | "perpFuturesUSDTV4" | "perpFuturesBTCV4" | "deliveryFuturesUSDTV4" | "deliveryFuturesBTCV4" | "optionsV4") - * @param channel - The channel this event is for (e.g. "spot.login" to authenticate) - * @param params - Any request parameters for the payload (contents of req_param in the docs). Signature generation is automatic, only send parameters such as order ID as per the docs. - * @returns Promise - tries to resolve with async WS API response. Rejects if disconnected or exception is seen in async WS API response - */ -⋮---- -// This overload allows the caller to omit the 3rd param, if it isn't required (e.g. for the login call) -async sendWSAPIRequest< - TWSKey extends keyof WSAPIWsKeyTopicMap, - TWSOperation extends WSAPIWsKeyTopicMap[TWSKey], - TWSParams extends Exact, - TWSAPIResponse extends - | WSAPITopicResponseMap[TWSOperation] - | object = WSAPITopicResponseMap[TWSOperation], - >( - wsKey: TWSKey, - operation: TWSOperation, - params?: TWSParams extends void | never ? undefined : TWSParams, - requestFlags?: WSAPIRequestFlags, - ): Promise; -⋮---- -async sendWSAPIRequest< - TWSKey extends keyof WSAPIWsKeyTopicMap, - TWSOperation extends WSAPIWsKeyTopicMap[TWSKey], - // if this throws a type error, probably forgot to add a new operation to WsAPITopicRequestParamMap - TWSParams extends Exact, - TWSAPIResponse extends - | WSAPITopicResponseMap[TWSOperation] - | object = WSAPITopicResponseMap[TWSOperation], - >( - wsKey: TWSKey, - operation: TWSOperation, - params: TWSParams & { signRequest?: boolean }, - requestFlags?: WSAPIRequestFlags, -): Promise -⋮---- -// if this throws a type error, probably forgot to add a new operation to WsAPITopicRequestParamMap -⋮---- -/** - * Base Info: - * - https://docs.kraken.com/api/docs/websocket-v2/add_order - * - * Currently only supported for Spot markets - */ -⋮---- -// Some commands don't require authentication. -⋮---- -// Sign request -⋮---- -// Store deferred promise -⋮---- -// Enrich returned promise with request context for easier debugging -⋮---- -// Send event -⋮---- -// Return deferred promise, so caller can await this call -⋮---- -/** - * - * Internal methods - not intended for public use - * - */ -⋮---- -private getRestClientOptions(): RestClientOptions -⋮---- -/** - * Note: implementing this method will wipe the WsStore state for this WsKey, once this method returns - */ -protected isCustomReconnectionNeeded(): boolean -⋮---- -protected async triggerCustomReconnectionWorkflow(): Promise -⋮---- -protected async getWsUrl(wsKey: WsKey): Promise -⋮---- -/** - * https://docs.kraken.com/api/docs/guides/spot-ws-intro/ - * - * Note: Kraken's v2 WebSockets clean up a number idiosyncrasies and ambiguities from v1 with the overall aim to enable easier integration with applications. It is intended that v1 will be maintained but future enhancements will be developed in v2. - * - * Given the above, we are only integrating with V2 for now. - * - * V2 SpotWebSocket Reference: https://docs.kraken.com/api/docs/websocket-v2/add_order/ - */ -⋮---- -// Uses the same URL, but we maintain separate connections for easier management -⋮---- -protected sendPingEvent(wsKey: WsKey) -⋮---- -// let pingChannel: WsRequestPing['channel']; -⋮---- -// Spot: https://docs.kraken.com/api/docs/websocket-v2/ping -⋮---- -protected sendPongEvent(wsKey: WsKey) -⋮---- -// Send a protocol layer pong -⋮---- -// NOT IN USE for kraken -// eslint-disable-next-line @typescript-eslint/no-unused-vars -protected isWsPing(_msg: any): boolean -⋮---- -protected isWsPong(msg: any): boolean -⋮---- -// Pre-parsed in resolveEmittableEvents into "pong" eventType: -⋮---- -/** - * Parse incoming events into categories, before emitting to the user - */ -protected resolveEmittableEvents( - wsKey: WsKey, - event: MessageEventLike, -): EmittableEvent[] -⋮---- -// derivatives sends 'challenge' on successful auth-init (used for sign during subscribe) -⋮---- -// spot confirmation for subscription success -⋮---- -// derivatives confirmation for subscription success -⋮---- -// WS API -⋮---- -// WS API Exception -⋮---- -// WS API Success -⋮---- -} // end of WS API response processing -⋮---- -// exceptions with derivatives v1 WS. E.g. { event: 'alert', message: 'Bad websocket message' } -⋮---- -// Most events use event: "update" or "snapshot" for topic updates -⋮---- -// These are request/reply pattern events (e.g. after subscribing to topics or authenticating) -// e.g. "method":"subscribe" -⋮---- -// derivatives events include the "feed" property to identify the channel name -⋮---- -// Request/reply pattern for authentication success -⋮---- -/** - * Determines if a topic is for a private channel, using a hardcoded list of strings - */ -protected isPrivateTopicRequest(request: WSTopicRequest): boolean -⋮---- -/** - * Not in use for Kraken - */ -⋮---- -// eslint-disable-next-line @typescript-eslint/no-unused-vars -protected getWsMarketForWsKey(_wsKey: WsKey): WsMarket -⋮---- -/** - * Whether key represents a private connection. Feeds into automatic auth on connect. - */ -protected getPrivateWSKeys(): WsKey[] -⋮---- -protected isAuthOnConnectWsKey(wsKey: WsKey): boolean -⋮---- -/** Force subscription requests to be sent in smaller batches, if a number is returned */ -// eslint-disable-next-line @typescript-eslint/no-unused-vars -protected getMaxTopicsPerSubscribeEvent(_wsKey: WsKey): number | null -⋮---- -protected authPrivateConnectionsOnConnect(wsKey: WsKey): boolean -⋮---- -// derivatives require you to send a challenge on connect -⋮---- -/** - * @returns one or more correctly structured request events for performing a operations over WS. This can vary per exchange spec. - */ -protected async getWsRequestEvents( - wsKey: WsKey, - operation: WSOperation, - requests: WSTopicRequest[], -): Promise>[]> -⋮---- -// Previously used to track topics in a request. Keeping this for subscribe/unsubscribe requests, no need for incremental values -⋮---- -// Get token from REST client cache -⋮---- -// Cache midflight subs on the req ID -// Enrich response with subs for that req ID -⋮---- -// No auth needed, it's public topics only here -⋮---- -// Cache midflight subs on the req ID -// Enrich response with subs for that req ID -⋮---- -// https://docs.kraken.com/api/docs/guides/futures-websockets -// Authenticated requests must include both the original challenge message (original_challenge) and the signed (signed_challenge) in JSON format. -⋮---- -// Cache midflight subs on the req ID -// Enrich response with subs for that req ID -⋮---- -private async signMessage( - paramsStr: string, - secret: string, - method: SignEncodeMethod, - algorithm: SignAlgorithm, - options?: SignMessageOptions, -): Promise -⋮---- -protected async getWsAuthRequestEvent( - wsKey: WsKey, - eventToAuth?: WSAPIAuthenticationRequestFromServer, -): Promise -⋮---- -// Not needed here, handled automatically with request during subscribe -⋮---- -// Public WS - no auth -⋮---- -// cleanup old challenge key (in case we were reconnected) -⋮---- -// https://docs.kraken.com/api/docs/futures-api/websocket/challenge/ -⋮---- -/** - * - * @param requestEvent - * @returns A signed updated WS API request object, ready to be sent - */ -private async signWSAPIRequest( - requestEvent: WSAPIRequestOperationKrakenSpot, -): Promise -⋮---- -// Get token from REST client cache -⋮---- -// authParams.broker = APIIDMain; - ================ File: src/DerivativesClient.ts ================ @@ -13444,7 +13619,7 @@ File: package.json ================ { "name": "@siebly/kraken-api", - "version": "1.0.6", + "version": "1.0.7", "description": "Complete & robust Node.js SDK for Kraken's REST APIs and WebSockets, with TypeScript & strong end to end tests.", "scripts": { "clean": "rm -rf dist", diff --git a/package-lock.json b/package-lock.json index 4bd1e87..ff5339c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@siebly/kraken-api", - "version": "1.0.6", + "version": "1.0.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@siebly/kraken-api", - "version": "1.0.6", + "version": "1.0.7", "license": "MIT", "dependencies": { "axios": "^1.10.0", diff --git a/package.json b/package.json index ac11096..e0491bb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@siebly/kraken-api", - "version": "1.0.6", + "version": "1.0.7", "description": "Complete & robust Node.js SDK for Kraken's REST APIs and WebSockets, with TypeScript & strong end to end tests.", "scripts": { "clean": "rm -rf dist", diff --git a/src/SpotClient.ts b/src/SpotClient.ts index f3cdf05..3990658 100644 --- a/src/SpotClient.ts +++ b/src/SpotClient.ts @@ -6,12 +6,15 @@ import { OauthUpdateFastApiKeyParams, SpotAccountTransferParams, SpotAmendOrderParams, + SpotGetApiKeyInfoParams, SpotGetAssetPairsParams, SpotGetClosedOrdersParams, SpotGetDepositAddressesParams, SpotGetDepositMethodsParams, SpotGetDepositStatusParams, + SpotGetGroupedBookParams, SpotGetLedgersInfoParams, + SpotGetLevel3Params, SpotGetOHLCParams, SpotGetOpenOrdersParams, SpotGetOpenPositionsParams, @@ -20,6 +23,7 @@ import { SpotGetRecentSpreadsParams, SpotGetRecentTradesParams, SpotGetTradesHistoryParams, + SpotGetTradingVolumeParams, SpotGetWithdrawalAddressesParams, SpotGetWithdrawalInfoParams, SpotGetWithdrawalMethodsParams, @@ -43,6 +47,7 @@ import { OauthGetUserInfoResponse, SpotAccountBalance, SpotAccountTransferResponse, + SpotApiKeyInfo, SpotAssetInfo, SpotAssetPair, SpotAssetTickerInfo, @@ -56,7 +61,9 @@ import { SpotEarnStrategy, SpotExportReportStatus, SpotExtendedBalance, + SpotGroupedBookResponse, SpotLedgersInfoResponse, + SpotLevel3OrderBookResponse, SpotListEarnAllocationsResponse, SpotOHLCResponse, SpotOpenOrdersResponse, @@ -204,6 +211,28 @@ export class SpotClient extends BaseRestClient { return this.get('0/public/Depth', params); } + /** + * Get Grouped Order Book + * + * Aggregates order book volume over a configurable tick grouping. + */ + getGroupedBook( + params: SpotGetGroupedBookParams, + ): Promise> { + return this.get('0/public/GroupedBook', params); + } + + /** + * Get Level 3 Order Book + * + * Individual order-level book data. Requires authentication. + */ + getLevel3OrderBook( + params: SpotGetLevel3Params, + ): Promise> { + return this.postPrivate('0/private/Level3', { body: params }); + } + /** * Get Recent Trades * @@ -243,6 +272,17 @@ export class SpotClient extends BaseRestClient { return this.postPrivate('0/private/Balance', { body: params }); } + /** + * Get API Key Info + * + * Retrieve configuration and usage details for the API key used in the request. + */ + getApiKeyInfo( + params?: SpotGetApiKeyInfoParams, + ): Promise> { + return this.postPrivate('0/private/GetApiKeyInfo', { body: params }); + } + /** * Get Extended Balance * @@ -385,10 +425,9 @@ export class SpotClient extends BaseRestClient { * Returns 30 day USD trading volume and resulting fee schedule for any asset pair(s) provided. * Also use this endpoint (with a Spot API key) to determine Futures fee rates as of 2026-06-22. */ - getTradingVolume(params?: { - pair?: string; - rebase_multiplier?: 'rebased' | 'base'; - }): Promise> { + getTradingVolume( + params?: SpotGetTradingVolumeParams, + ): Promise> { return this.postPrivate('0/private/TradeVolume', { body: params }); } diff --git a/src/types/request/spot.types.ts b/src/types/request/spot.types.ts index 0504911..aa5293d 100644 --- a/src/types/request/spot.types.ts +++ b/src/types/request/spot.types.ts @@ -23,6 +23,36 @@ export interface SpotGetOrderBookParams { asset_class?: 'tokenized_asset'; } +export interface SpotGetGroupedBookParams { + pair: string; + depth?: 10 | 25 | 100 | 250 | 1000; + grouping?: 1 | 5 | 10 | 25 | 50 | 100 | 250 | 500 | 1000; +} + +export interface SpotGetLevel3Params { + pair: string; + depth?: 0 | 10 | 25 | 100 | 250 | 1000; +} + +export interface SpotTradeVolumePairInput { + asset: string; + aclass: + | 'currency' + | 'forex' + | 'equity' + | 'equity_pair' + | 'nft' + | 'derivatives' + | 'tokenized_asset' + | 'futures_contract'; +} + +export interface SpotGetTradingVolumeParams { + pair?: string | SpotTradeVolumePairInput[]; + fee_schedule?: boolean; + rebase_multiplier?: 'rebased' | 'base'; +} + export interface SpotGetRecentTradesParams { pair: string; since?: string; @@ -40,6 +70,10 @@ export interface SpotGetRecentSpreadsParams { * Account Data */ +export interface SpotGetApiKeyInfoParams { + otp?: string; +} + export interface SpotGetOpenOrdersParams { trades?: boolean; userref?: number; diff --git a/src/types/response/spot.types.ts b/src/types/response/spot.types.ts index 0f5a42b..90b31d4 100644 --- a/src/types/response/spot.types.ts +++ b/src/types/response/spot.types.ts @@ -85,6 +85,31 @@ export interface SpotOrderBookResponse { [pairName: string]: SpotOrderBook; } +export interface SpotGroupedBookLevel { + price: string; + qty: string; +} + +export interface SpotGroupedBookResponse { + pair: string; + grouping: number; + bids: SpotGroupedBookLevel[]; + asks: SpotGroupedBookLevel[]; +} + +export interface SpotLevel3OrderEntry { + price: string; + qty: string; + order_id: string; + timestamp: number; +} + +export interface SpotLevel3OrderBookResponse { + pair: string; + bids: SpotLevel3OrderEntry[]; + asks: SpotLevel3OrderEntry[]; +} + // [price, volume, time, buy/sell, market/limit, miscellaneous, trade_id] export type SpotTradeData = [ string, @@ -113,6 +138,7 @@ export interface SpotRecentSpreadsResponse { * Account Data */ +/** @deprecated Kraken deprecated `.F` suffixed balance assets */ export interface SpotAccountBalance { [assetName: string]: string; } @@ -369,15 +395,79 @@ export interface SpotFeeTierInfo { next_volume: string | null; } +export interface SpotTradeVolumeInputs { + domain_spot_volume_30d: string; + domain_futures_volume_30d: string; + domain_assets_on_platform: string; +} + +export interface SpotTradeVolumeFeeScheduleTier { + maker_fee: string; + taker_fee: string; + min_spot_volume?: string | null; + min_futures_volume?: string | null; + min_assets_on_platform?: string | null; + active?: boolean | null; +} + +export interface SpotTradeVolumeFeeSchedule { + pair: string; + class: + | 'currency' + | 'forex' + | 'equity' + | 'equity_pair' + | 'nft' + | 'derivatives' + | 'tokenized_asset' + | 'futures_contract' + | 'volume'; + tiers: SpotTradeVolumeFeeScheduleTier[]; +} + +export interface SpotTradeVolumeSubaccount { + iiban: string; + volume: string; +} + export interface SpotTradeVolume { currency: string; + asset_class?: + | 'currency' + | 'forex' + | 'equity' + | 'equity_pair' + | 'nft' + | 'derivatives' + | 'tokenized_asset' + | 'futures_contract' + | null; volume: string; + inputs: SpotTradeVolumeInputs; fees?: { [pairName: string]: SpotFeeTierInfo; - }; + } | null; fees_maker?: { [pairName: string]: SpotFeeTierInfo; - }; + } | null; + volume_subaccounts?: SpotTradeVolumeSubaccount[]; + schedules?: SpotTradeVolumeFeeSchedule[] | null; +} + +export interface SpotApiKeyInfo { + apiKeyName: string; + apiKey: string; + nonce: string; + nonceWindow: number; + permissions: string[]; + iban: string; + validUntil: string; + queryFrom: string; + queryTo: string; + createdTime: string; + modifiedTime: string; + ipAllowlist: string[]; + lastUsed: string | null; } export interface SpotRequestExportReportResponse { diff --git a/src/types/websockets/ws-subscriptions.ts b/src/types/websockets/ws-subscriptions.ts index 36fe02b..815a5da 100644 --- a/src/types/websockets/ws-subscriptions.ts +++ b/src/types/websockets/ws-subscriptions.ts @@ -46,3 +46,20 @@ export type WSDerivativesTopic = | WSDerivativesPrivateTopic; export type WSTopic = WSSpotTopic | WSDerivativesTopic; + +export interface WSSpotInstrumentSubscribeParams { + execution_venue?: 'international' | 'bitnomial-exchange'; + snapshot?: boolean; +} + +export interface WSSpotExecutionsSubscribeParams { + symbol?: string[]; + snap_trades?: boolean; + snapshot?: boolean; + rebased?: boolean; +} + +export interface WSSpotBalancesSubscribeParams { + snapshot?: boolean; + rebased?: boolean; +}