@pipsend/sdk 0.3.0 โ†’ 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -36,12 +36,12 @@ pnpm add @pipsend/sdk
36
36
  The SDK uses JWT-based authentication with automatic token refresh.
37
37
 
38
38
  ```typescript
39
- import { createClient } from '@pipsend/sdk';
39
+ import { createClient } from "@pipsend/sdk";
40
40
 
41
41
  const client = createClient({
42
- server: 'http://localhost:8080',
43
- login: '1000', // Your admin/API login
44
- password: 'YourPassword' // Your admin/API password
42
+ server: "http://localhost:8080",
43
+ login: "1000", // Your admin/API login
44
+ password: "YourPassword", // Your admin/API password
45
45
  });
46
46
 
47
47
  // The SDK automatically:
@@ -69,7 +69,7 @@ await client.logout();
69
69
 
70
70
  // Get current token info
71
71
  const tokenInfo = client.getTokenInfo();
72
- console.log('Token expires at:', tokenInfo?.expiresAt);
72
+ console.log("Token expires at:", tokenInfo?.expiresAt);
73
73
  ```
74
74
 
75
75
  ---
@@ -77,45 +77,45 @@ console.log('Token expires at:', tokenInfo?.expiresAt);
77
77
  ## ๐Ÿ”ง Quick Start
78
78
 
79
79
  ```typescript
80
- import { createClient } from '@pipsend/sdk';
80
+ import { createClient } from "@pipsend/sdk";
81
81
 
82
82
  // Create authenticated client
83
83
  const client = createClient({
84
- server: 'http://localhost:8080',
85
- login: '1000',
86
- password: 'DemoMaster'
84
+ server: "http://localhost:8080",
85
+ login: "1000",
86
+ password: "DemoMaster",
87
87
  });
88
88
 
89
89
  const login = 50001;
90
90
 
91
91
  // List accounts with filters
92
92
  const accounts = await client.accounts.list({
93
- state: 'active',
94
- country: 'Mexico',
95
- min_balance: 1000
93
+ state: "active",
94
+ country: "Mexico",
95
+ min_balance: 1000,
96
96
  });
97
97
 
98
98
  // Open a trade
99
99
  const trade = await client.trades.open({
100
100
  login,
101
- symbol: 'EURUSD',
102
- action: 'buy',
103
- type: 'market',
101
+ symbol: "EURUSD",
102
+ action: "buy",
103
+ type: "market",
104
104
  volume: 1.0,
105
- stop_loss: 1.0850,
106
- take_profit: 1.0950
105
+ stop_loss: 1.085,
106
+ take_profit: 1.095,
107
107
  });
108
108
 
109
109
  // Get market data
110
110
  const candles = await client.marketData.getCandles({
111
- symbol: 'BTCUSD',
112
- timeframe: '1h',
113
- limit: 100
111
+ symbol: "BTCUSD",
112
+ timeframe: "1h",
113
+ limit: 100,
114
114
  });
115
115
 
116
116
  // WebSocket real-time updates
117
117
  client.stream.onPriceUpdate((price) => {
118
- console.log('Price update:', price);
118
+ console.log("Price update:", price);
119
119
  });
120
120
 
121
121
  await client.stream.connect();
@@ -130,32 +130,32 @@ Manage accounts with advanced filtering and statistics.
130
130
  ```typescript
131
131
  // Create a new trading account
132
132
  const newAccount = await client.accounts.create({
133
- trading_group: 'Premium',
134
- country: 'MX',
135
- master_password: 'SecurePass123!',
136
- investor_password: 'InvestorPass123!',
137
- email: 'trader@example.com',
138
- first_name: 'John',
139
- last_name: 'Doe',
133
+ trading_group: "Premium",
134
+ country: "MX",
135
+ master_password: "SecurePass123!",
136
+ investor_password: "InvestorPass123!",
137
+ email: "trader@example.com",
138
+ first_name: "John",
139
+ last_name: "Doe",
140
140
  leverage: 100,
141
- state: 'active'
141
+ state: "active",
142
142
  });
143
143
 
144
144
  // List accounts with filters
145
145
  const accounts = await client.accounts.list({
146
- state: 'active',
147
- country: 'Mexico,United States',
148
- trading_group: 'Premium',
146
+ state: "active",
147
+ country: "Mexico,United States",
148
+ trading_group: "Premium",
149
149
  min_balance: 1000,
150
150
  max_balance: 50000,
151
151
  page: 1,
152
- per_page: 20
152
+ per_page: 20,
153
153
  });
154
154
 
155
155
  // Get statistics with filters
