diff --git a/.gitignore b/.gitignore index 939ccba..b3a2026 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ examples/ts-commerce.ts ts-exchange-priv.ts testfile-cbexch.ts restClientRegex.ts +privaterepotracker.txt diff --git a/README.md b/README.md index 146943d..8c3a81b 100644 --- a/README.md +++ b/README.md @@ -218,18 +218,48 @@ See all clients [here](./src/) for more information on all the functions or the ## WebSockets -TO BE FILLED - All available WebSockets can be used via a shared `WebsocketClient`. The WebSocket client will automatically open/track/manage connections as needed. Each unique connection (one per server URL) is tracked using a WsKey (each WsKey is a string - see [WS_KEY_MAP](src/lib/websocket/websocket-util.ts) for a list of supported values). Any subscribe/unsubscribe events will need to include a WsKey, so the WebSocket client understands which connection the event should be routed to. See examples below or in the [examples](./examples/) folder on GitHub. Data events are emitted from the WebsocketClient via the `update` event, see example below: +#### Public Websocket + ```javascript -const { WebsocketClient } = require('kucoin-api'); +const { WebsocketClient } = require('coinbase-api'); +// public ws client, doesnt need any api keys to run const client = new WebsocketClient(); +``` + +#### Private Websocket + +```javascript +const { WebsocketClient } = require('coinbase-api'); + +// key name & private key, as returned by coinbase when creating your API keys. +// Note: the below example is a dummy key and won't actually work +const advancedTradeCdpAPIKey = { + name: 'organizations/13232211d-d7e2-d7e2-d7e2-d7e2d7e2d7e2/apiKeys/d7e2d7e2-d7e2-d7e2-d7e2-d7e2d7e2d7e2', + privateKey: + '-----BEGIN EC PRIVATE KEY-----\nADFGHmkgnjdfg16k165kuu1kdtyudtyjdtyjytj/ADFGHmkgnjdfg16k165kuu1kdtyudtyjdtyjytj+oAoGCCqGSM49\nAwEHoUQDQgAEhtAep/ADFGHmkgnjdfg16k165kuu1kdtyudtyjdtyjytj+bzduY3iYXEmj/KtCk\nADFGHmkgnjdfg16k165kuu1kdtyudtyjdtyjytj\n-----END EC PRIVATE KEY-----\n', +}; + +const client = new WebsocketClient({ + // Either pass the full JSON object that can be downloaded when creating your API keys + // cdpApiKey: advancedTradeCdpAPIKey, + + // Or use the key name as "apiKey" and private key (WITH the "begin/end EC PRIVATE KEY" comment) as "apiSecret" + apiKey: advancedTradeCdpAPIKey.name, + apiSecret: advancedTradeCdpAPIKey.privateKey, +}); +``` + +#### Listening and subscribing to Websocket events + +```javascript +// add event listeners for websocket clients client.on('open', (data) => { console.log('open: ', data?.wsKey); @@ -237,7 +267,7 @@ client.on('open', (data) => { // Data received client.on('update', (data) => { - console.info('data received: ', JSON.stringify(data)); + console.info(new Date(), 'data received: ', JSON.stringify(data)); }); // Something happened, attempting to reconenct @@ -257,57 +287,89 @@ client.on('close', (data) => { // Reply to a request, e.g. "subscribe"/"unsubscribe"/"authenticate" client.on('response', (data) => { - console.info('response: ', data); + console.info('response: ', JSON.stringify(data, null, 2)); // throw new Error('res?'); }); client.on('exception', (data) => { - console.error('exception: ', { - msg: data.msg, - errno: data.errno, - code: data.code, - syscall: data.syscall, - hostname: data.hostname, - }); + console.error('exception: ', data); }); -try { - // Optional: await a connection to be ready before subscribing (this is not necessary) - // await client.connect('futuresPublicV1'); - +/** + * Use the client subscribe(topic, market) pattern to subscribe to any websocket topic. + * + * You can subscribe to topics one at a time or many in one request. + * + * Topics can be sent as simple strings, if no parameters are required: + */ + +// market data +client.subscribe('heartbeats', 'advTradeMarketData'); + +// user data +client.subscribe('futures_balance_summary', 'advTradeUserData'); +client.subscribe('user', 'advTradeUserData'); + +/** + * Or send a more structured object with parameters, e.g. if parameters are required + */ +const tickerSubscribeRequst = { + topic: 'ticker', /** - * Examples for public futures websocket topics (that don't require authentication). - * - * These should all subscribe via the "futuresPublicV1" wsKey. For detailed usage, refer to the ws-spot-public.ts example. + * Anything in the payload will be merged into the subscribe "request", + * allowing you to send misc parameters supported by the exchange (such as `product_ids: string[]`) */ - client.subscribe( - [ - '/contractMarket/tickerV2:XBTUSDM', - '/contractMarket/ticker:XBTUSDM', - '/contractMarket/level2:XBTUSDM', - '/contractMarket/execution:XBTUSDM', - '/contractMarket/level2Depth5:XBTUSDM', - '/contractMarket/level2Depth50:XBTUSDM', - '/contractMarket/limitCandle:XBTUSDTM_1hour', - '/contract/instrument:XBTUSDM', - '/contract/announcement', - '/contractMarket/snapshot:XBTUSDM', - ], - 'futuresPublicV1', - ); -} catch (e) { - console.error(`Subscribe exception: `, e); -} + payload: { + product_ids: ['ETH-USD', 'BTC-USD'], + }, +}; +client.subscribe(tickerSubscribeRequst, 'advTradeMarketData'); + +// Other adv trade public websocket topics: + +client.subscribe( + [ + { + topic: 'candles', + payload: { + product_ids: ['ETH-USD'], + }, + }, + { + topic: 'market_trades', + payload: { + product_ids: ['ETH-USD', 'BTC-USD'], + }, + }, + { + topic: 'ticker', + payload: { + product_ids: ['ETH-USD', 'BTC-USD'], + }, + }, + { + topic: 'ticker_batch', + payload: { + product_ids: ['ETH-USD', 'BTC-USD'], + }, + }, + { + topic: 'level2', + payload: { + product_ids: ['ETH-USD', 'BTC-USD'], + }, + }, + ], + 'advTradeMarketData', +); ``` -See [WebsocketClient](./src/WebsocketClient.ts) for further information and make sure to check the [examples](./examples/) folder for much more detail, especially [ws-spot-public.ts](./examples/ws-spot-public.ts), which explains a lot of detail. +See [WebsocketClient](./src/WebsocketClient.ts) for further information and make sure to check the [examples](./examples/) folder for much more usage examples, especially [publicWs.ts](./examples/AdvancedTrade/WebSockets/publicWs.ts) and [privateWs.ts](./examples/AdvancedTrade/WebSockets/privateWs.ts), which explains a lot of small details. --- ## Customise Logging -TO BE FILLED - Pass a custom logger which supports the log methods `trace`, `info` and `error`, or override methods from the default logger as desired. ```javascript diff --git a/examples/AdvancedTrade/WebSockets/privateWs.ts b/examples/AdvancedTrade/WebSockets/privateWs.ts index f907c88..1fc5256 100644 --- a/examples/AdvancedTrade/WebSockets/privateWs.ts +++ b/examples/AdvancedTrade/WebSockets/privateWs.ts @@ -74,13 +74,7 @@ async function start() { }); client.on('exception', (data) => { - console.error('exception: ', { - msg: data.msg, - errno: data.errno, - code: data.code, - syscall: data.syscall, - hostname: data.hostname, - }); + console.error('exception: ', data); }); try { diff --git a/examples/AdvancedTrade/WebSockets/publicWs.ts b/examples/AdvancedTrade/WebSockets/publicWs.ts index 0c7851c..45572bb 100644 --- a/examples/AdvancedTrade/WebSockets/publicWs.ts +++ b/examples/AdvancedTrade/WebSockets/publicWs.ts @@ -57,13 +57,7 @@ async function start() { }); client.on('exception', (data) => { - console.error('exception: ', { - msg: data.msg, - errno: data.errno, - code: data.code, - syscall: data.syscall, - hostname: data.hostname, - }); + console.error('exception: ', data); }); try { diff --git a/examples/CBExchange/cb-exchange-public.ts b/examples/CBExchange/cb-exchange-public.ts index 1f7f180..e000235 100644 --- a/examples/CBExchange/cb-exchange-public.ts +++ b/examples/CBExchange/cb-exchange-public.ts @@ -1,4 +1,4 @@ -import { CBExchangeClient } from '../../src/CBExchangeClient.js'; +import { CBExchangeClient } from '../../src/index.js'; // import { CBExchangeClient } from 'coinbase-api'; // Initialize the client, you can pass in api keys here if you have them but they are not required for public endpoints diff --git a/examples/CBInternationalExchange/cb-intx-public.ts b/examples/CBInternationalExchange/cb-intx-public.ts index a3b47ba..68fb058 100644 --- a/examples/CBInternationalExchange/cb-intx-public.ts +++ b/examples/CBInternationalExchange/cb-intx-public.ts @@ -1,4 +1,4 @@ -import { CBInternationalClient } from '../../src/CBInternationalClient.js'; +import { CBInternationalClient } from '../../src/index.js'; // import { CBInternationalClient } from 'coinbase-api'; // Initialize the client, you can pass in api keys here if you have them but they are not required for public endpoints diff --git a/test/CBExchangeClient/private.test.ts b/test/CBExchangeClient/private.test.ts index b1703d5..960d96e 100644 --- a/test/CBExchangeClient/private.test.ts +++ b/test/CBExchangeClient/private.test.ts @@ -46,30 +46,9 @@ describe('CBExchangeClient PRIVATE', () => { }); test('with params', async () => { - const res = await rest.submitOrder({ - product_id: 'BTC-GBP', - price: '1000', - side: 'buy', - type: 'limit', - size: '0.001', - }); + const res = await rest.getTransfers({ type: 'deposit' }); console.log('res with params', res); - expect(res).toMatchObject({ - id: expect.any(String), - price: expect.any(String), - size: expect.any(String), - product_id: expect.any(String), - side: expect.any(String), - type: expect.any(String), - time_in_force: expect.any(String), - post_only: expect.any(Boolean), - created_at: expect.any(String), - fill_fees: expect.any(String), - filled_size: expect.any(String), - executed_value: expect.any(String), - status: expect.any(String), - settled: expect.any(Boolean), - }); + expect(res).toEqual(expect.arrayContaining([expect.any(Object)])); }); });