@discomedia/utils 1.0.43 → 1.0.44

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/dist/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.0.43",
6
+ "version": "1.0.44",
7
7
  "author": "Disco Media",
8
8
  "description": "Utility functions used in Disco Media apps",
9
9
  "always-build-npm": true,
package/dist/test.js CHANGED
@@ -13474,7 +13474,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
13474
13474
  */
13475
13475
  async getHistoricalBars(params) {
13476
13476
  const symbols = params.symbols;
13477
- const symbolsStr = symbols.join(',');
13477
+ symbols.join(',');
13478
13478
  let allBars = {};
13479
13479
  let pageToken = null;
13480
13480
  let hasMorePages = true;
@@ -13485,7 +13485,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
13485
13485
  symbols.forEach((symbol) => {
13486
13486
  allBars[symbol] = [];
13487
13487
  });
13488
- log(`Starting historical bars fetch for ${symbolsStr.length} symbols (${params.timeframe}, ${params.start || 'no start'} to ${params.end || 'no end'})`);
13488
+ log(`Starting historical bars fetch for ${symbols.length} symbols (${params.timeframe}, ${params.start || 'no start'} to ${params.end || 'no end'})`);
13489
13489
  while (hasMorePages) {
13490
13490
  pageCount++;
13491
13491
  const requestParams = {
@@ -13496,7 +13496,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
13496
13496
  };
13497
13497
  const response = await this.makeRequest('/stocks/bars', 'GET', requestParams);
13498
13498
  if (!response.bars) {
13499
- log(`No bars data found in response for ${symbolsStr.length} symbols`, { type: 'warn' });
13499
+ log(`No bars data found in response for ${symbols.length} symbols`, { type: 'warn' });
13500
13500
  break;
13501
13501
  }
13502
13502
  // Track currency from first response
@@ -13538,10 +13538,10 @@ class AlpacaMarketDataAPI extends EventEmitter {
13538
13538
  }
13539
13539
  }
13540
13540
  // Final summary
13541
- const symbolsJoined = Object.entries(allBars)
13541
+ const symbolCounts = Object.entries(allBars)
13542
13542
  .map(([symbol, bars]) => `${symbol}: ${bars.length}`)
13543
13543
  .join(', ');
13544
- log(`Bars fetch complete: ${totalBarsCount.toLocaleString()} total bars across ${pageCount} pages for ${symbolsJoined.length} symbols'}`);
13544
+ log(`Bars fetch complete: ${totalBarsCount.toLocaleString()} total bars across ${pageCount} pages for ${symbols.length} symbols (${symbolCounts})`);
13545
13545
  return {
13546
13546
  bars: allBars,
13547
13547
  next_page_token: null, // Always null since we fetch all pages
@@ -13812,7 +13812,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
13812
13812
  */
13813
13813
  async getHistoricalOptionsBars(params) {
13814
13814
  const symbols = params.symbols;
13815
- const symbolsStr = symbols.join(',');
13815
+ symbols.join(',');
13816
13816
  let allBars = {};
13817
13817
  let pageToken = null;
13818
13818
  let hasMorePages = true;
@@ -13822,7 +13822,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
13822
13822
  symbols.forEach((symbol) => {
13823
13823
  allBars[symbol] = [];
13824
13824
  });
13825
- log(`Starting historical options bars fetch for ${symbolsStr.length} symbols (${params.timeframe}, ${params.start || 'no start'} to ${params.end || 'no end'})`);
13825
+ log(`Starting historical options bars fetch for ${symbols.length} symbols (${params.timeframe}, ${params.start || 'no start'} to ${params.end || 'no end'})`);
13826
13826
  while (hasMorePages) {
13827
13827
  pageCount++;
13828
13828
  const requestParams = {
@@ -13831,7 +13831,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
13831
13831
  };
13832
13832
  const response = await this.makeRequest('/options/bars', 'GET', requestParams, 'v1beta1');
13833
13833
  if (!response.bars) {
13834
- log(`No options bars data found in response for ${symbolsStr.length} symbols`, { type: 'warn' });
13834
+ log(`No options bars data found in response for ${symbols.length} symbols`, { type: 'warn' });
13835
13835
  break;
13836
13836
  }
13837
13837
  // Combine bars for each symbol
@@ -13861,7 +13861,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
13861
13861
  const dateRangeStr = earliestTimestamp && latestTimestamp
13862
13862
  ? `${earliestTimestamp.toLocaleDateString('en-US', { timeZone: 'America/New_York' })} to ${latestTimestamp.toLocaleDateString('en-US', { timeZone: 'America/New_York' })}`
13863
13863
  : 'unknown range';
13864
- log(`Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} option bars (total: ${totalBarsCount.toLocaleString()}) for ${symbolsStr}, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`, {
13864
+ log(`Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} option bars (total: ${totalBarsCount.toLocaleString()}) for ${symbols.length} symbols, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`, {
13865
13865
  type: 'debug',
13866
13866
  });
13867
13867
  // Prevent infinite loops
@@ -13890,7 +13890,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
13890
13890
  */
13891
13891
  async getHistoricalOptionsTrades(params) {
13892
13892
  const symbols = params.symbols;
13893
- const symbolsStr = symbols.join(',');
13893
+ symbols.join(',');
13894
13894
  let allTrades = {};
13895
13895
  let pageToken = null;
13896
13896
  let hasMorePages = true;
@@ -13900,7 +13900,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
13900
13900
  symbols.forEach((symbol) => {
13901
13901
  allTrades[symbol] = [];
13902
13902
  });
13903
- log(`Starting historical options trades fetch for ${symbolsStr.length} symbols (${params.start || 'no start'} to ${params.end || 'no end'})`);
13903
+ log(`Starting historical options trades fetch for ${symbols.length} symbols (${params.start || 'no start'} to ${params.end || 'no end'})`);
13904
13904
  while (hasMorePages) {
13905
13905
  pageCount++;
13906
13906
  const requestParams = {
@@ -13909,7 +13909,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
13909
13909
  };
13910
13910
  const response = await this.makeRequest('/options/trades', 'GET', requestParams, 'v1beta1');
13911
13911
  if (!response.trades) {
13912
- log(`No options trades data found in response for ${symbolsStr.length} symbols`, { type: 'warn' });
13912
+ log(`No options trades data found in response for ${symbols.length} symbols`, { type: 'warn' });
13913
13913
  break;
13914
13914
  }
13915
13915
  // Combine trades for each symbol
@@ -13939,7 +13939,7 @@ class AlpacaMarketDataAPI extends EventEmitter {
13939
13939
  const dateRangeStr = earliestTimestamp && latestTimestamp
13940
13940
  ? `${earliestTimestamp.toLocaleDateString('en-US', { timeZone: 'America/New_York' })} to ${latestTimestamp.toLocaleDateString('en-US', { timeZone: 'America/New_York' })}`
13941
13941
  : 'unknown range';
13942
- log(`Page ${pageCount}: Fetched ${pageTradesCount.toLocaleString()} option trades (total: ${totalTradesCount.toLocaleString()}) for ${symbolsStr.length} symbols, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`, {
13942
+ log(`Page ${pageCount}: Fetched ${pageTradesCount.toLocaleString()} option trades (total: ${totalTradesCount.toLocaleString()}) for ${symbols.length} symbols, date range: ${dateRangeStr}${hasMorePages ? ', more pages available' : ', complete'}`, {
13943
13943
  type: 'debug',
13944
13944
  });
13945
13945
  // Prevent infinite loops
@@ -14399,57 +14399,318 @@ var alpacaMarketDataApi = /*#__PURE__*/Object.freeze({
14399
14399
  });
14400
14400
 
14401
14401
  // Test file for context functionality
14402
- async function testGetAssetsShortableFilter() {
14403
- console.log('\n--- Testing getAssets params and shortable filter ---');
14404
- const log = (message, options = { type: 'info' }) => {
14405
- log$1(message, { ...options, source: 'Test' });
14406
- };
14402
+ async function testMarketDataAPI() {
14403
+ console.log('\n--- Testing Market Data API ---');
14407
14404
  if (!process.env.ALPACA_API_KEY || !process.env.ALPACA_SECRET_KEY) {
14408
- console.log('Skipping getAssets test: Missing environment variables (ALPACA_API_KEY, ALPACA_SECRET_KEY)');
14405
+ console.log('Skipping Market Data API tests: Missing environment variables (ALPACA_API_KEY, ALPACA_SECRET_KEY)');
14409
14406
  return;
14410
14407
  }
14411
14408
  try {
14412
14409
  const { marketDataAPI } = await Promise.resolve().then(function () { return alpacaMarketDataApi; });
14413
- // 1) Default call: should filter to shortable && easy_to_borrow and default to active us_equity
14414
- log('Calling getAssets() with defaults');
14415
- const filtered = await marketDataAPI.getAssets();
14416
- console.log(`Received ${filtered.length} filtered assets (default params)`);
14417
- const allFilteredValid = filtered.every((a) => a.shortable === true && a.easy_to_borrow === true);
14418
- if (!allFilteredValid) {
14419
- console.error('✗ Default getAssets() included assets that are not shortable and easy_to_borrow');
14410
+ // Test 1: Single symbol request - verify only 1 symbol is returned
14411
+ console.log('\n[Test 1] Single symbol historical bars');
14412
+ try {
14413
+ const testSymbol = 'AAPL';
14414
+ const endDate = new Date('2023-02-28T23:59:59.999Z');
14415
+ const startDate = new Date('2023-02-24T00:00:00.000Z');
14416
+ const response = await marketDataAPI.getHistoricalBars({
14417
+ symbols: [testSymbol],
14418
+ timeframe: '1Min',
14419
+ start: startDate.toISOString(),
14420
+ end: endDate.toISOString(),
14421
+ });
14422
+ const symbolsInResponse = Object.keys(response.bars);
14423
+ const barsCount = response.bars[testSymbol]?.length || 0;
14424
+ console.log(` Requested symbols: 1 (${testSymbol})`);
14425
+ console.log(` Symbols in response: ${symbolsInResponse.length} (${symbolsInResponse.join(', ')})`);
14426
+ console.log(` Bars for ${testSymbol}: ${barsCount}`);
14427
+ if (symbolsInResponse.length !== 1) {
14428
+ console.error(` ✗ FAILED: Expected 1 symbol in response, got ${symbolsInResponse.length}`);
14429
+ }
14430
+ else if (symbolsInResponse[0] !== testSymbol) {
14431
+ console.error(` ✗ FAILED: Expected symbol ${testSymbol}, got ${symbolsInResponse[0]}`);
14432
+ }
14433
+ else {
14434
+ console.log(` ✓ Single symbol request correctly returned 1 symbol`);
14435
+ }
14420
14436
  }
14421
- else {
14422
- console.log(' Default getAssets() correctly filtered shortable and easy_to_borrow assets');
14437
+ catch (error) {
14438
+ console.error(' Test 1 failed:', error);
14423
14439
  }
14424
- // 2) Unfiltered call: shortable=false
14425
- log('Calling getAssets({ shortable: false })');
14426
- const unfiltered = await marketDataAPI.getAssets({ shortable: false });
14427
- console.log(`Received ${unfiltered.length} unfiltered assets`);
14428
- if (unfiltered.length < filtered.length) {
14429
- console.warn('Unfiltered list is smaller than filtered. This is unexpected but not fatal.');
14440
+ // Test 2: Multiple symbols request - verify correct count
14441
+ console.log('\n[Test 2] Multiple symbols (3) historical bars');
14442
+ try {
14443
+ const testSymbols = ['AAPL', 'MSFT', 'GOOGL'];
14444
+ const endDate = new Date('2023-02-28T23:59:59.999Z');
14445
+ const startDate = new Date('2023-02-24T00:00:00.000Z');
14446
+ const response = await marketDataAPI.getHistoricalBars({
14447
+ symbols: testSymbols,
14448
+ timeframe: '1Min',
14449
+ start: startDate.toISOString(),
14450
+ end: endDate.toISOString(),
14451
+ });
14452
+ const symbolsInResponse = Object.keys(response.bars);
14453
+ const totalBars = Object.values(response.bars).reduce((sum, bars) => sum + bars.length, 0);
14454
+ console.log(` Requested symbols: ${testSymbols.length} (${testSymbols.join(', ')})`);
14455
+ console.log(` Symbols in response: ${symbolsInResponse.length} (${symbolsInResponse.join(', ')})`);
14456
+ console.log(` Total bars: ${totalBars}`);
14457
+ // Check each requested symbol
14458
+ const missingSymbols = testSymbols.filter((s) => !symbolsInResponse.includes(s));
14459
+ const extraSymbols = symbolsInResponse.filter((s) => !testSymbols.includes(s));
14460
+ if (missingSymbols.length > 0) {
14461
+ console.error(` ✗ FAILED: Missing symbols: ${missingSymbols.join(', ')}`);
14462
+ }
14463
+ if (extraSymbols.length > 0) {
14464
+ console.error(` ✗ FAILED: Extra symbols not requested: ${extraSymbols.join(', ')}`);
14465
+ }
14466
+ if (symbolsInResponse.length !== testSymbols.length) {
14467
+ console.error(` ✗ FAILED: Expected ${testSymbols.length} symbols in response, got ${symbolsInResponse.length}`);
14468
+ }
14469
+ else if (missingSymbols.length === 0 && extraSymbols.length === 0) {
14470
+ console.log(` ✓ Multiple symbols request correctly returned ${testSymbols.length} symbols`);
14471
+ }
14472
+ // Show bars per symbol
14473
+ testSymbols.forEach((symbol) => {
14474
+ const count = response.bars[symbol]?.length || 0;
14475
+ console.log(` ${symbol}: ${count} bars`);
14476
+ });
14430
14477
  }
14431
- else {
14432
- console.log(' Unfiltered list length is >= filtered list length');
14478
+ catch (error) {
14479
+ console.error(' Test 2 failed:', error);
14433
14480
  }
14434
- // 3) Specific constraints: inactive crypto, not asserting non-empty
14435
- log("Calling getAssets({ status: 'inactive', asset_class: 'crypto', shortable: false })");
14436
- const inactiveCrypto = await marketDataAPI.getAssets({ status: 'inactive', asset_class: 'crypto', shortable: false });
14437
- console.log(`Received ${inactiveCrypto.length} inactive crypto assets`);
14438
- if (inactiveCrypto.length > 0) {
14439
- const valid = inactiveCrypto.every((a) => a.class === 'crypto' && a.status === 'inactive');
14440
- if (!valid) {
14441
- console.error('✗ Inactive crypto request returned assets with mismatched class or status');
14481
+ // Test 3: Latest bars - single symbol
14482
+ console.log('\n[Test 3] Latest bars for single symbol');
14483
+ try {
14484
+ const testSymbol = 'TSLA';
14485
+ const response = await marketDataAPI.getLatestBars([testSymbol]);
14486
+ const symbolsInResponse = Object.keys(response.bars);
14487
+ console.log(` Requested symbols: 1 (${testSymbol})`);
14488
+ console.log(` Symbols in response: ${symbolsInResponse.length} (${symbolsInResponse.join(', ')})`);
14489
+ if (symbolsInResponse.length !== 1) {
14490
+ console.error(` ✗ FAILED: Expected 1 symbol in response, got ${symbolsInResponse.length}`);
14491
+ }
14492
+ else if (symbolsInResponse[0] !== testSymbol) {
14493
+ console.error(` ✗ FAILED: Expected symbol ${testSymbol}, got ${symbolsInResponse[0]}`);
14442
14494
  }
14443
14495
  else {
14444
- console.log('Inactive crypto request returned only crypto with inactive status');
14496
+ console.log(` Latest bars correctly returned 1 symbol`);
14445
14497
  }
14446
14498
  }
14447
- else {
14448
- console.log('No inactive crypto assets returned; skipping class/status assertions.');
14499
+ catch (error) {
14500
+ console.error(' Test 3 failed:', error);
14501
+ }
14502
+ // Test 4: Latest bars - multiple symbols
14503
+ console.log('\n[Test 4] Latest bars for multiple symbols');
14504
+ try {
14505
+ const testSymbols = ['SPY', 'QQQ', 'IWM', 'DIA'];
14506
+ const response = await marketDataAPI.getLatestBars(testSymbols);
14507
+ const symbolsInResponse = Object.keys(response.bars);
14508
+ console.log(` Requested symbols: ${testSymbols.length} (${testSymbols.join(', ')})`);
14509
+ console.log(` Symbols in response: ${symbolsInResponse.length} (${symbolsInResponse.join(', ')})`);
14510
+ const missingSymbols = testSymbols.filter((s) => !symbolsInResponse.includes(s));
14511
+ const extraSymbols = symbolsInResponse.filter((s) => !testSymbols.includes(s));
14512
+ if (missingSymbols.length > 0) {
14513
+ console.error(` ✗ FAILED: Missing symbols: ${missingSymbols.join(', ')}`);
14514
+ }
14515
+ if (extraSymbols.length > 0) {
14516
+ console.error(` ✗ FAILED: Extra symbols not requested: ${extraSymbols.join(', ')}`);
14517
+ }
14518
+ if (symbolsInResponse.length !== testSymbols.length) {
14519
+ console.error(` ✗ FAILED: Expected ${testSymbols.length} symbols in response, got ${symbolsInResponse.length}`);
14520
+ }
14521
+ else if (missingSymbols.length === 0 && extraSymbols.length === 0) {
14522
+ console.log(` ✓ Latest bars correctly returned ${testSymbols.length} symbols`);
14523
+ }
14524
+ }
14525
+ catch (error) {
14526
+ console.error(' ✗ Test 4 failed:', error);
14527
+ }
14528
+ // Test 5: Latest quotes - verify symbol count
14529
+ console.log('\n[Test 5] Latest quotes for multiple symbols');
14530
+ try {
14531
+ const testSymbols = ['AAPL', 'NVDA', 'AMD'];
14532
+ const response = await marketDataAPI.getLatestQuotes(testSymbols);
14533
+ const symbolsInResponse = Object.keys(response.quotes);
14534
+ console.log(` Requested symbols: ${testSymbols.length} (${testSymbols.join(', ')})`);
14535
+ console.log(` Symbols in response: ${symbolsInResponse.length} (${symbolsInResponse.join(', ')})`);
14536
+ const missingSymbols = testSymbols.filter((s) => !symbolsInResponse.includes(s));
14537
+ const extraSymbols = symbolsInResponse.filter((s) => !testSymbols.includes(s));
14538
+ if (missingSymbols.length > 0) {
14539
+ console.error(` ✗ FAILED: Missing symbols: ${missingSymbols.join(', ')}`);
14540
+ }
14541
+ if (extraSymbols.length > 0) {
14542
+ console.error(` ✗ FAILED: Extra symbols not requested: ${extraSymbols.join(', ')}`);
14543
+ }
14544
+ if (symbolsInResponse.length !== testSymbols.length) {
14545
+ console.error(` ✗ FAILED: Expected ${testSymbols.length} symbols in response, got ${symbolsInResponse.length}`);
14546
+ }
14547
+ else if (missingSymbols.length === 0 && extraSymbols.length === 0) {
14548
+ console.log(` ✓ Latest quotes correctly returned ${testSymbols.length} symbols`);
14549
+ }
14550
+ }
14551
+ catch (error) {
14552
+ console.error(' ✗ Test 5 failed:', error);
14553
+ }
14554
+ // Test 6: Latest trades - verify symbol count
14555
+ console.log('\n[Test 6] Latest trades for multiple symbols');
14556
+ try {
14557
+ const testSymbols = ['META', 'AMZN'];
14558
+ const response = await marketDataAPI.getLatestTrades(testSymbols);
14559
+ const symbolsInResponse = Object.keys(response.trades);
14560
+ console.log(` Requested symbols: ${testSymbols.length} (${testSymbols.join(', ')})`);
14561
+ console.log(` Symbols in response: ${symbolsInResponse.length} (${symbolsInResponse.join(', ')})`);
14562
+ const missingSymbols = testSymbols.filter((s) => !symbolsInResponse.includes(s));
14563
+ const extraSymbols = symbolsInResponse.filter((s) => !testSymbols.includes(s));
14564
+ if (missingSymbols.length > 0) {
14565
+ console.error(` ✗ FAILED: Missing symbols: ${missingSymbols.join(', ')}`);
14566
+ }
14567
+ if (extraSymbols.length > 0) {
14568
+ console.error(` ✗ FAILED: Extra symbols not requested: ${extraSymbols.join(', ')}`);
14569
+ }
14570
+ if (symbolsInResponse.length !== testSymbols.length) {
14571
+ console.error(` ✗ FAILED: Expected ${testSymbols.length} symbols in response, got ${symbolsInResponse.length}`);
14572
+ }
14573
+ else if (missingSymbols.length === 0 && extraSymbols.length === 0) {
14574
+ console.log(` ✓ Latest trades correctly returned ${testSymbols.length} symbols`);
14575
+ }
14576
+ }
14577
+ catch (error) {
14578
+ console.error(' ✗ Test 6 failed:', error);
14579
+ }
14580
+ // Test 7: Empty symbols array
14581
+ console.log('\n[Test 7] Empty symbols array handling');
14582
+ try {
14583
+ const response = await marketDataAPI.getLatestQuotes([]);
14584
+ const symbolsInResponse = Object.keys(response.quotes);
14585
+ console.log(` Requested symbols: 0 (empty array)`);
14586
+ console.log(` Symbols in response: ${symbolsInResponse.length}`);
14587
+ if (symbolsInResponse.length === 0) {
14588
+ console.log(` ✓ Empty symbols array correctly returned empty response`);
14589
+ }
14590
+ else {
14591
+ console.error(` ✗ FAILED: Expected 0 symbols in response, got ${symbolsInResponse.length}`);
14592
+ }
14593
+ }
14594
+ catch (error) {
14595
+ console.error(' ✗ Test 7 failed:', error);
14596
+ }
14597
+ // Test 8: Historical bars with date range that spans multiple pages
14598
+ console.log('\n[Test 8] Historical bars with pagination (longer date range)');
14599
+ try {
14600
+ const testSymbols = ['SPY'];
14601
+ const endDate = new Date('2023-03-15T23:59:59.999Z');
14602
+ const startDate = new Date('2023-03-01T01:00:00.000Z');
14603
+ const response = await marketDataAPI.getHistoricalBars({
14604
+ symbols: testSymbols,
14605
+ timeframe: '1Min',
14606
+ start: startDate.toISOString(),
14607
+ end: endDate.toISOString(),
14608
+ });
14609
+ const symbolsInResponse = Object.keys(response.bars);
14610
+ const totalBars = Object.values(response.bars).reduce((sum, bars) => sum + bars.length, 0);
14611
+ console.log(` Requested symbols: ${testSymbols.length} (${testSymbols.join(', ')})`);
14612
+ console.log(` Symbols in response: ${symbolsInResponse.length} (${symbolsInResponse.join(', ')})`);
14613
+ console.log(` Total bars: ${totalBars}`);
14614
+ const missingSymbols = testSymbols.filter((s) => !symbolsInResponse.includes(s));
14615
+ const extraSymbols = symbolsInResponse.filter((s) => !testSymbols.includes(s));
14616
+ if (missingSymbols.length > 0) {
14617
+ console.error(` ✗ FAILED: Missing symbols: ${missingSymbols.join(', ')}`);
14618
+ }
14619
+ if (extraSymbols.length > 0) {
14620
+ console.error(` ✗ FAILED: Extra symbols not requested: ${extraSymbols.join(', ')}`);
14621
+ }
14622
+ if (symbolsInResponse.length !== testSymbols.length) {
14623
+ console.error(` ✗ FAILED: Expected ${testSymbols.length} symbols in response, got ${symbolsInResponse.length}`);
14624
+ }
14625
+ else if (missingSymbols.length === 0 && extraSymbols.length === 0) {
14626
+ console.log(` ✓ Paginated request correctly returned ${testSymbols.length} symbols`);
14627
+ }
14628
+ }
14629
+ catch (error) {
14630
+ console.error(' ✗ Test 8 failed:', error);
14631
+ }
14632
+ // Test 9: Check for duplicate bars across pagination
14633
+ console.log('\n[Test 9] Check for duplicate bars in paginated response');
14634
+ try {
14635
+ const testSymbol = 'AAPL';
14636
+ const endDate = new Date('2023-02-28T23:59:59.999Z');
14637
+ const startDate = new Date('2023-02-24T00:00:00.000Z');
14638
+ const response = await marketDataAPI.getHistoricalBars({
14639
+ symbols: [testSymbol],
14640
+ timeframe: '1Min',
14641
+ start: startDate.toISOString(),
14642
+ end: endDate.toISOString(),
14643
+ });
14644
+ const bars = response.bars[testSymbol] || [];
14645
+ const timestamps = bars.map((bar) => bar.t);
14646
+ const uniqueTimestamps = new Set(timestamps);
14647
+ console.log(` Total bars: ${bars.length}`);
14648
+ console.log(` Unique timestamps: ${uniqueTimestamps.size}`);
14649
+ if (bars.length !== uniqueTimestamps.size) {
14650
+ const duplicateCount = bars.length - uniqueTimestamps.size;
14651
+ console.error(` ✗ FAILED: Found ${duplicateCount} duplicate bars`);
14652
+ // Show some duplicate examples
14653
+ const timestampCounts = new Map();
14654
+ timestamps.forEach((ts) => {
14655
+ timestampCounts.set(ts, (timestampCounts.get(ts) || 0) + 1);
14656
+ });
14657
+ const duplicates = Array.from(timestampCounts.entries())
14658
+ .filter(([_, count]) => count > 1)
14659
+ .slice(0, 5);
14660
+ if (duplicates.length > 0) {
14661
+ console.error(` Examples of duplicates:`);
14662
+ duplicates.forEach(([ts, count]) => {
14663
+ console.error(` ${ts}: ${count} occurrences`);
14664
+ });
14665
+ }
14666
+ }
14667
+ else {
14668
+ console.log(` ✓ No duplicate bars found`);
14669
+ }
14670
+ }
14671
+ catch (error) {
14672
+ console.error(' ✗ Test 9 failed:', error);
14673
+ }
14674
+ // Test 10: Verify logging accuracy - track what logs say vs actual data
14675
+ console.log('\n[Test 10] Verify logging accuracy');
14676
+ try {
14677
+ const testSymbols = ['AAPL', 'MSFT', 'GOOGL'];
14678
+ // Capture logs
14679
+ const originalLog = console.log;
14680
+ const logs = [];
14681
+ console.log = (...args) => {
14682
+ logs.push(args.join(' '));
14683
+ originalLog(...args);
14684
+ };
14685
+ const response = await marketDataAPI.getHistoricalBars({
14686
+ symbols: testSymbols,
14687
+ timeframe: '5Min',
14688
+ start: new Date('2023-02-27T09:30:00.000Z').toISOString(),
14689
+ end: new Date('2023-02-27T16:00:00.000Z').toISOString(),
14690
+ });
14691
+ console.log = originalLog;
14692
+ const symbolsInResponse = Object.keys(response.bars);
14693
+ console.log(` Requested symbols: ${testSymbols.length}`);
14694
+ console.log(` Actual symbols in response: ${symbolsInResponse.length}`);
14695
+ // Check if any logs mention incorrect symbol counts
14696
+ const logLines = logs.filter((log) => log.includes('symbols') && (log.includes('Starting') || log.includes('complete')));
14697
+ logLines.forEach((line) => {
14698
+ console.log(` Log: ${line}`);
14699
+ });
14700
+ if (symbolsInResponse.length === testSymbols.length) {
14701
+ console.log(` ✓ Response contains correct number of symbols`);
14702
+ }
14703
+ else {
14704
+ console.error(` ✗ FAILED: Expected ${testSymbols.length} symbols, got ${symbolsInResponse.length} (${symbolsInResponse.join(', ')})`);
14705
+ }
14706
+ }
14707
+ catch (error) {
14708
+ console.error(' ✗ Test 10 failed:', error);
14449
14709
  }
14710
+ console.log('\n✓ All Market Data API tests completed!');
14450
14711
  }
14451
14712
  catch (error) {
14452
- console.error('✗ getAssets test failed:', error);
14713
+ console.error('✗ Market Data API test setup failed:', error);
14453
14714
  if (error instanceof Error) {
14454
14715
  console.error('Error message:', error.message);
14455
14716
  console.error('Stack trace:', error.stack);
@@ -14469,5 +14730,6 @@ async function testGetAssetsShortableFilter() {
14469
14730
  // testCryptoMarketData();
14470
14731
  // testGetPortfolioDailyHistory();
14471
14732
  // testWebSocketConnectAndDisconnect();
14472
- testGetAssetsShortableFilter();
14733
+ // testGetAssetsShortableFilter();
14734
+ testMarketDataAPI();
14473
14735
  //# sourceMappingURL=test.js.map