156
156
  const stats = await client.accounts.getStatistics({
157
- country: 'Mexico',
158
- state: 'active'
157
+ country: "Mexico",
158
+ state: "active",
159
159
  });
160
160
 
161
161
  // Get all account logins
@@ -163,18 +163,15 @@ const logins = await client.accounts.getLogins();
163
163
 
164
164
  // Get account status/metrics (balance, equity, credit, margin)
165
165
  const status = await client.accounts.getStatus(50001);
166
- console.log('Balance:', status.data.balance);
167
- console.log('Equity:', status.data.equity);
168
- console.log('Credit:', status.data.credit);
169
- console.log('Margin:', status.data.margin);
166
+ console.log("Balance:", status.data.balance);
167
+ console.log("Equity:", status.data.equity);
168
+ console.log("Credit:", status.data.credit);
169
+ console.log("Margin:", status.data.margin);
170
170
 
171
- // Change passwords
172
- await client.accounts.changeMasterPassword(50001, {
173
- new_password: 'NewPass123!'
174
- });
175
-
176
- await client.accounts.changeInvestorPassword(50001, {
177
- new_password: 'InvestorPass123!'
171
+ // Change passwords (master and/or investor)
172
+ await client.accounts.changePassword(50001, {
173
+ master: "NewMasterPass123!",
174
+ investor: "NewInvestorPass123!",
178
175
  });
179
176
 
180
177
  // Archive/Unarchive
@@ -183,30 +180,30 @@ await client.accounts.unarchive(50001);
183
180
 
184
181
  // Update account information (partial update)
185
182
  await client.accounts.update(50001, {
186
- email: 'newemail@example.com',
183
+ email: "newemail@example.com",
187
184
  leverage: 200,
188
- city: 'Los Angeles',
189
- trading_group: 'Premium'
185
+ city: "Los Angeles",
186
+ trading_group: "Premium",
190
187
  });
191
188
 
192
189
  // Adjust balance or credit
193
190
  await client.accounts.balance(50001, {
194
- type: 'balance',
195
- amount: 500.00,
196
- comment: 'Client deposit'
191
+ type: "balance",
192
+ amount: 500.0,
193
+ comment: "Client deposit",
197
194
  });
198
195
 
199
196
  await client.accounts.balance(50001, {
200
- type: 'credit',
201
- amount: 1000.00,
202
- comment: 'Credit line increase'
197
+ type: "credit",
198
+ amount: 1000.0,
199
+ comment: "Credit line increase",
203
200
  });
204
201
 
205
202
  // Subtract balance
206
203
  await client.accounts.balance(50001, {
207
- type: 'balance',
208
- amount: -200.00,
209
- comment: 'Withdrawal request'
204
+ type: "balance",
205
+ amount: -200.0,
206
+ comment: "Withdrawal request",
210
207
  });
211
208
  ```
212
209
 
@@ -217,35 +214,35 @@ Manage pending orders with statistics and validation.
217
214
  ```typescript
218
215
  // List orders with advanced filters
219
216
  const orders = await client.orders.list({
220
- login: '50001',
221
- symbol: 'EURUSD,GBPUSD',
222
- order_type: 'limit',
223
- status: 'new,partial',
224
- created_from: '2025-01-01T00:00:00Z',
225
- created_to: '2025-01-31T23:59:59Z',
217
+ login: "50001",
218
+ symbol: "EURUSD,GBPUSD",
219
+ order_type: "limit",
220
+ status: "new,partial",
221
+ created_from: "2025-01-01T00:00:00Z",
222
+ created_to: "2025-01-31T23:59:59Z",
226
223
  price_min: 1.08,
227
- price_max: 1.10,
228
- sort_by: 'created_at',
229
- sort_order: 'desc'
224
+ price_max: 1.1,
225
+ sort_by: "created_at",
226
+ sort_order: "desc",
230
227
  });
231
228
 
232
229
  // Get statistics grouped by symbol
233
230
  const stats = await client.orders.getStats({
234
- login: '50001',
235
- group_by: 'symbol'
231
+ login: "50001",
232
+ group_by: "symbol",
236
233
  });
237
234
 
238
235
  // Get totals by order type
239
236
  const totals = await client.orders.getTotals({
240
- login: '50001',
241
- group_by: 'order_type'
237
+ login: "50001",
238
+ group_by: "order_type",
242
239
  });
243
240
 
244
241
  // Update order
245
242
  await client.orders.update(12345, {
246
243
  login: 50001,
247
- stop_loss: 1.0800,
248
- take_profit: 1.0950
244
+ stop_loss: 1.08,
245
+ take_profit: 1.095,
249
246
  });
250
247
 
251
248
  // Delete order
@@ -255,8 +252,8 @@ await client.orders.delete(12345, { login: 50001 });
255
252
  const checkResult = await client.orders.check({
256
253
  filters: {
257
254
  logins: [50001],
258
- statuses: ['new']
259
- }
255
+ statuses: ["new"],
256
+ },
260
257
  });
261
258
  ```
262
259
 
@@ -267,31 +264,31 @@ Manage open positions with recalculation support.
267
264
  ```typescript
268
265
  // List positions with filters
269
266
  const positions = await client.positions.list({
270
- login: '50001',
271
- symbol: 'EURUSD',
272
- state: 'open',
267
+ login: "50001",
268
+ symbol: "EURUSD",
269
+ state: "open",
273
270
  profit_min: 100,
274
- profit_max: 1000
271
+ profit_max: 1000,
275
272
  });
276
273
 
277
274
  // Get statistics grouped by type
278
275
  const stats = await client.positions.getStats({
279
- login: '50001',
280
- state: 'open',
281
- group_by: 'type'
276
+ login: "50001",
277
+ state: "open",
278
+ group_by: "type",
282
279
  });
283
280
 
284
281
  // Get totals by symbol
285
282
  const totals = await client.positions.getTotals({
286
- login: '50001',
287
- group_by: 'symbol'
283
+ login: "50001",
284
+ group_by: "symbol",
288
285
  });
289
286
 
290
287
  // Update position
291
288
  await client.positions.update(1, {
292
289
  login: 50001,
293
290
  stop_loss: 1.0875,
294
- take_profit: 1.0975
291
+ take_profit: 1.0975,
295
292
  });
296
293
 
297
294
  // Delete position
@@ -301,8 +298,8 @@ await client.positions.delete(1, { login: 50001 });
301
298
  const checkResult = await client.positions.check({
302
299
  filters: {
303
300
  logins: [50001],
304
- states: ['open']
305
- }
301
+ states: ["open"],
302
+ },
306
303
  });
