@pipsend/sdk 0.1.0

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 ADDED
@@ -0,0 +1,774 @@
1
+ # @pipsend/sdk
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@pipsend/sdk.svg)](https://www.npmjs.com/package/@pipsend/sdk)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ Official Pipsend SDK for Node.js and TypeScript. Complete MT5 trading platform integration with WebSocket support.
7
+
8
+ ## ๐Ÿš€ Features
9
+
10
+ - โœ… **6 Complete API Modules**: Accounts, Orders, Positions, Trades, Market Data, Trading Groups
11
+ - โœ… **TypeScript Native** with 100+ complete types
12
+ - โœ… **WebSocket Support** with auto-reconnect and heartbeat
13
+ - โœ… **Advanced Filtering** (dates, ranges, multi-value, search)
14
+ - โœ… **Dynamic Statistics** grouped by any field
15
+ - โœ… **Pagination Support** for all list endpoints
16
+ - โœ… **Dual Package** (ESM + CommonJS)
17
+ - โœ… **56 Unit Tests** passing
18
+ - โœ… **Compatible with Node.js โ‰ฅ16**
19
+
20
+ ## ๐Ÿ“ฆ Installation
21
+
22
+ ```bash
23
+ npm install @pipsend/sdk
24
+ ```
25
+
26
+ ```bash
27
+ yarn add @pipsend/sdk
28
+ ```
29
+
30
+ ```bash
31
+ pnpm add @pipsend/sdk
32
+ ```
33
+
34
+ ## ๐Ÿ”ง Quick Start
35
+
36
+ ```typescript
37
+ import { createClient } from '@pipsend/sdk';
38
+
39
+ const client = createClient({
40
+ server: 'http://localhost:8080'
41
+ });
42
+
43
+ const login = 50001;
44
+
45
+ // List accounts with filters
46
+ const accounts = await client.accounts.list({
47
+ state: 'active',
48
+ country: 'Mexico',
49
+ min_balance: 1000
50
+ });
51
+
52
+ // Open a trade
53
+ const trade = await client.trades.open({
54
+ login,
55
+ symbol: 'EURUSD',
56
+ action: 'buy',
57
+ type: 'market',
58
+ volume: 1.0,
59
+ stop_loss: 1.0850,
60
+ take_profit: 1.0950
61
+ });
62
+
63
+ // Get market data
64
+ const candles = await client.marketData.getCandles({
65
+ symbol: 'BTCUSD',
66
+ timeframe: '1h',
67
+ limit: 100
68
+ });
69
+
70
+ // WebSocket real-time updates
71
+ client.stream.onPriceUpdate((price) => {
72
+ console.log('Price update:', price);
73
+ });
74
+
75
+ await client.stream.connect();
76
+ ```
77
+
78
+ ## ๐Ÿ“š API Modules
79
+
80
+ ### 1. Accounts API
81
+
82
+ Manage MT5 accounts with advanced filtering and statistics.
83
+
84
+ ```typescript
85
+ // List accounts with filters
86
+ const accounts = await client.accounts.list({
87
+ state: 'active',
88
+ country: 'Mexico,United States',
89
+ trading_group: 'Premium',
90
+ min_balance: 1000,
91
+ max_balance: 50000,
92
+ page: 1,
93
+ per_page: 20
94
+ });
95
+
96
+ // Get statistics with filters
97
+ const stats = await client.accounts.getStatistics({
98
+ country: 'Mexico',
99
+ state: 'active'
100
+ });
101
+
102
+ // Get all account logins
103
+ const logins = await client.accounts.getLogins();
104
+
105
+ // Change passwords
106
+ await client.accounts.changeMasterPassword(50001, {
107
+ new_password: 'NewPass123!'
108
+ });
109
+
110
+ await client.accounts.changeInvestorPassword(50001, {
111
+ new_password: 'InvestorPass123!'
112
+ });
113
+
114
+ // Archive/Unarchive
115
+ await client.accounts.archive(50001);
116
+ await client.accounts.unarchive(50001);
117
+ ```
118
+
119
+ ### 2. Orders API
120
+
121
+ Manage pending orders with statistics and validation.
122
+
123
+ ```typescript
124
+ // List orders with advanced filters
125
+ const orders = await client.orders.list({
126
+ login: '50001',
127
+ symbol: 'EURUSD,GBPUSD',
128
+ order_type: 'limit',
129
+ status: 'new,partial',
130
+ created_from: '2025-01-01T00:00:00Z',
131
+ created_to: '2025-01-31T23:59:59Z',
132
+ price_min: 1.08,
133
+ price_max: 1.10,
134
+ sort_by: 'created_at',
135
+ sort_order: 'desc'
136
+ });
137
+
138
+ // Get statistics grouped by symbol
139
+ const stats = await client.orders.getStats({
140
+ login: '50001',
141
+ group_by: 'symbol'
142
+ });
143
+
144
+ // Get totals by order type
145
+ const totals = await client.orders.getTotals({
146
+ login: '50001',
147
+ group_by: 'order_type'
148
+ });
149
+
150
+ // Update order
151
+ await client.orders.update(12345, {
152
+ login: 50001,
153
+ stop_loss: 1.0800,
154
+ take_profit: 1.0950
155
+ });
156
+
157
+ // Delete order
158
+ await client.orders.delete(12345, { login: 50001 });
159
+
160
+ // Validate orders
161
+ const checkResult = await client.orders.check({
162
+ filters: {
163
+ logins: [50001],
164
+ statuses: ['new']
165
+ }
166
+ });
167
+ ```
168
+
169
+ ### 3. Positions API
170
+
171
+ Manage open positions with recalculation support.
172
+
173
+ ```typescript
174
+ // List positions with filters
175
+ const positions = await client.positions.list({
176
+ login: '50001',
177
+ symbol: 'EURUSD',
178
+ state: 'open',
179
+ profit_min: 100,
180
+ profit_max: 1000
181
+ });
182
+
183
+ // Get statistics grouped by type
184
+ const stats = await client.positions.getStats({
185
+ login: '50001',
186
+ state: 'open',
187
+ group_by: 'type'
188
+ });
189
+
190
+ // Get totals by symbol
191
+ const totals = await client.positions.getTotals({
192
+ login: '50001',
193
+ group_by: 'symbol'
194
+ });
195
+
196
+ // Update position
197
+ await client.positions.update(1, {
198
+ login: 50001,
199
+ stop_loss: 1.0875,
200
+ take_profit: 1.0975
201
+ });
202
+
203
+ // Delete position
204
+ await client.positions.delete(1, { login: 50001 });
205
+
206
+ // Recalculate positions
207
+ const checkResult = await client.positions.check({
208
+ filters: {
209
+ logins: [50001],
210
+ states: ['open']
211
+ }
212
+ });
213
+ ```
214
+
215
+ ### 4. Trades API
216
+
217
+ Execute trading operations with margin checking.
218
+
219
+ ```typescript
220
+ // Check margin before trading
221
+ const marginCheck = await client.trades.checkMargin({
222
+ login: 50001,
223
+ symbol: 'EURUSD',
224
+ action: 'buy',
225
+ volume: 1.0
226
+ });
227
+
228
+ if (marginCheck.can_execute) {
229
+ // Open trade
230
+ const trade = await client.trades.open({
231
+ login: 50001,
232
+ symbol: 'EURUSD',
233
+ action: 'buy',
234
+ type: 'market',
235
+ volume: 1.0,
236
+ stop_loss: 1.0850,
237
+ take_profit: 1.0950,
238
+ comment: 'API Trade'
239
+ });
240
+
241
+ // Modify trade
242
+ await client.trades.modify({
243
+ login: 50001,
244
+ position_id: trade.position_id,
245
+ stop_loss: 1.0875,
246
+ take_profit: 1.0975
247
+ });
248
+
249
+ // Calculate potential profit
250
+ const profitCalc = await client.trades.calculateProfit({
251
+ login: 50001,
252
+ symbol: 'EURUSD',
253
+ action: 'buy',
254
+ volume: 1.0,
255
+ open_price: 1.0900,
256
+ close_price: 1.0950
257
+ });
258
+
259
+ // Close trade (partial or full)
260
+ await client.trades.close({
261
+ login: 50001,
262
+ position_id: trade.position_id,
263
+ volume: 0.5, // Partial close
264
+ comment: 'Taking profit'
265
+ });
266
+ }
267
+
268
+ // Force price (for historical data import)
269
+ const historicalTrade = await client.trades.open({
270
+ login: 50001,
271
+ symbol: 'EURUSD',
272
+ action: 'buy',
273
+ type: 'market',
274
+ volume: 1.0,
275
+ price: 1.0850,
276
+ force_price: true,
277
+ force_timestamp: '2025-01-15T10:30:00Z'
278
+ });
279
+ ```
280
+
281
+ ### 5. Market Data API
282
+
283
+ Query historical market data (minimum 1 hour old).
284
+
285
+ ```typescript
286
+ // Get candles with filters
287
+ const candles = await client.marketData.getCandles({
288
+ symbol: 'BTCUSD,ETHUSD',
289
+ timeframe: '1h',
290
+ from: '2025-01-01T00:00:00Z',
291
+ to: '2025-01-02T00:00:00Z',
292
+ min_volume: 1000,
293
+ max_volume: 50000,
294
+ sort: 'volume',
295
+ order: 'desc',
296
+ limit: 100
297
+ });
298
+
299
+ // Get last 100 candles
300
+ const recentCandles = await client.marketData.getCandles({
301
+ symbol: 'BTCUSD',
302
+ timeframe: '1m',
303
+ limit: 100,
304
+ order: 'desc'
305
+ });
306
+
307
+ // Get symbols with filters
308
+ const symbols = await client.marketData.getSymbols({
309
+ group: 'CRYPTO_MAJOR',
310
+ has_data: true,
311
+ search: 'bitcoin'
312
+ });
313
+
314
+ // Get groups hierarchy
315
+ const groups = await client.marketData.getGroups({
316
+ root_only: true,
317
+ sort: 'symbol_count',
318
+ order: 'desc'
319
+ });
320
+ ```
321
+
322
+ **Timeframes**: `1m`, `5m`, `15m`, `1h`, `4h`, `1d`
323
+
324
+ **Note**: Data must be at least 1 hour old (no real-time data).
325
+
326
+ ### 6. Trading Groups API
327
+
328
+ Manage trading groups and their statistics.
329
+
330
+ ```typescript
331
+ // List trading groups
332
+ const groups = await client.tradingGroups.list({
333
+ page: 1,
334
+ per_page: 20
335
+ });
336
+
337
+ // Get statistics
338
+ const stats = await client.tradingGroups.getStatistics();
339
+ ```
340
+
341
+ ### 7. WebSocket API
342
+
343
+ Real-time updates for prices, orders, positions, and balance.
344
+
345
+ ```typescript
346
+ // Connect to WebSocket
347
+ await client.stream.connect();
348
+
349
+ // Subscribe to price updates
350
+ client.stream.onPriceUpdate((price) => {
351
+ console.log('Price:', price.symbol, price.bid, price.ask);
352
+ });
353
+
354
+ // Subscribe to order updates
355
+ client.stream.onOrderUpdate((order) => {
356
+ console.log('Order:', order.id, order.status);
357
+ });
358
+
359
+ // Subscribe to position updates
360
+ client.stream.onPositionUpdate((position) => {
361
+ console.log('Position:', position.id, position.profit);
362
+ });
363
+
364
+ // Subscribe to balance updates
365
+ client.stream.onBalanceUpdate((balance) => {
366
+ console.log('Balance:', balance.balance, balance.equity);
367
+ });
368
+
369
+ // Disconnect
370
+ await client.stream.disconnect();
371
+ ```
372
+
373
+ **Features**:
374
+ - Auto-reconnect with exponential backoff
375
+ - Heartbeat/ping-pong mechanism
376
+ - Automatic subscription restoration
377
+
378
+ ## ๐Ÿ”ง Configuration
379
+
380
+ ```typescript
381
+ const client = createClient({
382
+ server: 'http://localhost:8080', // Required
383
+ login: 'username', // Optional (for future auth)
384
+ password: 'password' // Optional (for future auth)
385
+ });
386
+ ```
387
+
388
+ ## ๐Ÿ“ฆ API Response Structure
389
+
390
+ All API endpoints return a consistent response structure:
391
+
392
+ ### Success Response (without pagination)
393
+ ```typescript
394
+ {
395
+ status: "success",
396
+ status_code: "SUCCESS",
397
+ data: [...] // Array of results or single object
398
+ }
399
+ ```
400
+
401
+ ### Success Response (with pagination)
402
+ ```typescript
403
+ {
404
+ status: "success",
405
+ status_code: "SUCCESS",
406
+ data: [...],
407
+ meta: {
408
+ total: 156,
409
+ page: 1,
410
+ per_page: 20,
411
+ total_pages: 8,
412
+ has_next: true,
413
+ has_prev: false
414
+ }
415
+ }
416
+ ```
417
+
418
+ ### Error Response
419
+ ```typescript
420
+ {
421
+ status: "error",
422
+ status_code: "VALIDATION_ERROR",
423
+ message: "The provided data is not valid.",
424
+ errors?: [
425
+ {
426
+ field: "symbol",
427
+ message: "At least one symbol is required."
428
+ }
429
+ ]
430
+ }
431
+ ```
432
+
433
+ ### Common Status Codes
434
+
435
+ **Success:**
436
+ - `SUCCESS` - Operation successful
437
+ - `CREATED` - Resource created successfully
438
+
439
+ **Errors:**
440
+ - `VALIDATION_ERROR` (400) - Invalid parameters
441
+ - `BAD_REQUEST` (400) - Invalid request
442
+ - `UNAUTHORIZED` (401) - Authentication required
443
+ - `FORBIDDEN` (403) - Insufficient permissions
444
+ - `NOT_FOUND` (404) - Resource not found
445
+ - `CONFLICT` (409) - Resource conflict (duplicate)
446
+ - `INTERNAL_ERROR` (500) - Server error
447
+
448
+ **Market Data Specific:**
449
+ - `SYMBOL_NOT_FOUND` (404) - Symbol not found
450
+ - `INVALID_TIMEFRAME` (400) - Invalid timeframe
451
+ - `TIME_RANGE_TOO_LARGE` (400) - Time range exceeds maximum
452
+ - `DATA_TOO_RECENT` (400) - Data must be at least 1 hour old
453
+
454
+ ## ๐ŸŽฏ Common Patterns
455
+
456
+ ### Pagination
457
+
458
+ **Option 1: Get all results (no pagination)**
459
+ ```typescript
460
+ // Returns all results in a single array
461
+ const accounts = await client.accounts.list({
462
+ state: 'active'
463
+ });
464
+ // Response: { status, status_code, data: [...] }
465
+ ```
466
+
467
+ **Option 2: Paginated results**
468
+ ```typescript
469
+ // Returns paginated results with metadata
470
+ const accounts = await client.accounts.list({
471
+ state: 'active',
472
+ page: 1,
473
+ per_page: 20
474
+ });
475
+ // Response: { status, status_code, data: [...], meta: {...} }
476
+
477
+ // Iterate through pages
478
+ let page = 1;
479
+ let hasMore = true;
480
+
481
+ while (hasMore) {
482
+ const response = await client.accounts.list({
483
+ state: 'active',
484
+ page,
485
+ per_page: 50
486
+ });
487
+
488
+ // Process response.data
489
+ console.log(`Page ${page}:`, response.data.length);
490
+
491
+ hasMore = response.meta.has_next;
492
+ page++;
493
+ }
494
+ ```
495
+
496
+ **Option 3: Limit results (ignores pagination)**
497
+ ```typescript
498
+ // Get specific number of results
499
+ const candles = await client.marketData.getCandles({
500
+ symbol: 'BTCUSD',
501
+ timeframe: '1h',
502
+ limit: 100 // Max: 10,000 for candles
503
+ });
504
+ ```
505
+
506
+ ### Multi-value Filters
507
+
508
+ Many filters accept comma-separated values:
509
+
510
+ ```typescript
511
+ // Multiple symbols (OR logic)
512
+ const positions = await client.positions.list({
513
+ symbol: 'EURUSD,GBPUSD,USDJPY' // Positions in ANY of these symbols
514
+ });
515
+
516
+ // Multiple countries
517
+ const accounts = await client.accounts.list({
518
+ country: 'Mexico,United States,Canada'
519
+ });
520
+
521
+ // Multiple states
522
+ const orders = await client.orders.list({
523
+ status: 'new,partial' // Orders with status new OR partial
524
+ });
525
+ ```
526
+
527
+ ### Date Filters
528
+
529
+ All date parameters must be in **ISO 8601 / RFC3339 format** (UTC):
530
+
531
+ ```typescript
532
+ // Correct format
533
+ const positions = await client.positions.list({
534
+ opened_from: '2025-01-01T00:00:00Z',
535
+ opened_to: '2025-01-31T23:59:59Z'
536
+ });
537
+
538
+ // Also valid
539
+ const candles = await client.marketData.getCandles({
540
+ symbol: 'BTCUSD',
541
+ timeframe: '1h',
542
+ from: '2025-01-15T10:30:00Z',
543
+ to: '2025-01-15T18:30:00Z'
544
+ });
545
+ ```
546
+
547
+ **Note**: Market data has a minimum age of 1 hour. The `to` parameter cannot be more recent than `now - 1 hour`.
548
+
549
+ ### Range Filters
550
+
551
+ Use `min_*` and `max_*` for numeric ranges:
552
+
553
+ ```typescript
554
+ // Balance range
555
+ const accounts = await client.accounts.list({
556
+ min_balance: 1000,
557
+ max_balance: 50000
558
+ });
559
+
560
+ // Profit range
561
+ const positions = await client.positions.list({
562
+ profit_min: 100,
563
+ profit_max: 1000
564
+ });
565
+
566
+ // Volume range
567
+ const candles = await client.marketData.getCandles({
568
+ symbol: 'BTCUSD',
569
+ timeframe: '1h',
570
+ min_volume: 1000,
571
+ max_volume: 50000
572
+ });
573
+ ```
574
+
575
+ ### Sorting
576
+
577
+ Most list endpoints support sorting:
578
+
579
+ ```typescript
580
+ const orders = await client.orders.list({
581
+ login: '50001',
582
+ sort_by: 'created_at', // Field to sort by
583
+ sort_order: 'desc' // 'asc' or 'desc'
584
+ });
585
+
586
+ const candles = await client.marketData.getCandles({
587
+ symbol: 'BTCUSD',
588
+ timeframe: '1h',
589
+ sort: 'volume', // Some endpoints use 'sort'
590
+ order: 'desc' // instead of 'sort_by'/'sort_order'
591
+ });
592
+ ```
593
+
594
+ ## โš ๏ธ Error Handling
595
+
596
+ Always wrap API calls in try-catch blocks:
597
+
598
+ ```typescript
599
+ try {
600
+ const trade = await client.trades.open({
601
+ login: 50001,
602
+ symbol: 'EURUSD',
603
+ action: 'buy',
604
+ type: 'market',
605
+ volume: 1.0
606
+ });
607
+
608
+ console.log('Trade opened:', trade.position_id);
609
+
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);
620
+ }
621
+ }
622
+ ```
623
+
624
+ ### Common Error Scenarios
625
+
626
+ ```typescript
627
+ // 1. Insufficient margin
628
+ try {
629
+ await client.trades.open({...});
630
+ } catch (error: any) {
631
+ if (error.status_code === 'INSUFFICIENT_MARGIN') {
632
+ // Check margin first
633
+ const check = await client.trades.checkMargin({...});
634
+ console.log('Required margin:', check.margin_required);
635
+ }
636
+ }
637
+
638
+ // 2. Position not found
639
+ try {
640
+ await client.positions.update(999, {...});
641
+ } catch (error: any) {
642
+ if (error.status_code === 'NOT_FOUND') {
643
+ console.error('Position does not exist');
644
+ }
645
+ }
646
+
647
+ // 3. Invalid time range
648
+ try {
649
+ await client.marketData.getCandles({
650
+ symbol: 'BTCUSD',
651
+ timeframe: '1m',
652
+ from: '2025-01-01T00:00:00Z',
653
+ to: '2025-02-01T00:00:00Z' // Too large for 1m
654
+ });
655
+ } catch (error: any) {
656
+ if (error.status_code === 'TIME_RANGE_TOO_LARGE') {
657
+ console.error('Time range exceeds maximum for this timeframe');
658
+ // Max ranges: 1m=7d, 5m=30d, 15m=60d, 1h=6mo, 4h=1y, 1d=5y
659
+ }
660
+ }
661
+
662
+ // 4. Data too recent
663
+ try {
664
+ await client.marketData.getCandles({
665
+ symbol: 'BTCUSD',
666
+ timeframe: '1h',
667
+ to: new Date().toISOString() // Too recent!
668
+ });
669
+ } catch (error: any) {
670
+ if (error.status_code === 'DATA_TOO_RECENT') {
671
+ console.error('Market data must be at least 1 hour old');
672
+ }
673
+ }
674
+ ```
675
+
676
+ ## ๐Ÿ“ TypeScript Support
677
+
678
+ The SDK is written in TypeScript and provides complete type definitions:
679
+
680
+ ```typescript
681
+ import type {
682
+ Account,
683
+ Order,
684
+ Position,
685
+ Candle,
686
+ Symbol,
687
+ OpenTradeRequest,
688
+ OpenTradeResponse
689
+ } from '@pipsend/sdk';
690
+ ```
691
+
692
+ ## ๐Ÿงช Testing
693
+
694
+ ```bash
695
+ # Run tests
696
+ npm test
697
+
698
+ # Run tests in watch mode
699
+ npm run test:watch
700
+
701
+ # Type checking
702
+ npm run typecheck
703
+
704
+ # Linting
705
+ npm run lint
706
+ ```
707
+
708
+ ## ๐Ÿ› ๏ธ Development
709
+
710
+ ```bash
711
+ # Install dependencies
712
+ npm install
713
+
714
+ # Build
715
+ npm run build
716
+
717
+ # Watch mode
718
+ npm run dev
719
+ ```
720
+
721
+ ## ๐Ÿ“– Examples
722
+
723
+ Check the `examples/` directory for complete usage examples:
724
+
725
+ - `examples/api-usage.ts` - Comprehensive API usage
726
+ - `examples/quick-start.ts` - Quick start guide
727
+
728
+ ## ๐Ÿ”— Links
729
+
730
+ - [Documentation](https://docs.pipsend.com)
731
+ - [NPM Package](https://www.npmjs.com/package/@pipsend/sdk)
732
+ - [GitHub Repository](https://github.com/pipsend/sdk)
733
+ - [Report Issues](https://github.com/pipsend/sdk/issues)
734
+
735
+ ## ๐Ÿ“„ License
736
+
737
+ MIT ยฉ 2025 Pipsend
738
+
739
+ ## ๐Ÿค Contributing
740
+
741
+ Contributions are welcome! Please:
742
+
743
+ 1. Fork the repository
744
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
745
+ 3. Commit your changes (`git commit -m 'Add amazing feature'`)
746
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
747
+ 5. Open a Pull Request
748
+
749
+ ## โš ๏ธ Project Status
750
+
751
+ **Current Version: 0.1.0 (Beta)**
752
+
753
+ This SDK is in active development. The API may change between minor versions until version 1.0.0.
754
+
755
+ ## ๐ŸŒŸ Features Roadmap
756
+
757
+ - [ ] Authentication with JWT tokens
758
+ - [ ] Rate limiting handling
759
+ - [ ] Retry logic with exponential backoff
760
+ - [ ] Request/response interceptors
761
+ - [ ] Batch operations
762
+ - [ ] Streaming data export
763
+ - [ ] Advanced error handling
764
+ - [ ] Performance metrics
765
+ - [ ] Request caching
766
+ - [ ] GraphQL support (future)
767
+
768
+ ## ๐Ÿ“Š Stats
769
+
770
+ - **6 API Modules**: Accounts, Orders, Positions, Trades, Market Data, Trading Groups
771
+ - **100+ TypeScript Types**: Fully typed interfaces
772
+ - **56 Unit Tests**: Comprehensive test coverage
773
+ - **Bundle Size**: ~26 KB (minified)
774
+ - **Zero Dependencies**: Lightweight and fast