@pipsend/sdk 0.1.0 → 0.1.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
@@ -3,7 +3,7 @@
3
3
  [![npm version](https://img.shields.io/npm/v/@pipsend/sdk.svg)](https://www.npmjs.com/package/@pipsend/sdk)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
 
6
- Official Pipsend SDK for Node.js and TypeScript. Complete MT5 trading platform integration with WebSocket support.
6
+ Official Pipsend SDK for Node.js and TypeScript. Complete trading platform integration with WebSocket support.
7
7
 
8
8
  ## 🚀 Features
9
9
 
@@ -31,13 +31,59 @@ yarn add @pipsend/sdk
31
31
  pnpm add @pipsend/sdk
32
32
  ```
33
33
 
34
+ ## 🔐 Authentication
35
+
36
+ The SDK uses JWT-based authentication with automatic token refresh.
37
+
38
+ ```typescript
39
+ import { createClient } from '@pipsend/sdk';
40
+
41
+ const client = createClient({
42
+ server: 'http://localhost:8080',
43
+ login: '1000', // Your admin/API login
44
+ password: 'YourPassword' // Your admin/API password
45
+ });
46
+
47
+ // The SDK automatically:
48
+ // ✅ Authenticates on first API call
49
+ // ✅ Stores access and refresh tokens in memory
50
+ // ✅ Refreshes tokens automatically when they expire
51
+ // ✅ Re-authenticates if refresh fails
52
+ ```
53
+
54
+ **Authentication happens automatically** - you don't need to call any login method. Just create the client and start making API calls.
55
+
56
+ ### Manual Authentication Control (Advanced)
57
+
58
+ If you need manual control over authentication:
59
+
60
+ ```typescript
61
+ // Check authentication status
62
+ const isAuthenticated = client.isAuthenticated();
63
+
64
+ // Manually refresh token
65
+ await client.refreshToken();
66
+
67
+ // Logout (clears tokens)
68
+ await client.logout();
69
+
70
+ // Get current token info
71
+ const tokenInfo = client.getTokenInfo();
72
+ console.log('Token expires at:', tokenInfo?.expiresAt);
73
+ ```
74
+
75
+ ---
76
+
34
77
  ## 🔧 Quick Start
35
78
 
36
79
  ```typescript
37
80
  import { createClient } from '@pipsend/sdk';
38
81
 
82
+ // Create authenticated client
39
83
  const client = createClient({
40
- server: 'http://localhost:8080'
84
+ server: 'http://localhost:8080',
85
+ login: '1000',
86
+ password: 'DemoMaster'
41
87
  });
42
88
 
43
89
  const login = 50001;
@@ -79,9 +125,22 @@ await client.stream.connect();
79
125
 
80
126
  ### 1. Accounts API
81
127
 
82
- Manage MT5 accounts with advanced filtering and statistics.
128
+ Manage accounts with advanced filtering and statistics.
83
129
 
84
130
  ```typescript
131
+ // Create a new trading account
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',
140
+ leverage: 100,
141
+ state: 'active'
142
+ });
143
+
85
144
  // List accounts with filters
86
145
  const accounts = await client.accounts.list({
87
146
  state: 'active',
@@ -102,6 +161,13 @@ const stats = await client.accounts.getStatistics({
102
161
  // Get all account logins
103
162
  const logins = await client.accounts.getLogins();
104
163
 
164
+ // Get account status/metrics (balance, equity, credit, margin)
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);
170
+
105
171
  // Change passwords
106
172
  await client.accounts.changeMasterPassword(50001, {
107
173
  new_password: 'NewPass123!'
@@ -114,6 +180,34 @@ await client.accounts.changeInvestorPassword(50001, {
114
180
  // Archive/Unarchive
115
181
  await client.accounts.archive(50001);
116
182
  await client.accounts.unarchive(50001);
183
+
184
+ // Update account information (partial update)
185
+ await client.accounts.update(50001, {
186
+ email: 'newemail@example.com',
187
+ leverage: 200,
188
+ city: 'Los Angeles',
189
+ trading_group: 'Premium'
190
+ });
191
+
192
+ // Adjust balance or credit
193
+ await client.accounts.balance(50001, {
194
+ type: 'balance',
195
+ amount: 500.00,
196
+ comment: 'Client deposit'
197
+ });
198
+
199
+ await client.accounts.balance(50001, {
200
+ type: 'credit',
201
+ amount: 1000.00,
202
+ comment: 'Credit line increase'
203
+ });
204
+
205
+ // Subtract balance
206
+ await client.accounts.balance(50001, {
207
+ type: 'balance',
208
+ amount: -200.00,
209
+ comment: 'Withdrawal request'
210
+ });
117
211
  ```
118
212
 
119
213
  ### 2. Orders API
@@ -340,51 +434,120 @@ const stats = await client.tradingGroups.getStatistics();
340
434
 
341
435
  ### 7. WebSocket API
342
436
 
343
- Real-time updates for prices, orders, positions, and balance.
437
+ Real-time updates for positions and balance with manual channel subscription.
344
438
 
345
439
  ```typescript
440
+ // Enable WebSocket in config
441
+ const client = createClient({
442
+ server: 'http://localhost:8080',
443
+ login: '1000',
444
+ password: 'DemoMaster',
445
+ websocket: {
446
+ enabled: true,
447
+ autoConnect: false
448
+ }
449
+ });
450
+
346
451
  // Connect to WebSocket
347
452
  await client.stream.connect();
348
453
 
349
- // Subscribe to price updates
350
- client.stream.onPriceUpdate((price) => {
351
- console.log('Price:', price.symbol, price.bid, price.ask);
454
+ // Subscribe to channels
455
+ 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
460
+ ]);
461
+
462
+ // Listen to position opened events
463
+ client.stream.onPositionOpened((event) => {
464
+ const pos = event.position;
465
+ console.log('Position opened:', pos.symbol, pos.side === 1 ? 'LONG' : 'SHORT', pos.qty);
352
466
  });
353
467
 
354
- // Subscribe to order updates
355
- client.stream.onOrderUpdate((order) => {
356
- console.log('Order:', order.id, order.status);
468
+ // Listen to position closed events
469
+ client.stream.onPositionClosed((event) => {
470
+ const pos = event.position;
471
+ console.log('Position closed:', pos.symbol, 'PnL:', pos.net_pnl);
357
472
  });
358
473
 
359
- // Subscribe to position updates
360
- client.stream.onPositionUpdate((position) => {
361
- console.log('Position:', position.id, position.profit);
474
+ // Listen to position updated events (throttled)
475
+ client.stream.onPositionUpdated((event) => {
476
+ const pos = event.position;
477
+ console.log('Position update:', pos.position_id, 'PnL:', pos.unrealized_pnl);
362
478
  });
363
479
 
364
- // Subscribe to balance updates
365
- client.stream.onBalanceUpdate((balance) => {
366
- console.log('Balance:', balance.balance, balance.equity);
480
+ // Listen to balance updates
481
+ client.stream.onBalanceUpdated((event) => {
482
+ console.log('Balance:', event.balance, 'Equity:', event.equity);
367
483
  });
368
484
 
485
+ // Unsubscribe from channels
486
+ client.stream.unsubscribe(['positions:updated']);
487
+
369
488
  // Disconnect
370
- await client.stream.disconnect();
489
+ client.stream.disconnect();
371
490
  ```
372
491
 
492
+ **Available Channels**:
493
+ - `positions:new` - New position opened
494
+ - `positions:closed` - Position closed (total or partial)
495
+ - `positions:updated` - PnL updates (throttled to max 1 per 2 seconds)
496
+ - `accounts:balance` - Balance changes
497
+
373
498
  **Features**:
499
+ - Manual subscription to specific channels
374
500
  - Auto-reconnect with exponential backoff
375
501
  - Heartbeat/ping-pong mechanism
376
- - Automatic subscription restoration
502
+ - Automatic subscription restoration on reconnect
503
+ - Throttled position updates to reduce load
504
+
505
+ See [WebSocket API Documentation](docs/WEBSOCKET_API.md) for complete guide.
377
506
 
378
507
  ## 🔧 Configuration
379
508
 
509
+ ### Basic Configuration
510
+
380
511
  ```typescript
381
512
  const client = createClient({
382
- server: 'http://localhost:8080', // Required
383
- login: 'username', // Optional (for future auth)
384
- password: 'password' // Optional (for future auth)
513
+ server: 'http://localhost:8080', // Required: API server URL
514
+ login: '1000', // Required: Admin/API login
515
+ password: 'YourPassword' // Required: Admin/API password
385
516
  });
386
517
  ```
387
518
 
519
+ ### Advanced Configuration
520
+
521
+ ```typescript
522
+ const client = createClient({
523
+ server: 'http://localhost:8080',
524
+ login: '1000',
525
+ password: 'YourPassword',
526
+
527
+ // WebSocket configuration (optional)
528
+ 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
+ }
535
+ });
536
+ ```
537
+
538
+ ### Configuration Options
539
+
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
+
388
551
  ## 📦 API Response Structure
389
552
 
390
553
  All API endpoints return a consistent response structure:
@@ -593,9 +756,13 @@ const candles = await client.marketData.getCandles({
593
756
 
594
757
  ## ⚠️ Error Handling
595
758
 
596
- Always wrap API calls in try-catch blocks:
759
+ All errors thrown by the SDK are instances of `PipsendError` with detailed information.
760
+
761
+ ### Basic Error Handling
597
762
 
598
763
  ```typescript
764
+ import { PipsendError } from '@pipsend/sdk';
765
+
599
766
  try {
600
767
  const trade = await client.trades.open({
601
768
  login: 50001,
@@ -607,20 +774,80 @@ try {
607
774
 
608
775
  console.log('Trade opened:', trade.position_id);
609
776
 
610
- } catch (error: any) {
611
- // Check status code
612
- if (error.status_code === 'INSUFFICIENT_MARGIN') {
613
- console.error('Not enough margin to open trade');
614
- } else if (error.status_code === 'SYMBOL_NOT_FOUND') {
615
- console.error('Symbol does not exist');
616
- } else if (error.status_code === 'VALIDATION_ERROR') {
617
- console.error('Invalid parameters:', error.errors);
618
- } else {
619
- console.error('Unexpected error:', error.message);
777
+ } catch (error) {
778
+ 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
+
783
+ // Check if it's a validation error
784
+ if (error.isValidationError()) {
785
+ console.error('Validation errors:', error.errors);
786
+ // Get formatted message with all details
787
+ console.error(error.getDetailedMessage());
788
+ }
789
+ }
790
+ }
791
+ ```
792
+
793
+ ### Handling Validation Errors (422)
794
+
795
+ When the API returns validation errors, the SDK provides detailed field-level information:
796
+
797
+ ```typescript
798
+ try {
799
+ 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'
807
+ });
808
+ } catch (error) {
809
+ if (error instanceof PipsendError && error.isValidationError()) {
810
+ console.log('Validation failed:');
811
+
812
+ // Access individual validation errors
813
+ error.errors?.forEach(err => {
814
+ console.log(` - ${err.field}: ${err.message}`);
815
+ });
816
+
817
+ // Or get formatted message
818
+ console.log(error.getDetailedMessage());
819
+
820
+ // Output:
821
+ // The provided data is not valid.
822
+ // - trading_group: Trading group 'InvalidGroup' not found
823
+ // - country: Country 'XYZ' not found
824
+ // - master_password: The field master_password must be at least 8 characters.
825
+ // - email: The field email must be a valid email address.
620
826
  }
621
827
  }
622
828
  ```
623
829
 
830
+ ### Error Properties
831
+
832
+ ```typescript
833
+ 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
+
840
+ // Helper methods
841
+ isValidationError(): boolean; // Check if it's a validation error
842
+ getDetailedMessage(): string; // Get formatted message with details
843
+ }
844
+
845
+ interface ValidationError {
846
+ field: string; // Field name that failed validation
847
+ message: string; // Validation error message
848
+ }
849
+ ```
850
+
624
851
  ### Common Error Scenarios
625
852
 
626
853
  ```typescript