307
304
  ```
308
305
 
@@ -314,22 +311,22 @@ Execute trading operations with margin checking.
314
311
  // Check margin before trading
315
312
  const marginCheck = await client.trades.checkMargin({
316
313
  login: 50001,
317
- symbol: 'EURUSD',
318
- action: 'buy',
319
- volume: 1.0
314
+ symbol: "EURUSD",
315
+ action: "buy",
316
+ volume: 1.0,
320
317
  });
321
318
 
322
319
  if (marginCheck.can_execute) {
323
320
  // Open trade
324
321
  const trade = await client.trades.open({
325
322
  login: 50001,
326
- symbol: 'EURUSD',
327
- action: 'buy',
328
- type: 'market',
323
+ symbol: "EURUSD",
324
+ action: "buy",
325
+ type: "market",
329
326
  volume: 1.0,
330
- stop_loss: 1.0850,
331
- take_profit: 1.0950,
332
- comment: 'API Trade'
327
+ stop_loss: 1.085,
328
+ take_profit: 1.095,
329
+ comment: "API Trade",
333
330
  });
334
331
 
335
332
  // Modify trade
@@ -337,17 +334,17 @@ if (marginCheck.can_execute) {
337
334
  login: 50001,
338
335
  position_id: trade.position_id,
339
336
  stop_loss: 1.0875,
340
- take_profit: 1.0975
337
+ take_profit: 1.0975,
341
338
  });
342
339
 
343
340
  // Calculate potential profit
344
341
  const profitCalc = await client.trades.calculateProfit({
345
342
  login: 50001,
346
- symbol: 'EURUSD',
347
- action: 'buy',
343
+ symbol: "EURUSD",
344
+ action: "buy",
348
345
  volume: 1.0,
349
- open_price: 1.0900,
350
- close_price: 1.0950
346
+ open_price: 1.09,
347
+ close_price: 1.095,
351
348
  });
352
349
 
353
350
  // Close trade (partial or full)
@@ -355,20 +352,20 @@ if (marginCheck.can_execute) {
355
352
  login: 50001,
356
353
  position_id: trade.position_id,
357
354
  volume: 0.5, // Partial close
358
- comment: 'Taking profit'
355
+ comment: "Taking profit",
359
356
  });
360
357
  }
361
358
 
362
359
  // Force price (for historical data import)
363
360
  const historicalTrade = await client.trades.open({
364
361
  login: 50001,
365
- symbol: 'EURUSD',
366
- action: 'buy',
367
- type: 'market',
362
+ symbol: "EURUSD",
363
+ action: "buy",
364
+ type: "market",
368
365
  volume: 1.0,
369
- price: 1.0850,
366
+ price: 1.085,
370
367
  force_price: true,
371
- force_timestamp: '2025-01-15T10:30:00Z'
368
+ force_timestamp: "2025-01-15T10:30:00Z",
372
369
  });
373
370
  ```
374
371
 
@@ -379,37 +376,37 @@ Query historical market data (minimum 1 hour old).
379
376
  ```typescript
380
377
  // Get candles with filters
381
378
  const candles = await client.marketData.getCandles({
382
- symbol: 'BTCUSD,ETHUSD',
383
- timeframe: '1h',
384
- from: '2025-01-01T00:00:00Z',
385
- to: '2025-01-02T00:00:00Z',
379
+ symbol: "BTCUSD,ETHUSD",
380
+ timeframe: "1h",
381
+ from: "2025-01-01T00:00:00Z",
382
+ to: "2025-01-02T00:00:00Z",
386
383
  min_volume: 1000,
387
384
  max_volume: 50000,
388
- sort: 'volume',
389
- order: 'desc',
390
- limit: 100
385
+ sort: "volume",
386
+ order: "desc",
387
+ limit: 100,
391
388
  });
392
389
 
393
390
  // Get last 100 candles
394
391
  const recentCandles = await client.marketData.getCandles({
395
- symbol: 'BTCUSD',
396
- timeframe: '1m',
392
+ symbol: "BTCUSD",
393
+ timeframe: "1m",
397
394
  limit: 100,
398
- order: 'desc'
395
+ order: "desc",
399
396
  });
400
397
 
401
398
  // Get symbols with filters
402
399
  const symbols = await client.marketData.getSymbols({
403
- group: 'CRYPTO_MAJOR',
400
+ group: "CRYPTO_MAJOR",
404
401
  has_data: true,
405
- search: 'bitcoin'
402
+ search: "bitcoin",
406
403
  });
407
404
 
408
405
  // Get groups hierarchy
409
406
  const groups = await client.marketData.getGroups({
410
407
  root_only: true,
411
- sort: 'symbol_count',
412
- order: 'desc'
408
+ sort: "symbol_count",
409
+ order: "desc",
413
410
  });
414
411
  ```
415
412
 
@@ -425,7 +422,7 @@ Manage trading groups and their statistics.
425
422
  // List trading groups
426
423
  const groups = await client.tradingGroups.list({
427
424
  page: 1,
428
- per_page: 20
425
+ per_page: 20,
429
426
  });
430
427
 
431
428
  // Get statistics
@@ -439,13 +436,13 @@ Real-time updates for positions and balance with manual channel subscription.
439
436
  ```typescript
440
437
  // Enable WebSocket in config
441
438
  const client = createClient({
442
- server: 'http://localhost:8080',
443
- login: '1000',
444
- password: 'DemoMaster',
439
+ server: "http://localhost:8080",
440
+ login: "1000",
441
+ password: "DemoMaster",
445
442
  websocket: {
446
443
  enabled: true,
447
- autoConnect: false
448
- }
444
+ autoConnect: false,
445
+ },
449
446
  });
450
447
 
451
448
  // Connect to WebSocket
@@ -453,49 +450,56 @@ await client.stream.connect();
453
450
 
454
451
  // Subscribe to channels
455
452
  client.stream.subscribe([
456
- 'positions:new', // New positions opened
457
- 'positions:closed', // Positions closed (total and partial)
458
- 'positions:updated', // Position PnL updates (throttled to 1 per 2s)
459
- 'accounts:balance' // Balance updates
453
+ "positions:new", // New positions opened
454
+ "positions:closed", // Positions closed (total and partial)
455
+ "positions:updated", // Position PnL updates (throttled to 1 per 2s)
456
+ "accounts:balance", // Balance updates
460
457
  ]);
461
458
 
462
459
  // Listen to position opened events
463
460
  client.stream.onPositionOpened((event) => {
464
461
  const pos = event.position;
465
- console.log('Position opened:', pos.symbol, pos.side === 1 ? 'LONG' : 'SHORT', pos.qty);
462
+ console.log(
463
+ "Position opened:",
464
+ pos.symbol,
465
+ pos.side === 1 ? "LONG" : "SHORT",
466
+ pos.qty,
467
+ );
466
468
  });
467
469
 
468
470
  // Listen to position closed events
469
471
  client.stream.onPositionClosed((event) => {
470
472
  const pos = event.position;
471
- console.log('Position closed:', pos.symbol, 'PnL:', pos.net_pnl);
473
+ console.log("Position closed:", pos.symbol, "PnL:", pos.net_pnl);
472
474
  });
473
475
 
474
476
  // Listen to position updated events (throttled)
475
477
  client.stream.onPositionUpdated((event) => {
476
478
  const pos = event.position;
477
- console.log('Position update:', pos.position_id, 'PnL:', pos.unrealized_pnl);
479
+ console.log("Position update:", pos.position_id, "PnL:", pos.unrealized_pnl);
478
480
  });
479
481
 
480
482
  // Listen to balance updates
481
483
  client.stream.onBalanceUpdated((event) => {
482
- console.log('Balance:', event.balance, 'Equity:', event.equity);
484
+ console.log("Balance:", event.balance, "Equity:", event.equity);
483
485
  });
484
486
 
485
487
  // Unsubscribe from channels
486
- client.stream.unsubscribe(['positions:updated']);
488
+ client.stream.unsubscribe(["positions:updated"]);
487
489
 
488
490
  // Disconnect
489
491
  client.stream.disconnect();
490
492
  ```
491
493
 
492
494
  **Available Channels**:
495
+
493
496
  - `positions:new` - New position opened
494
497
  - `positions:closed` - Position closed (total or partial)
495
498
  - `positions:updated` - PnL updates (throttled to max 1 per 2 seconds)
496
499
  - `accounts:balance` - Balance changes
497
500
 
498
501
  **Features**:
502
+
499
503
  - Manual subscription to specific channels
500
504
  - Auto-reconnect with exponential backoff
501
505
  - Heartbeat/ping-pong mechanism
@@ -504,15 +508,21 @@ client.stream.disconnect();
504
508
 
505
509
  See [WebSocket API Documentation](docs/WEBSOCKET_API.md) for complete guide.
506
510
 
507
- ## ๐Ÿ”ง Configuration
511
+ ## ๏ฟฝ Documentation
512
+
513
+ - **[Positions & Trading Guide](docs/POSITIONS_TRADING.md)** - Complete guide for opening, closing, and modifying positions (SL/TP)
514
+ - **[WebSocket API](docs/WEBSOCKET_API.md)** - Real-time updates and streaming data
515
+ - **[Authentication](AUTHENTICATION.md)** - Authentication system and token management
516
+
517
+ ## ๏ฟฝ๐Ÿ”ง Configuration
508
518
 
509
519
  ### Basic Configuration
510
520
 
511
521
  ```typescript
512
522
  const client = createClient({
513
- server: 'http://localhost:8080', // Required: API server URL
514
- login: '1000', // Required: Admin/API login
515
- password: 'YourPassword' // Required: Admin/API password
523
+ server: "http://localhost:8080", // Required: API server URL
524
+ login: "1000", // Required: Admin/API login
525
+ password: "YourPassword", // Required: Admin/API password
516
526
  });
517
527
  ```
518
528
 
@@ -520,39 +530,40 @@ const client = createClient({
520
530
 
521
531
  ```typescript
522
532
  const client = createClient({
523
- server: 'http://localhost:8080',
524
- login: '1000',
525
- password: 'YourPassword',
526
-
533
+ server: "http://localhost:8080",
534
+ login: "1000",
535
+ password: "YourPassword",
536
+
527
537
  // WebSocket configuration (optional)
528
538
  websocket: {
529
- enabled: true, // Enable WebSocket support
530
- autoConnect: false, // Auto-connect on client creation
531
- autoReconnect: true, // Auto-reconnect on disconnect
532
- maxReconnectAttempts: 5, // Max reconnection attempts
533
- heartbeatInterval: 30000 // Heartbeat interval in ms
534
- }
539
+ enabled: true, // Enable WebSocket support
540
+ autoConnect: false, // Auto-connect on client creation
541
+ autoReconnect: true, // Auto-reconnect on disconnect
542
+ maxReconnectAttempts: 5, // Max reconnection attempts
543
+ heartbeatInterval: 30000, // Heartbeat interval in ms
544
+ },
535
545
  });
536
546
  ```
537
547
 
538
548
  ### Configuration Options
539
549
 
540
- | Option | Type | Required | Default | Description |
541
- |--------|------|----------|---------|-------------|
542
- | `server` | string | โœ… Yes | - | Pipsend API server URL |
543
- | `login` | string | โœ… Yes | - | Admin/API login for authentication |
544
- | `password` | string | โœ… Yes | - | Admin/API password |
545
- | `websocket.enabled` | boolean | No | `false` | Enable WebSocket support |
546
- | `websocket.autoConnect` | boolean | No | `false` | Auto-connect on creation |
547
- | `websocket.autoReconnect` | boolean | No | `true` | Auto-reconnect on disconnect |
548
- | `websocket.maxReconnectAttempts` | number | No | `5` | Max reconnection attempts |
549
- | `websocket.heartbeatInterval` | number | No | `30000` | Heartbeat interval (ms) |
550
+ | Option | Type | Required | Default | Description |
551
+ | -------------------------------- | ------- | -------- | ------- | ---------------------------------- |
552
+ | `server` | string | โœ… Yes | - | Pipsend API server URL |
553
+ | `login` | string | โœ… Yes | - | Admin/API login for authentication |
554
+ | `password` | string | โœ… Yes | - | Admin/API password |
555
+ | `websocket.enabled` | boolean | No | `false` | Enable WebSocket support |
556
+ | `websocket.autoConnect` | boolean | No | `false` | Auto-connect on creation |
557
+ | `websocket.autoReconnect` | boolean | No | `true` | Auto-reconnect on disconnect |
558
+ | `websocket.maxReconnectAttempts` | number | No | `5` | Max reconnection attempts |
559
+ | `websocket.heartbeatInterval` | number | No | `30000` | Heartbeat interval (ms) |
550
560
 
551
561
  ## ๐Ÿ“ฆ API Response Structure
552
562
 
553
563
  All API endpoints return a consistent response structure:
554
564
 
555
565
  ### Success Response (without pagination)
566
+
556
567
  ```typescript
557
568
  {
558
569
  status: "success",
@@ -562,6 +573,7 @@ All API endpoints return a consistent response structure:
562
573
  ```
563
574
 
564
575
  ### Success Response (with pagination)
576
+
565
577
  ```typescript
566
578
  {
567
579
  status: "success",
@@ -579,6 +591,7 @@ All API endpoints return a consistent response structure:
579
591
  ```
580
592
 
581
593
  ### Error Response
594
+
582
595
  ```typescript
583
596
  {
584
597
  status: "error",
@@ -596,10 +609,12 @@ All API endpoints return a consistent response structure:
596
609
  ### Common Status Codes
597
610
 
598
611
  **Success:**
612
+
599
613
  - `SUCCESS` - Operation successful
600
614
  - `CREATED` - Resource created successfully
601
615
 
602
616
  **Errors:**
617
+
603
618
  - `VALIDATION_ERROR` (400) - Invalid parameters
604
619
  - `BAD_REQUEST` (400) - Invalid request
605
620
  - `UNAUTHORIZED` (401) - Authentication required
@@ -609,6 +624,7 @@ All API endpoints return a consistent response structure:
609
624
  - `INTERNAL_ERROR` (500) - Server error
610
625
 
611
626
  **Market Data Specific:**
627
+
612
628
  - `SYMBOL_NOT_FOUND` (404) - Symbol not found
613
629
  - `INVALID_TIMEFRAME` (400) - Invalid timeframe
614
630
  - `TIME_RANGE_TOO_LARGE` (400) - Time range exceeds maximum
@@ -619,21 +635,23 @@ All API endpoints return a consistent response structure:
619
635
  ### Pagination
620
636
 
621
637
  **Option 1: Get all results (no pagination)**
638
+
622
639
  ```typescript
623
640
  // Returns all results in a single array
624
641
  const accounts = await client.accounts.list({
625
- state: 'active'
642
+ state: "active",
626
643
  });
627
644
  // Response: { status, status_code, data: [...] }
628
645
  ```
629
646
 
630
647
  **Option 2: Paginated results**
648
+
631
649
  ```typescript
632
650
  // Returns paginated results with metadata
633
651
  const accounts = await client.accounts.list({
634
- state: 'active',
652
+ state: "active",
635
653
  page: 1,
636
- per_page: 20
654
+ per_page: 20,
637
655
  });
638
656
  // Response: { status, status_code, data: [...], meta: {...} }
639
657
 
@@ -643,26 +661,27 @@ let hasMore = true;
643
661
 
644
662
  while (hasMore) {
645
663
  const response = await client.accounts.list({
646
- state: 'active',
664
+ state: "active",
647
665
  page,
648
- per_page: 50
666
+ per_page: 50,
649
667
  });
650
-
668
+
651
669
  // Process response.data
652
670
  console.log(`Page ${page}:`, response.data.length);
653
-
671
+
654
672
  hasMore = response.meta.has_next;
655
673
  page++;
656
674
  }
657
675
  ```
658
676
 
659
677
  **Option 3: Limit results (ignores pagination)**
678
+
660
679
  ```typescript
661
680
  // Get specific number of results
662
681
  const candles = await client.marketData.getCandles({
663
- symbol: 'BTCUSD',
664
- timeframe: '1h',
665
- limit: 100 // Max: 10,000 for candles
682
+ symbol: "BTCUSD",
683
+ timeframe: "1h",
684
+ limit: 100, // Max: 10,000 for candles
666
685
  });
667
686
  ```
668
687
 
@@ -673,17 +692,17 @@ Many filters accept comma-separated values:
673
692
  ```typescript
674
693
  // Multiple symbols (OR logic)
675
694
  const positions = await client.positions.list({
676
- symbol: 'EURUSD,GBPUSD,USDJPY' // Positions in ANY of these symbols
695
+ symbol: "EURUSD,GBPUSD,USDJPY", // Positions in ANY of these symbols
677
696
  });
678
697
 
679
698
  // Multiple countries
680
699
  const accounts = await client.accounts.list({
681
- country: 'Mexico,United States,Canada'
700
+ country: "Mexico,United States,Canada",
682
701
  });
683
702
 
684
703
  // Multiple states
685
704
  const orders = await client.orders.list({
686
- status: 'new,partial' // Orders with status new OR partial
705
+ status: "new,partial", // Orders with status new OR partial
687
706
  });
688
707
  ```
689
708
 
@@ -694,16 +713,16 @@ All date parameters must be in **ISO 8601 / RFC3339 format** (UTC):
694
713
  ```typescript
695
714
  // Correct format
696
715
  const positions = await client.positions.list({
697
- opened_from: '2025-01-01T00:00:00Z',
698
- opened_to: '2025-01-31T23:59:59Z'
716
+ opened_from: "2025-01-01T00:00:00Z",
717
+ opened_to: "2025-01-31T23:59:59Z",
699
718
  });
700
719
 
701
720
  // Also valid
702
721
  const candles = await client.marketData.getCandles({
703
- symbol: 'BTCUSD',
704
- timeframe: '1h',
705
- from: '2025-01-15T10:30:00Z',
706
- to: '2025-01-15T18:30:00Z'
722
+ symbol: "BTCUSD",
723
+ timeframe: "1h",
724
+ from: "2025-01-15T10:30:00Z",
725
+ to: "2025-01-15T18:30:00Z",
707
726
  });
708
727
  ```
709
728
 
@@ -717,21 +736,21 @@ Use `min_*` and `max_*` for numeric ranges:
717
736
  // Balance range
718
737
  const accounts = await client.accounts.list({
719
738
  min_balance: 1000,
720
- max_balance: 50000
739
+ max_balance: 50000,
721
740
  });
722
741
 
723
742
  // Profit range
724
743
  const positions = await client.positions.list({
725
744
  profit_min: 100,
726
- profit_max: 1000
745
+ profit_max: 1000,
727
746
  });
728
747
 
729
748
  // Volume range
730
749
  const candles = await client.marketData.getCandles({
731
- symbol: 'BTCUSD',
732
- timeframe: '1h',
750
+ symbol: "BTCUSD",
751
+ timeframe: "1h",
733
752
  min_volume: 1000,
734
- max_volume: 50000
753
+ max_volume: 50000,
735
754
  });
736
755
  ```
737
756
 
@@ -741,16 +760,16 @@ Most list endpoints support sorting:
741
760
 
742
761
  ```typescript
743
762
  const orders = await client.orders.list({
744
- login: '50001',
745
- sort_by: 'created_at', // Field to sort by
746
- sort_order: 'desc' // 'asc' or 'desc'
763
+ login: "50001",
764
+ sort_by: "created_at", // Field to sort by
765
+ sort_order: "desc", // 'asc' or 'desc'
747
766
  });
748
767
 
749
768
  const candles = await client.marketData.getCandles({
750
- symbol: 'BTCUSD',
751
- timeframe: '1h',
752
- sort: 'volume', // Some endpoints use 'sort'
753
- order: 'desc' // instead of 'sort_by'/'sort_order'
769
+ symbol: "BTCUSD",
770
+ timeframe: "1h",
771
+ sort: "volume", // Some endpoints use 'sort'
772
+ order: "desc", // instead of 'sort_by'/'sort_order'
754
773
  });
755
774
  ```
756
775
 
@@ -761,28 +780,27 @@ All errors thrown by the SDK are instances of `PipsendError` with detailed infor
761
780
  ### Basic Error Handling
762
781
 
763
782
  ```typescript
764
- import { PipsendError } from '@pipsend/sdk';
783
+ import { PipsendError } from "@pipsend/sdk";
765
784
 
766
785
  try {
767
786
  const trade = await client.trades.open({
768
787
  login: 50001,
769
- symbol: 'EURUSD',
770
- action: 'buy',
771
- type: 'market',
772
- volume: 1.0
788
+ symbol: "EURUSD",
789
+ action: "buy",
790
+ type: "market",
791
+ volume: 1.0,
773
792
  });
774
-
775
- console.log('Trade opened:', trade.position_id);
776
-
793
+
794
+ console.log("Trade opened:", trade.position_id);
777
795
  } catch (error) {
778
796
  if (error instanceof PipsendError) {
779
- console.error('Error code:', error.code);
780
- console.error('Status code:', error.statusCode);
781
- console.error('Message:', error.message);
782
-
797
+ console.error("Error code:", error.code);
798
+ console.error("Status code:", error.statusCode);
799
+ console.error("Message:", error.message);
800
+
783
801
  // Check if it's a validation error
784
802
  if (error.isValidationError()) {
785
- console.error('Validation errors:', error.errors);
803
+ console.error("Validation errors:", error.errors);
786
804
  // Get formatted message with all details
787
805
  console.error(error.getDetailedMessage());
788
806
  }
@@ -797,26 +815,26 @@ When the API returns validation errors, the SDK provides detailed field-level in
797
815
  ```typescript
798
816
  try {
799
817
  const account = await client.accounts.create({
800
- trading_group: 'InvalidGroup',
801
- country: 'XYZ',
802
- master_password: 'short',
803
- investor_password: 'short',
804
- email: 'invalid-email',
805
- first_name: 'John',
806
- last_name: 'Doe'
818
+ trading_group: "InvalidGroup",
819
+ country: "XYZ",
820
+ master_password: "short",
821
+ investor_password: "short",
822
+ email: "invalid-email",
823
+ first_name: "John",
824
+ last_name: "Doe",
807
825
  });
808
826
  } catch (error) {
809
827
  if (error instanceof PipsendError && error.isValidationError()) {
810
- console.log('Validation failed:');
811
-
828
+ console.log("Validation failed:");
829
+
812
830
  // Access individual validation errors
813
- error.errors?.forEach(err => {
831
+ error.errors?.forEach((err) => {
814
832
  console.log(` - ${err.field}: ${err.message}`);
815
833
  });
816
-
834
+
817
835
  // Or get formatted message
818
836
  console.log(error.getDetailedMessage());
819
-
837
+
820
838
  // Output:
821
839
  // The provided data is not valid.
822
840
  // - trading_group: Trading group 'InvalidGroup' not found
@@ -831,20 +849,20 @@ try {
831
849
 
832
850
  ```typescript
833
851
  interface PipsendError {
834
- message: string; // Error message
835
- code: string; // Error code (e.g., 'VALIDATION_ERROR', 'NOT_FOUND')
836
- statusCode: number; // HTTP status code (e.g., 422, 404, 500)
837
- errors?: ValidationError[]; // Validation errors (for 422 responses)
838
- response?: any; // Full error response from server
839
-
852
+ message: string; // Error message
853
+ code: string; // Error code (e.g., 'VALIDATION_ERROR', 'NOT_FOUND')
854
+ statusCode: number; // HTTP status code (e.g., 422, 404, 500)
855
+ errors?: ValidationError[]; // Validation errors (for 422 responses)
856
+ response?: any; // Full error response from server
857
+
840
858
  // Helper methods
841
- isValidationError(): boolean; // Check if it's a validation error
842
- getDetailedMessage(): string; // Get formatted message with details
859
+ isValidationError(): boolean; // Check if it's a validation error
860
+ getDetailedMessage(): string; // Get formatted message with details
843
861
  }
844
862
 
845
863
  interface ValidationError {
846
- field: string; // Field name that failed validation
847
- message: string; // Validation error message
864
+ field: string; // Field name that failed validation
865
+ message: string; // Validation error message
848
866
  }
849
867
  ```
850
868
 
@@ -912,8 +930,8 @@ import type {
912
930
  Candle,
913
931
  Symbol,
914
932
  OpenTradeRequest,
915
- OpenTradeResponse
916
- } from '@pipsend/sdk';
933
+ OpenTradeResponse,
934
+ } from "@pipsend/sdk";
917
935
  ```
918
936
 
919
937
  ## ๐Ÿงช Testing