@discomedia/utils 1.0.58 → 1.0.60

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.
Files changed (45) hide show
  1. package/README.md +0 -2
  2. package/dist/index-frontend.cjs +132 -9
  3. package/dist/index-frontend.cjs.map +1 -1
  4. package/dist/index-frontend.mjs +132 -9
  5. package/dist/index-frontend.mjs.map +1 -1
  6. package/dist/index.cjs +136 -1394
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.mjs +136 -1394
  9. package/dist/index.mjs.map +1 -1
  10. package/dist/package.json +3 -3
  11. package/dist/test.js +136 -241
  12. package/dist/test.js.map +1 -1
  13. package/dist/types/index.d.ts +0 -82
  14. package/dist/types/index.d.ts.map +1 -1
  15. package/dist/types/misc-utils.d.ts +0 -6
  16. package/dist/types/misc-utils.d.ts.map +1 -1
  17. package/dist/types/types/index.d.ts +0 -2
  18. package/dist/types/types/index.d.ts.map +1 -1
  19. package/dist/types-frontend/index.d.ts +0 -82
  20. package/dist/types-frontend/index.d.ts.map +1 -1
  21. package/dist/types-frontend/misc-utils.d.ts +0 -6
  22. package/dist/types-frontend/misc-utils.d.ts.map +1 -1
  23. package/dist/types-frontend/types/index.d.ts +0 -2
  24. package/dist/types-frontend/types/index.d.ts.map +1 -1
  25. package/package.json +3 -3
  26. package/dist/types/polygon-indices.d.ts +0 -85
  27. package/dist/types/polygon-indices.d.ts.map +0 -1
  28. package/dist/types/polygon.d.ts +0 -126
  29. package/dist/types/polygon.d.ts.map +0 -1
  30. package/dist/types/technical-analysis.d.ts +0 -90
  31. package/dist/types/technical-analysis.d.ts.map +0 -1
  32. package/dist/types/types/polygon-indices-types.d.ts +0 -190
  33. package/dist/types/types/polygon-indices-types.d.ts.map +0 -1
  34. package/dist/types/types/polygon-types.d.ts +0 -204
  35. package/dist/types/types/polygon-types.d.ts.map +0 -1
  36. package/dist/types-frontend/polygon-indices.d.ts +0 -85
  37. package/dist/types-frontend/polygon-indices.d.ts.map +0 -1
  38. package/dist/types-frontend/polygon.d.ts +0 -126
  39. package/dist/types-frontend/polygon.d.ts.map +0 -1
  40. package/dist/types-frontend/technical-analysis.d.ts +0 -90
  41. package/dist/types-frontend/technical-analysis.d.ts.map +0 -1
  42. package/dist/types-frontend/types/polygon-indices-types.d.ts +0 -190
  43. package/dist/types-frontend/types/polygon-indices-types.d.ts.map +0 -1
  44. package/dist/types-frontend/types/polygon-types.d.ts +0 -204
  45. package/dist/types-frontend/types/polygon-types.d.ts.map +0 -1
package/dist/index.mjs CHANGED
@@ -1380,933 +1380,6 @@ async function fetchWithRetry(url, options = {}, retries = 3, initialBackoff = 1
1380
1380
  }
1381
1381
  throw new Error('Failed to fetch after multiple attempts');
1382
1382
  }
1383
- /**
1384
- * Validates a Polygon.io API key by making a test request.
1385
- * @param apiKey - The API key to validate.
1386
- * @returns Promise that resolves to true if valid, false otherwise.
1387
- */
1388
- async function validatePolygonApiKey(apiKey) {
1389
- try {
1390
- const response = await fetch(`https://api.polygon.io/v1/meta/symbols?apikey=${apiKey}&limit=1`);
1391
- if (response.status === 401) {
1392
- throw new Error('Invalid or expired Polygon.io API key');
1393
- }
1394
- if (response.status === 403) {
1395
- throw new Error('Polygon.io API key lacks required permissions');
1396
- }
1397
- return response.ok;
1398
- }
1399
- catch (error) {
1400
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
1401
- console.error('Polygon.io API key validation failed:', errorMessage);
1402
- return false;
1403
- }
1404
- }
1405
-
1406
- /*
1407
- How it works:
1408
- `this.#head` is an instance of `Node` which keeps track of its current value and nests another instance of `Node` that keeps the value that comes after it. When a value is provided to `.enqueue()`, the code needs to iterate through `this.#head`, going deeper and deeper to find the last value. However, iterating through every single item is slow. This problem is solved by saving a reference to the last value as `this.#tail` so that it can reference it to add a new value.
1409
- */
1410
-
1411
- class Node {
1412
- value;
1413
- next;
1414
-
1415
- constructor(value) {
1416
- this.value = value;
1417
- }
1418
- }
1419
-
1420
- class Queue {
1421
- #head;
1422
- #tail;
1423
- #size;
1424
-
1425
- constructor() {
1426
- this.clear();
1427
- }
1428
-
1429
- enqueue(value) {
1430
- const node = new Node(value);
1431
-
1432
- if (this.#head) {
1433
- this.#tail.next = node;
1434
- this.#tail = node;
1435
- } else {
1436
- this.#head = node;
1437
- this.#tail = node;
1438
- }
1439
-
1440
- this.#size++;
1441
- }
1442
-
1443
- dequeue() {
1444
- const current = this.#head;
1445
- if (!current) {
1446
- return;
1447
- }
1448
-
1449
- this.#head = this.#head.next;
1450
- this.#size--;
1451
- return current.value;
1452
- }
1453
-
1454
- peek() {
1455
- if (!this.#head) {
1456
- return;
1457
- }
1458
-
1459
- return this.#head.value;
1460
-
1461
- // TODO: Node.js 18.
1462
- // return this.#head?.value;
1463
- }
1464
-
1465
- clear() {
1466
- this.#head = undefined;
1467
- this.#tail = undefined;
1468
- this.#size = 0;
1469
- }
1470
-
1471
- get size() {
1472
- return this.#size;
1473
- }
1474
-
1475
- * [Symbol.iterator]() {
1476
- let current = this.#head;
1477
-
1478
- while (current) {
1479
- yield current.value;
1480
- current = current.next;
1481
- }
1482
- }
1483
-
1484
- * drain() {
1485
- while (this.#head) {
1486
- yield this.dequeue();
1487
- }
1488
- }
1489
- }
1490
-
1491
- function pLimit(concurrency) {
1492
- let rejectOnClear = false;
1493
-
1494
- if (typeof concurrency === 'object') {
1495
- ({concurrency, rejectOnClear = false} = concurrency);
1496
- }
1497
-
1498
- validateConcurrency(concurrency);
1499
-
1500
- if (typeof rejectOnClear !== 'boolean') {
1501
- throw new TypeError('Expected `rejectOnClear` to be a boolean');
1502
- }
1503
-
1504
- const queue = new Queue();
1505
- let activeCount = 0;
1506
-
1507
- const resumeNext = () => {
1508
- // Process the next queued function if we're under the concurrency limit
1509
- if (activeCount < concurrency && queue.size > 0) {
1510
- activeCount++;
1511
- queue.dequeue().run();
1512
- }
1513
- };
1514
-
1515
- const next = () => {
1516
- activeCount--;
1517
- resumeNext();
1518
- };
1519
-
1520
- const run = async (function_, resolve, arguments_) => {
1521
- // Execute the function and capture the result promise
1522
- const result = (async () => function_(...arguments_))();
1523
-
1524
- // Resolve immediately with the promise (don't wait for completion)
1525
- resolve(result);
1526
-
1527
- // Wait for the function to complete (success or failure)
1528
- // We catch errors here to prevent unhandled rejections,
1529
- // but the original promise rejection is preserved for the caller
1530
- try {
1531
- await result;
1532
- } catch {}
1533
-
1534
- // Decrement active count and process next queued function
1535
- next();
1536
- };
1537
-
1538
- const enqueue = (function_, resolve, reject, arguments_) => {
1539
- const queueItem = {reject};
1540
-
1541
- // Queue the internal resolve function instead of the run function
1542
- // to preserve the asynchronous execution context.
1543
- new Promise(internalResolve => { // eslint-disable-line promise/param-names
1544
- queueItem.run = internalResolve;
1545
- queue.enqueue(queueItem);
1546
- }).then(run.bind(undefined, function_, resolve, arguments_)); // eslint-disable-line promise/prefer-await-to-then
1547
-
1548
- // Start processing immediately if we haven't reached the concurrency limit
1549
- if (activeCount < concurrency) {
1550
- resumeNext();
1551
- }
1552
- };
1553
-
1554
- const generator = (function_, ...arguments_) => new Promise((resolve, reject) => {
1555
- enqueue(function_, resolve, reject, arguments_);
1556
- });
1557
-
1558
- Object.defineProperties(generator, {
1559
- activeCount: {
1560
- get: () => activeCount,
1561
- },
1562
- pendingCount: {
1563
- get: () => queue.size,
1564
- },
1565
- clearQueue: {
1566
- value() {
1567
- if (!rejectOnClear) {
1568
- queue.clear();
1569
- return;
1570
- }
1571
-
1572
- const abortError = AbortSignal.abort().reason;
1573
-
1574
- while (queue.size > 0) {
1575
- queue.dequeue().reject(abortError);
1576
- }
1577
- },
1578
- },
1579
- concurrency: {
1580
- get: () => concurrency,
1581
-
1582
- set(newConcurrency) {
1583
- validateConcurrency(newConcurrency);
1584
- concurrency = newConcurrency;
1585
-
1586
- queueMicrotask(() => {
1587
- // eslint-disable-next-line no-unmodified-loop-condition
1588
- while (activeCount < concurrency && queue.size > 0) {
1589
- resumeNext();
1590
- }
1591
- });
1592
- },
1593
- },
1594
- map: {
1595
- async value(iterable, function_) {
1596
- const promises = Array.from(iterable, (value, index) => this(function_, value, index));
1597
- return Promise.all(promises);
1598
- },
1599
- },
1600
- });
1601
-
1602
- return generator;
1603
- }
1604
-
1605
- function validateConcurrency(concurrency) {
1606
- if (!((Number.isInteger(concurrency) || concurrency === Number.POSITIVE_INFINITY) && concurrency > 0)) {
1607
- throw new TypeError('Expected `concurrency` to be a number from 1 and up');
1608
- }
1609
- }
1610
-
1611
- /**********************************************************************************
1612
- * Polygon.io calls
1613
- **********************************************************************************/
1614
- // Constants from environment variables
1615
- const POLYGON_API_KEY = process.env.POLYGON_API_KEY;
1616
- // Define concurrency limits per API
1617
- const POLYGON_CONCURRENCY_LIMIT = 100;
1618
- const polygonLimit = pLimit(POLYGON_CONCURRENCY_LIMIT);
1619
- // Use to update general information about stocks
1620
- /**
1621
- * Fetches general information about a stock ticker.
1622
- * @param {string} symbol - The stock ticker symbol to fetch information for.
1623
- * @param {Object} [options] - Optional parameters.
1624
- * @param {string} [options.apiKey] - The API key to use for the request.
1625
- * @returns {Promise<PolygonTickerInfo | null>} The ticker information or null if not found.
1626
- */
1627
- const fetchTickerInfo = async (symbol, options) => {
1628
- if (!options?.apiKey && !POLYGON_API_KEY) {
1629
- throw new Error('Polygon API key is missing');
1630
- }
1631
- const baseUrl = `https://api.polygon.io/v3/reference/tickers/${encodeURIComponent(symbol)}`;
1632
- const params = new URLSearchParams({
1633
- apiKey: options?.apiKey || POLYGON_API_KEY,
1634
- });
1635
- return polygonLimit(async () => {
1636
- try {
1637
- const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, {}, 3, 1000);
1638
- const data = await response.json();
1639
- // Check for "NOT_FOUND" status and return null
1640
- if (data.status === 'NOT_FOUND') {
1641
- console.warn(`Ticker not found: ${symbol}`);
1642
- return null;
1643
- }
1644
- // Map the results to the required structure
1645
- const results = data.results;
1646
- if (!results) {
1647
- throw new Error('No results in Polygon API response');
1648
- }
1649
- // Validate required fields
1650
- const requiredFields = [
1651
- 'active',
1652
- 'currency_name',
1653
- 'locale',
1654
- 'market',
1655
- 'name',
1656
- 'primary_exchange',
1657
- 'ticker',
1658
- 'type',
1659
- ];
1660
- for (const field of requiredFields) {
1661
- if (results[field] === undefined) {
1662
- throw new Error(`Missing required field in Polygon API response: ${field}`);
1663
- }
1664
- }
1665
- // Handle optional share_class_shares_outstanding field
1666
- if (results.share_class_shares_outstanding === undefined) {
1667
- results.share_class_shares_outstanding = null;
1668
- }
1669
- return {
1670
- ticker: results.ticker,
1671
- type: results.type,
1672
- active: results.active,
1673
- currency_name: results.currency_name,
1674
- description: results.description ?? 'No description available',
1675
- locale: results.locale,
1676
- market: results.market,
1677
- market_cap: results.market_cap ?? 0,
1678
- name: results.name,
1679
- primary_exchange: results.primary_exchange,
1680
- share_class_shares_outstanding: results.share_class_shares_outstanding,
1681
- };
1682
- }
1683
- catch (error) {
1684
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
1685
- const contextualMessage = `Error fetching ticker info for ${symbol}`;
1686
- console.error(`${contextualMessage}: ${errorMessage}`, {
1687
- symbol,
1688
- errorType: error instanceof Error && error.message.includes('AUTH_ERROR')
1689
- ? 'AUTH_ERROR'
1690
- : error instanceof Error && error.message.includes('RATE_LIMIT')
1691
- ? 'RATE_LIMIT'
1692
- : error instanceof Error && error.message.includes('NETWORK_ERROR')
1693
- ? 'NETWORK_ERROR'
1694
- : 'UNKNOWN',
1695
- url: hideApiKeyFromurl(`${baseUrl}?${params.toString()}`),
1696
- source: 'PolygonAPI.fetchTickerInfo',
1697
- timestamp: new Date().toISOString(),
1698
- });
1699
- throw new Error(`${contextualMessage}: ${errorMessage}`);
1700
- }
1701
- });
1702
- };
1703
- // Fetch last trade using Polygon.io
1704
- /**
1705
- * Fetches the last trade for a given stock ticker.
1706
- * @param {string} symbol - The stock ticker symbol to fetch the last trade for.
1707
- * @param {Object} [options] - Optional parameters.
1708
- * @param {string} [options.apiKey] - The API key to use for the request.
1709
- * @returns {Promise<PolygonQuote>} The last trade information.
1710
- */
1711
- const fetchLastTrade = async (symbol, options) => {
1712
- if (!options?.apiKey && !POLYGON_API_KEY) {
1713
- throw new Error('Polygon API key is missing');
1714
- }
1715
- const baseUrl = `https://api.polygon.io/v2/last/trade/${encodeURIComponent(symbol)}`;
1716
- const params = new URLSearchParams({
1717
- apiKey: options?.apiKey || POLYGON_API_KEY,
1718
- });
1719
- return polygonLimit(async () => {
1720
- try {
1721
- const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, {}, 3, 1000);
1722
- const data = await response.json();
1723
- if (data.status !== 'OK' || !data.results) {
1724
- throw new Error(`Polygon.io API error: ${data.status || 'No results'} ${data.error || ''}`);
1725
- }
1726
- const { p: price, s: vol, t: timestamp } = data.results;
1727
- if (typeof price !== 'number' || typeof vol !== 'number' || typeof timestamp !== 'number') {
1728
- throw new Error('Invalid trade data received from Polygon.io API');
1729
- }
1730
- return {
1731
- price,
1732
- vol,
1733
- time: new Date(Math.floor(timestamp / 1000000)), // Convert nanoseconds to milliseconds
1734
- };
1735
- }
1736
- catch (error) {
1737
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
1738
- const contextualMessage = `Error fetching last trade for ${symbol}`;
1739
- console.error(`${contextualMessage}: ${errorMessage}`, {
1740
- symbol,
1741
- errorType: error instanceof Error && error.message.includes('AUTH_ERROR')
1742
- ? 'AUTH_ERROR'
1743
- : error instanceof Error && error.message.includes('RATE_LIMIT')
1744
- ? 'RATE_LIMIT'
1745
- : error instanceof Error && error.message.includes('NETWORK_ERROR')
1746
- ? 'NETWORK_ERROR'
1747
- : 'UNKNOWN',
1748
- url: hideApiKeyFromurl(`${baseUrl}?${params.toString()}`),
1749
- source: 'PolygonAPI.fetchLastTrade',
1750
- timestamp: new Date().toISOString(),
1751
- });
1752
- throw new Error(`${contextualMessage}: ${errorMessage}`);
1753
- }
1754
- });
1755
- };
1756
- // use Polygon for all price data fetching
1757
- /**
1758
- * Fetches price data for a given stock ticker.
1759
- * @param {Object} params - The parameters for fetching price data.
1760
- * @param {string} params.ticker - The stock ticker symbol.
1761
- * @param {number} params.start - The start timestamp for fetching price data.
1762
- * @param {number} [params.end] - The end timestamp for fetching price data.
1763
- * @param {number} params.multiplier - The multiplier for the price data.
1764
- * @param {string} params.timespan - The timespan for the price data.
1765
- * @param {number} [params.limit] - The maximum number of price data points to fetch.
1766
- * @param {Object} [options] - Optional parameters.
1767
- * @param {string} [options.apiKey] - The API key to use for the request.
1768
- * @returns {Promise<PolygonPriceData[]>} The fetched price data.
1769
- */
1770
- const fetchPrices = async (params, options) => {
1771
- if (!options?.apiKey && !POLYGON_API_KEY) {
1772
- throw new Error('Polygon API key is missing');
1773
- }
1774
- const { ticker, start, end = Date.now().valueOf(), multiplier, timespan, limit = 1000 } = params;
1775
- const baseUrl = `https://api.polygon.io/v2/aggs/ticker/${encodeURIComponent(ticker)}/range/${multiplier}/${timespan}/${start}/${end}`;
1776
- const urlParams = new URLSearchParams({
1777
- apiKey: options?.apiKey || POLYGON_API_KEY,
1778
- adjusted: 'true',
1779
- sort: 'asc',
1780
- limit: limit.toString(),
1781
- });
1782
- return polygonLimit(async () => {
1783
- try {
1784
- let allResults = [];
1785
- let nextUrl = `${baseUrl}?${urlParams.toString()}`;
1786
- while (nextUrl) {
1787
- //console.log(`Debug: Fetching ${nextUrl}`);
1788
- const response = await fetchWithRetry(nextUrl, {}, 3, 1000);
1789
- const data = await response.json();
1790
- if (data.status !== 'OK') {
1791
- throw new Error(`Polygon.io API responded with status: ${data.status}`);
1792
- }
1793
- if (data.results) {
1794
- allResults = [...allResults, ...data.results];
1795
- }
1796
- // Check if there's a next page and append API key
1797
- nextUrl = data.next_url ? `${data.next_url}&apiKey=${options?.apiKey || POLYGON_API_KEY}` : '';
1798
- }
1799
- return allResults.map((entry) => ({
1800
- date: new Date(entry.t).toLocaleString('en-US', {
1801
- year: 'numeric',
1802
- month: 'short',
1803
- day: '2-digit',
1804
- hour: '2-digit',
1805
- minute: '2-digit',
1806
- second: '2-digit',
1807
- timeZone: 'America/New_York',
1808
- timeZoneName: 'short',
1809
- hourCycle: 'h23',
1810
- }),
1811
- timeStamp: entry.t,
1812
- open: entry.o,
1813
- high: entry.h,
1814
- low: entry.l,
1815
- close: entry.c,
1816
- vol: entry.v,
1817
- vwap: entry.vw,
1818
- trades: entry.n,
1819
- }));
1820
- }
1821
- catch (error) {
1822
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
1823
- const contextualMessage = `Error fetching price data for ${ticker}`;
1824
- console.error(`${contextualMessage}: ${errorMessage}`, {
1825
- ticker,
1826
- errorType: error instanceof Error && error.message.includes('AUTH_ERROR')
1827
- ? 'AUTH_ERROR'
1828
- : error instanceof Error && error.message.includes('RATE_LIMIT')
1829
- ? 'RATE_LIMIT'
1830
- : error instanceof Error && error.message.includes('NETWORK_ERROR')
1831
- ? 'NETWORK_ERROR'
1832
- : 'UNKNOWN',
1833
- source: 'PolygonAPI.fetchPrices',
1834
- timestamp: new Date().toISOString(),
1835
- });
1836
- throw new Error(`${contextualMessage}: ${errorMessage}`);
1837
- }
1838
- });
1839
- };
1840
- /**
1841
- * Analyzes the price data for a given stock.
1842
- * @param {PolygonPriceData[]} priceData - The price data to analyze.
1843
- * @returns {string} The analysis report.
1844
- */
1845
- function analysePolygonPriceData(priceData) {
1846
- if (!priceData || priceData.length === 0) {
1847
- return 'No price data available for analysis.';
1848
- }
1849
- // Parse the dates into Date objects
1850
- const parsedData = priceData.map((entry) => ({
1851
- ...entry,
1852
- date: new Date(entry.date),
1853
- }));
1854
- // Sort the data by date
1855
- parsedData.sort((a, b) => a.date.getTime() - b.date.getTime());
1856
- // Extract start and end times
1857
- const startTime = parsedData[0].date;
1858
- const endTime = parsedData[parsedData.length - 1].date;
1859
- // Calculate the total time in hours
1860
- (endTime.getTime() - startTime.getTime()) / (1000 * 60 * 60);
1861
- // Calculate the interval between data points
1862
- const intervals = parsedData
1863
- .slice(1)
1864
- .map((_, i) => (parsedData[i + 1].date.getTime() - parsedData[i].date.getTime()) / 1000); // in seconds
1865
- const avgInterval = intervals.length > 0 ? intervals.reduce((sum, interval) => sum + interval, 0) / intervals.length : 0;
1866
- // Format the report
1867
- const report = `
1868
- Report:
1869
- * Start time of data (US Eastern): ${startTime.toLocaleString('en-US', { timeZone: 'America/New_York' })}
1870
- * End time of data (US Eastern): ${endTime.toLocaleString('en-US', { timeZone: 'America/New_York' })}
1871
- * Number of data points: ${priceData.length}
1872
- * Average interval between data points (seconds): ${avgInterval.toFixed(2)}
1873
- `;
1874
- return report.trim();
1875
- }
1876
- /**
1877
- * Fetches grouped daily price data for a specific date.
1878
- * @param {string} date - The date to fetch grouped daily data for.
1879
- * @param {Object} [options] - Optional parameters.
1880
- * @param {string} [options.apiKey] - The API key to use for the request.
1881
- * @param {boolean} [options.adjusted] - Whether to adjust the data.
1882
- * @param {boolean} [options.includeOTC] - Whether to include OTC data.
1883
- * @returns {Promise<PolygonGroupedDailyResponse>} The grouped daily response.
1884
- */
1885
- const fetchGroupedDaily = async (date, options) => {
1886
- if (!options?.apiKey && !POLYGON_API_KEY) {
1887
- throw new Error('Polygon API key is missing');
1888
- }
1889
- const baseUrl = `https://api.polygon.io/v2/aggs/grouped/locale/us/market/stocks/${date}`;
1890
- const params = new URLSearchParams({
1891
- apiKey: options?.apiKey || POLYGON_API_KEY,
1892
- adjusted: options?.adjusted !== false ? 'true' : 'false',
1893
- include_otc: options?.includeOTC ? 'true' : 'false',
1894
- });
1895
- return polygonLimit(async () => {
1896
- try {
1897
- const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, {}, 3, 1000);
1898
- const data = await response.json();
1899
- if (data.status !== 'OK') {
1900
- throw new Error(`Polygon.io API responded with status: ${data.status}`);
1901
- }
1902
- return {
1903
- adjusted: data.adjusted,
1904
- queryCount: data.queryCount,
1905
- request_id: data.request_id,
1906
- resultsCount: data.resultsCount,
1907
- status: data.status,
1908
- results: data.results.map((result) => ({
1909
- symbol: result.T,
1910
- timeStamp: result.t,
1911
- open: result.o,
1912
- high: result.h,
1913
- low: result.l,
1914
- close: result.c,
1915
- vol: result.v,
1916
- vwap: result.vw,
1917
- trades: result.n,
1918
- })),
1919
- };
1920
- }
1921
- catch (error) {
1922
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
1923
- const contextualMessage = `Error fetching grouped daily data for ${date}`;
1924
- console.error(`${contextualMessage}: ${errorMessage}`, {
1925
- date,
1926
- errorType: error instanceof Error && error.message.includes('AUTH_ERROR')
1927
- ? 'AUTH_ERROR'
1928
- : error instanceof Error && error.message.includes('RATE_LIMIT')
1929
- ? 'RATE_LIMIT'
1930
- : error instanceof Error && error.message.includes('NETWORK_ERROR')
1931
- ? 'NETWORK_ERROR'
1932
- : 'UNKNOWN',
1933
- url: hideApiKeyFromurl(`${baseUrl}?${params.toString()}`),
1934
- source: 'PolygonAPI.fetchGroupedDaily',
1935
- timestamp: new Date().toISOString(),
1936
- });
1937
- throw new Error(`${contextualMessage}: ${errorMessage}`);
1938
- }
1939
- });
1940
- };
1941
- /**
1942
- * Formats the price data into a readable string.
1943
- * @param {PolygonPriceData[]} priceData - The price data to format.
1944
- * @returns {string} The formatted price data.
1945
- */
1946
- function formatPriceData(priceData) {
1947
- if (!priceData || priceData.length === 0)
1948
- return 'No price data available';
1949
- return priceData
1950
- .map((d) => {
1951
- // For daily data, remove the time portion if it's all zeros
1952
- const dateStr = d.date.includes(', 00:00:00') ? d.date.split(', 00:00:00')[0] : d.date;
1953
- return [
1954
- dateStr,
1955
- `O: ${formatCurrency(d.open)}`,
1956
- `H: ${formatCurrency(d.high)}`,
1957
- `L: ${formatCurrency(d.low)}`,
1958
- `C: ${formatCurrency(d.close)}`,
1959
- `Vol: ${d.vol}`,
1960
- ].join(' | ');
1961
- })
1962
- .join('\n');
1963
- }
1964
- const fetchDailyOpenClose = async (
1965
- /**
1966
- * Fetches the daily open and close data for a given stock ticker.
1967
- * @param {string} symbol - The stock ticker symbol to fetch data for.
1968
- * @param {Date} [date=new Date()] - The date to fetch data for.
1969
- * @param {Object} [options] - Optional parameters.
1970
- * @param {string} [options.apiKey] - The API key to use for the request.
1971
- * @param {boolean} [options.adjusted] - Whether to adjust the data.
1972
- * @returns {Promise<PolygonDailyOpenClose>} The daily open and close data.
1973
- */
1974
- symbol, date = new Date(), options) => {
1975
- if (!options?.apiKey && !POLYGON_API_KEY) {
1976
- throw new Error('Polygon API key is missing');
1977
- }
1978
- const formattedDate = date.toISOString().split('T')[0]; // Format as YYYY-MM-DD
1979
- const baseUrl = `https://api.polygon.io/v1/open-close/${encodeURIComponent(symbol)}/${formattedDate}`;
1980
- const params = new URLSearchParams({
1981
- apiKey: options?.apiKey || POLYGON_API_KEY,
1982
- adjusted: (options?.adjusted ?? true).toString(),
1983
- });
1984
- return polygonLimit(async () => {
1985
- const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, {}, 3, 1000);
1986
- const data = await response.json();
1987
- if (data.status !== 'OK') {
1988
- throw new Error(`Failed to fetch daily open/close data for ${symbol}: ${data.status}`);
1989
- }
1990
- return data;
1991
- });
1992
- };
1993
- /**
1994
- * Gets the previous close price for a given stock ticker.
1995
- * @param {string} symbol - The stock ticker symbol to fetch the previous close for.
1996
- * @param {Date} [referenceDate] - The reference date to use for fetching the previous close.
1997
- * @returns {Promise<{ close: number; date: Date }>} The previous close price and date.
1998
- */
1999
- async function getPreviousClose(symbol, referenceDate, options) {
2000
- const previousDate = getLastFullTradingDate(referenceDate);
2001
- const lastOpenClose = await fetchDailyOpenClose(symbol, previousDate, options);
2002
- if (!lastOpenClose) {
2003
- throw new Error(`Could not fetch last trade price for ${symbol}`);
2004
- }
2005
- return {
2006
- close: lastOpenClose.close,
2007
- date: previousDate,
2008
- };
2009
- }
2010
- /**
2011
- * Fetches trade data for a given stock ticker.
2012
- * @param {string} symbol - The stock ticker symbol to fetch trades for.
2013
- * @param {Object} [options] - Optional parameters.
2014
- * @param {string} [options.apiKey] - The API key to use for the request.
2015
- * @param {string | number} [options.timestamp] - The timestamp for fetching trades.
2016
- * @param {string | number} [options.timestampgt] - Greater than timestamp for fetching trades.
2017
- * @param {string | number} [options.timestampgte] - Greater than or equal to timestamp for fetching trades.
2018
- * @param {string | number} [options.timestamplt] - Less than timestamp for fetching trades.
2019
- * @param {string | number} [options.timestamplte] - Less than or equal to timestamp for fetching trades.
2020
- * @param {'asc' | 'desc'} [options.order] - The order of the trades.
2021
- * @param {number} [options.limit] - The maximum number of trades to fetch.
2022
- * @param {string} [options.sort] - The sort order for the trades.
2023
- * @returns {Promise<PolygonTradesResponse>} The fetched trades response.
2024
- */
2025
- const fetchTrades = async (symbol, options) => {
2026
- if (!options?.apiKey && !POLYGON_API_KEY) {
2027
- throw new Error('Polygon API key is missing');
2028
- }
2029
- const baseUrl = `https://api.polygon.io/v3/trades/${encodeURIComponent(symbol)}`;
2030
- const params = new URLSearchParams({
2031
- apiKey: options?.apiKey || POLYGON_API_KEY,
2032
- });
2033
- // Add optional parameters if they exist
2034
- if (options?.timestamp)
2035
- params.append('timestamp', options.timestamp.toString());
2036
- if (options?.timestampgt)
2037
- params.append('timestamp.gt', options.timestampgt.toString());
2038
- if (options?.timestampgte)
2039
- params.append('timestamp.gte', options.timestampgte.toString());
2040
- if (options?.timestamplt)
2041
- params.append('timestamp.lt', options.timestamplt.toString());
2042
- if (options?.timestamplte)
2043
- params.append('timestamp.lte', options.timestamplte.toString());
2044
- if (options?.order)
2045
- params.append('order', options.order);
2046
- if (options?.limit)
2047
- params.append('limit', options.limit.toString());
2048
- if (options?.sort)
2049
- params.append('sort', options.sort);
2050
- return polygonLimit(async () => {
2051
- const url = `${baseUrl}?${params.toString()}`;
2052
- try {
2053
- console.log(`[DEBUG] Fetching trades for ${symbol} from ${url}`);
2054
- const response = await fetchWithRetry(url, {}, 3, 1000);
2055
- const data = (await response.json());
2056
- if ('message' in data) {
2057
- // This is an error response
2058
- throw new Error(`Polygon API Error: ${data.message}`);
2059
- }
2060
- return data;
2061
- }
2062
- catch (error) {
2063
- const errorMessage = error instanceof Error ? error.message : 'Unknown error occurred';
2064
- const contextualMessage = `Error fetching trades for ${symbol}`;
2065
- console.error(`${contextualMessage}: ${errorMessage}`, {
2066
- symbol,
2067
- errorType: error instanceof Error && error.message.includes('AUTH_ERROR')
2068
- ? 'AUTH_ERROR'
2069
- : error instanceof Error && error.message.includes('RATE_LIMIT')
2070
- ? 'RATE_LIMIT'
2071
- : error instanceof Error && error.message.includes('NETWORK_ERROR')
2072
- ? 'NETWORK_ERROR'
2073
- : 'UNKNOWN',
2074
- url: hideApiKeyFromurl(url),
2075
- source: 'PolygonAPI.fetchTrades',
2076
- timestamp: new Date().toISOString(),
2077
- });
2078
- throw new Error(`${contextualMessage}: ${errorMessage}`);
2079
- }
2080
- });
2081
- };
2082
-
2083
- /**
2084
- * Polygon Indices API Implementation
2085
- *
2086
- * This module provides functions to interact with the Polygon.io Indices API.
2087
- */
2088
- // Constants from environment variables
2089
- const { ALPACA_INDICES_API_KEY } = process.env;
2090
- // Define concurrency limits for API
2091
- const POLYGON_INDICES_CONCURRENCY_LIMIT = 5;
2092
- const polygonIndicesLimit = pLimit(POLYGON_INDICES_CONCURRENCY_LIMIT);
2093
- // Base URL for Polygon API
2094
- const POLYGON_API_BASE_URL = 'https://api.polygon.io';
2095
- /**
2096
- * Validates that an API key is available
2097
- * @param {string | undefined} apiKey - Optional API key to use
2098
- * @throws {Error} If no API key is available
2099
- */
2100
- const validateApiKey = (apiKey) => {
2101
- const key = apiKey || ALPACA_INDICES_API_KEY;
2102
- if (!key) {
2103
- throw new Error('Polygon Indices API key is missing');
2104
- }
2105
- return key;
2106
- };
2107
- /**
2108
- * Fetches aggregate bars for an index over a given date range in custom time window sizes.
2109
- *
2110
- * @param {PolygonIndicesAggregatesParams} params - Parameters for the aggregates request
2111
- * @param {Object} [options] - Optional parameters
2112
- * @param {string} [options.apiKey] - API key to use for the request
2113
- * @returns {Promise<PolygonIndicesAggregatesResponse>} The aggregates response
2114
- */
2115
- const fetchIndicesAggregates = async (params, options) => {
2116
- const apiKey = validateApiKey(options?.apiKey);
2117
- const { indicesTicker, multiplier, timespan, from, to, sort = 'asc', limit } = params;
2118
- const url = new URL(`${POLYGON_API_BASE_URL}/v2/aggs/ticker/${encodeURIComponent(indicesTicker)}/range/${multiplier}/${timespan}/${from}/${to}`);
2119
- const queryParams = new URLSearchParams();
2120
- queryParams.append('apiKey', apiKey);
2121
- if (sort) {
2122
- queryParams.append('sort', sort);
2123
- }
2124
- if (limit) {
2125
- queryParams.append('limit', limit.toString());
2126
- }
2127
- url.search = queryParams.toString();
2128
- return polygonIndicesLimit(async () => {
2129
- try {
2130
- const response = await fetchWithRetry(url.toString(), {}, 3, 300);
2131
- const data = await response.json();
2132
- if (data.status === 'ERROR') {
2133
- throw new Error(`Polygon API Error: ${data.error}`);
2134
- }
2135
- return data;
2136
- }
2137
- catch (error) {
2138
- console.error('Error fetching indices aggregates:', error);
2139
- throw error;
2140
- }
2141
- });
2142
- };
2143
- /**
2144
- * Gets the previous day's open, high, low, and close (OHLC) for the specified index.
2145
- *
2146
- * @param {string} indicesTicker - The ticker symbol of the index
2147
- * @param {Object} [options] - Optional parameters
2148
- * @param {string} [options.apiKey] - API key to use for the request
2149
- * @returns {Promise<PolygonIndicesPrevCloseResponse>} The previous close response
2150
- */
2151
- const fetchIndicesPreviousClose = async (indicesTicker, options) => {
2152
- const apiKey = validateApiKey(options?.apiKey);
2153
- const url = new URL(`${POLYGON_API_BASE_URL}/v2/aggs/ticker/${encodeURIComponent(indicesTicker)}/prev`);
2154
- const queryParams = new URLSearchParams();
2155
- queryParams.append('apiKey', apiKey);
2156
- url.search = queryParams.toString();
2157
- return polygonIndicesLimit(async () => {
2158
- try {
2159
- const response = await fetchWithRetry(url.toString(), {}, 3, 300);
2160
- const data = await response.json();
2161
- if (data.status === 'ERROR') {
2162
- throw new Error(`Polygon API Error: ${data.error}`);
2163
- }
2164
- return data;
2165
- }
2166
- catch (error) {
2167
- console.error('Error fetching indices previous close:', error);
2168
- throw error;
2169
- }
2170
- });
2171
- };
2172
- /**
2173
- * Gets the open, close and afterhours values of an index symbol on a certain date.
2174
- *
2175
- * @param {string} indicesTicker - The ticker symbol of the index
2176
- * @param {string} date - The date in YYYY-MM-DD format
2177
- * @param {Object} [options] - Optional parameters
2178
- * @param {string} [options.apiKey] - API key to use for the request
2179
- * @returns {Promise<PolygonIndicesDailyOpenCloseResponse>} The daily open/close response
2180
- */
2181
- const fetchIndicesDailyOpenClose = async (indicesTicker, date, options) => {
2182
- const apiKey = validateApiKey(options?.apiKey);
2183
- const url = new URL(`${POLYGON_API_BASE_URL}/v1/open-close/${encodeURIComponent(indicesTicker)}/${date}`);
2184
- const queryParams = new URLSearchParams();
2185
- queryParams.append('apiKey', apiKey);
2186
- url.search = queryParams.toString();
2187
- return polygonIndicesLimit(async () => {
2188
- try {
2189
- const response = await fetchWithRetry(url.toString(), {}, 3, 300);
2190
- const data = await response.json();
2191
- if (data.status === 'ERROR') {
2192
- throw new Error(`Polygon API Error: ${data.error}`);
2193
- }
2194
- return data;
2195
- }
2196
- catch (error) {
2197
- console.error('Error fetching indices daily open/close:', error);
2198
- throw error;
2199
- }
2200
- });
2201
- };
2202
- /**
2203
- * Gets a snapshot of indices data for specified tickers.
2204
- *
2205
- * @param {PolygonIndicesSnapshotParams} [params] - Parameters for the snapshot request
2206
- * @param {Object} [options] - Optional parameters
2207
- * @param {string} [options.apiKey] - API key to use for the request
2208
- * @returns {Promise<PolygonIndicesSnapshotResponse>} The indices snapshot response
2209
- */
2210
- const fetchIndicesSnapshot = async (params, options) => {
2211
- const apiKey = validateApiKey(options?.apiKey);
2212
- const url = new URL(`${POLYGON_API_BASE_URL}/v3/snapshot/indices`);
2213
- const queryParams = new URLSearchParams();
2214
- queryParams.append('apiKey', apiKey);
2215
- if (params?.tickers?.length) {
2216
- queryParams.append('ticker.any_of', params.tickers.join(','));
2217
- }
2218
- if (params?.order) {
2219
- queryParams.append('order', params.order);
2220
- }
2221
- if (params?.limit) {
2222
- queryParams.append('limit', params.limit.toString());
2223
- }
2224
- if (params?.sort) {
2225
- queryParams.append('sort', params.sort);
2226
- }
2227
- url.search = queryParams.toString();
2228
- return polygonIndicesLimit(async () => {
2229
- try {
2230
- const response = await fetchWithRetry(url.toString(), {}, 3, 300);
2231
- const data = await response.json();
2232
- if (data.status === 'ERROR') {
2233
- throw new Error(`Polygon API Error: ${data.error}`);
2234
- }
2235
- return data;
2236
- }
2237
- catch (error) {
2238
- console.error('Error fetching indices snapshot:', error);
2239
- throw error;
2240
- }
2241
- });
2242
- };
2243
- /**
2244
- * Gets snapshots for assets of all types, including indices.
2245
- *
2246
- * @param {string[]} tickers - Array of tickers to fetch snapshots for
2247
- * @param {Object} [options] - Optional parameters
2248
- * @param {string} [options.apiKey] - API key to use for the request
2249
- * @param {string} [options.type] - Filter by asset type
2250
- * @param {string} [options.order] - Order results
2251
- * @param {number} [options.limit] - Limit the number of results
2252
- * @param {string} [options.sort] - Sort field
2253
- * @returns {Promise<any>} The universal snapshot response
2254
- */
2255
- const fetchUniversalSnapshot = async (tickers, options) => {
2256
- const apiKey = validateApiKey(options?.apiKey);
2257
- const url = new URL(`${POLYGON_API_BASE_URL}/v3/snapshot`);
2258
- const queryParams = new URLSearchParams();
2259
- queryParams.append('apiKey', apiKey);
2260
- if (tickers.length) {
2261
- queryParams.append('ticker.any_of', tickers.join(','));
2262
- }
2263
- if (options?.type) {
2264
- queryParams.append('type', options.type);
2265
- }
2266
- if (options?.order) {
2267
- queryParams.append('order', options.order);
2268
- }
2269
- if (options?.limit) {
2270
- queryParams.append('limit', options.limit.toString());
2271
- }
2272
- if (options?.sort) {
2273
- queryParams.append('sort', options.sort);
2274
- }
2275
- url.search = queryParams.toString();
2276
- return polygonIndicesLimit(async () => {
2277
- try {
2278
- const response = await fetchWithRetry(url.toString(), {}, 3, 300);
2279
- const data = await response.json();
2280
- if (data.status === 'ERROR') {
2281
- throw new Error(`Polygon API Error: ${data.error}`);
2282
- }
2283
- return data;
2284
- }
2285
- catch (error) {
2286
- console.error('Error fetching universal snapshot:', error);
2287
- throw error;
2288
- }
2289
- });
2290
- };
2291
- /**
2292
- * Converts Polygon Indices bar data to a more standardized format
2293
- *
2294
- * @param {PolygonIndicesAggregatesResponse} data - The raw aggregates response
2295
- * @returns {Array<{date: string, open: number, high: number, low: number, close: number, timestamp: number}>} Formatted bar data
2296
- */
2297
- const formatIndicesBarData = (data) => {
2298
- return data.results.map((bar) => {
2299
- const date = new Date(bar.t);
2300
- return {
2301
- date: date.toISOString().split('T')[0],
2302
- open: bar.o,
2303
- high: bar.h,
2304
- low: bar.l,
2305
- close: bar.c,
2306
- timestamp: bar.t,
2307
- };
2308
- });
2309
- };
2310
1383
 
2311
1384
  function __classPrivateFieldSet(receiver, state, value, kind, f) {
2312
1385
  if (typeof state === "function" ? receiver !== state || true : !state.has(receiver))
@@ -2539,7 +1612,7 @@ const safeJSON = (text) => {
2539
1612
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2540
1613
  const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
2541
1614
 
2542
- const VERSION = '6.17.0'; // x-release-please-version
1615
+ const VERSION = '6.22.0'; // x-release-please-version
2543
1616
 
2544
1617
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2545
1618
  const isRunningInBrowser = () => {
@@ -3672,6 +2745,11 @@ async function defaultParseResponse(client, props) {
3672
2745
  const mediaType = contentType?.split(';')[0]?.trim();
3673
2746
  const isJSON = mediaType?.includes('application/json') || mediaType?.endsWith('+json');
3674
2747
  if (isJSON) {
2748
+ const contentLength = response.headers.get('content-length');
2749
+ if (contentLength === '0') {
2750
+ // if there is no content we can't do anything
2751
+ return undefined;
2752
+ }
3675
2753
  const json = await response.json();
3676
2754
  return addRequestID(json, response);
3677
2755
  }
@@ -7028,7 +6106,7 @@ class Completions extends APIResource {
7028
6106
  }
7029
6107
 
7030
6108
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
7031
- class Content extends APIResource {
6109
+ let Content$2 = class Content extends APIResource {
7032
6110
  /**
7033
6111
  * Retrieve Container File Content
7034
6112
  */
@@ -7040,13 +6118,13 @@ class Content extends APIResource {
7040
6118
  __binaryResponse: true,
7041
6119
  });
7042
6120
  }
7043
- }
6121
+ };
7044
6122
 
7045
6123
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
7046
6124
  let Files$2 = class Files extends APIResource {
7047
6125
  constructor() {
7048
6126
  super(...arguments);
7049
- this.content = new Content(this._client);
6127
+ this.content = new Content$2(this._client);
7050
6128
  }
7051
6129
  /**
7052
6130
  * Create a Container File
@@ -7055,7 +6133,7 @@ let Files$2 = class Files extends APIResource {
7055
6133
  * a JSON request with a file ID.
7056
6134
  */
7057
6135
  create(containerID, body, options) {
7058
- return this._client.post(path `/containers/${containerID}/files`, multipartFormRequestOptions({ body, ...options }, this._client));
6136
+ return this._client.post(path `/containers/${containerID}/files`, maybeMultipartFormRequestOptions({ body, ...options }, this._client));
7059
6137
  }
7060
6138
  /**
7061
6139
  * Retrieve Container File
@@ -7084,7 +6162,7 @@ let Files$2 = class Files extends APIResource {
7084
6162
  });
7085
6163
  }
7086
6164
  };
7087
- Files$2.Content = Content;
6165
+ Files$2.Content = Content$2;
7088
6166
 
7089
6167
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
7090
6168
  class Containers extends APIResource {
@@ -8372,6 +7450,114 @@ class Responses extends APIResource {
8372
7450
  Responses.InputItems = InputItems;
8373
7451
  Responses.InputTokens = InputTokens;
8374
7452
 
7453
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
7454
+ let Content$1 = class Content extends APIResource {
7455
+ /**
7456
+ * Get Skill Content
7457
+ */
7458
+ retrieve(skillID, options) {
7459
+ return this._client.get(path `/skills/${skillID}/content`, {
7460
+ ...options,
7461
+ headers: buildHeaders([{ Accept: 'application/binary' }, options?.headers]),
7462
+ __binaryResponse: true,
7463
+ });
7464
+ }
7465
+ };
7466
+
7467
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
7468
+ class Content extends APIResource {
7469
+ /**
7470
+ * Get Skill Version Content
7471
+ */
7472
+ retrieve(version, params, options) {
7473
+ const { skill_id } = params;
7474
+ return this._client.get(path `/skills/${skill_id}/versions/${version}/content`, {
7475
+ ...options,
7476
+ headers: buildHeaders([{ Accept: 'application/binary' }, options?.headers]),
7477
+ __binaryResponse: true,
7478
+ });
7479
+ }
7480
+ }
7481
+
7482
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
7483
+ class Versions extends APIResource {
7484
+ constructor() {
7485
+ super(...arguments);
7486
+ this.content = new Content(this._client);
7487
+ }
7488
+ /**
7489
+ * Create Skill Version
7490
+ */
7491
+ create(skillID, body = {}, options) {
7492
+ return this._client.post(path `/skills/${skillID}/versions`, maybeMultipartFormRequestOptions({ body, ...options }, this._client));
7493
+ }
7494
+ /**
7495
+ * Get Skill Version
7496
+ */
7497
+ retrieve(version, params, options) {
7498
+ const { skill_id } = params;
7499
+ return this._client.get(path `/skills/${skill_id}/versions/${version}`, options);
7500
+ }
7501
+ /**
7502
+ * List Skill Versions
7503
+ */
7504
+ list(skillID, query = {}, options) {
7505
+ return this._client.getAPIList(path `/skills/${skillID}/versions`, (CursorPage), {
7506
+ query,
7507
+ ...options,
7508
+ });
7509
+ }
7510
+ /**
7511
+ * Delete Skill Version
7512
+ */
7513
+ delete(version, params, options) {
7514
+ const { skill_id } = params;
7515
+ return this._client.delete(path `/skills/${skill_id}/versions/${version}`, options);
7516
+ }
7517
+ }
7518
+ Versions.Content = Content;
7519
+
7520
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
7521
+ class Skills extends APIResource {
7522
+ constructor() {
7523
+ super(...arguments);
7524
+ this.content = new Content$1(this._client);
7525
+ this.versions = new Versions(this._client);
7526
+ }
7527
+ /**
7528
+ * Create Skill
7529
+ */
7530
+ create(body = {}, options) {
7531
+ return this._client.post('/skills', maybeMultipartFormRequestOptions({ body, ...options }, this._client));
7532
+ }
7533
+ /**
7534
+ * Get Skill
7535
+ */
7536
+ retrieve(skillID, options) {
7537
+ return this._client.get(path `/skills/${skillID}`, options);
7538
+ }
7539
+ /**
7540
+ * Update Skill Default Version
7541
+ */
7542
+ update(skillID, body, options) {
7543
+ return this._client.post(path `/skills/${skillID}`, { body, ...options });
7544
+ }
7545
+ /**
7546
+ * List Skills
7547
+ */
7548
+ list(query = {}, options) {
7549
+ return this._client.getAPIList('/skills', (CursorPage), { query, ...options });
7550
+ }
7551
+ /**
7552
+ * Delete Skill
7553
+ */
7554
+ delete(skillID, options) {
7555
+ return this._client.delete(path `/skills/${skillID}`, options);
7556
+ }
7557
+ }
7558
+ Skills.Content = Content$1;
7559
+ Skills.Versions = Versions;
7560
+
8375
7561
  // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
8376
7562
  class Parts extends APIResource {
8377
7563
  /**
@@ -8981,6 +8167,7 @@ class OpenAI {
8981
8167
  this.conversations = new Conversations(this);
8982
8168
  this.evals = new Evals(this);
8983
8169
  this.containers = new Containers(this);
8170
+ this.skills = new Skills(this);
8984
8171
  this.videos = new Videos(this);
8985
8172
  if (apiKey === undefined) {
8986
8173
  throw new OpenAIError('Missing credentials. Please pass an `apiKey`, or set the `OPENAI_API_KEY` environment variable.');
@@ -9238,7 +8425,9 @@ class OpenAI {
9238
8425
  return { response, options, controller, requestLogID, retryOfRequestLogID, startTime };
9239
8426
  }
9240
8427
  getAPIList(path, Page, opts) {
9241
- return this.requestAPIList(Page, { method: 'get', path, ...opts });
8428
+ return this.requestAPIList(Page, opts && 'then' in opts ?
8429
+ opts.then((opts) => ({ method: 'get', path, ...opts }))
8430
+ : { method: 'get', path, ...opts });
9242
8431
  }
9243
8432
  requestAPIList(Page, options) {
9244
8433
  const request = this.makeRequest(options, null, undefined);
@@ -9246,9 +8435,10 @@ class OpenAI {
9246
8435
  }
9247
8436
  async fetchWithTimeout(url, init, ms, controller) {
9248
8437
  const { signal, method, ...options } = init || {};
8438
+ const abort = this._makeAbort(controller);
9249
8439
  if (signal)
9250
- signal.addEventListener('abort', () => controller.abort());
9251
- const timeout = setTimeout(() => controller.abort(), ms);
8440
+ signal.addEventListener('abort', abort, { once: true });
8441
+ const timeout = setTimeout(abort, ms);
9252
8442
  const isReadableBody = (globalThis.ReadableStream && options.body instanceof globalThis.ReadableStream) ||
9253
8443
  (typeof options.body === 'object' && options.body !== null && Symbol.asyncIterator in options.body);
9254
8444
  const fetchOptions = {
@@ -9379,6 +8569,11 @@ class OpenAI {
9379
8569
  this.validateHeaders(headers);
9380
8570
  return headers.values;
9381
8571
  }
8572
+ _makeAbort(controller) {
8573
+ // note: we can't just inline this method inside `fetchWithTimeout()` because then the closure
8574
+ // would capture all request options, and cause a memory leak.
8575
+ return () => controller.abort();
8576
+ }
9382
8577
  buildBody({ options: { body, headers: rawHeaders } }) {
9383
8578
  if (!body) {
9384
8579
  return { bodyHeaders: undefined, body: undefined };
@@ -9452,6 +8647,7 @@ OpenAI.Realtime = Realtime;
9452
8647
  OpenAI.Conversations = Conversations;
9453
8648
  OpenAI.Evals = Evals;
9454
8649
  OpenAI.Containers = Containers;
8650
+ OpenAI.Skills = Skills;
9455
8651
  OpenAI.Videos = Videos;
9456
8652
 
9457
8653
  // llm-openai-config.ts
@@ -10936,428 +10132,6 @@ class PerformanceTimer {
10936
10132
  }
10937
10133
  }
10938
10134
 
10939
- /**
10940
- * Calculates Bollinger Bands for a given set of price data.
10941
- * Bollinger Bands consist of a middle band (SMA) and two outer bands
10942
- * that are standard deviations away from the middle band.
10943
- *
10944
- * @param priceData - An array of price data objects containing closing prices.
10945
- * @param params - An object containing optional parameters for the calculation.
10946
- * @param params.period - The number of periods to use for the SMA (default is 20).
10947
- * @param params.standardDeviations - The number of standard deviations for the outer bands (default is 2).
10948
- * @returns An array of BollingerBandsData objects containing the calculated bands.
10949
- */
10950
- function calculateBollingerBands(priceData, { period = 20, standardDeviations = 2 } = {}) {
10951
- if (priceData.length < period) {
10952
- logIfDebug(`Insufficient data for Bollinger Bands calculation: required periods: ${period}, but only received ${priceData.length} periods of data`);
10953
- return [];
10954
- }
10955
- const result = [];
10956
- for (let i = period - 1; i < priceData.length; i++) {
10957
- const periodSlice = priceData.slice(i - period + 1, i + 1);
10958
- const prices = periodSlice.map((d) => d.close);
10959
- // Calculate middle band (SMA)
10960
- const sum = prices.reduce((acc, price) => acc + price, 0);
10961
- const sma = sum / period;
10962
- // Calculate standard deviation
10963
- const squaredDifferences = prices.map((price) => Math.pow(price - sma, 2));
10964
- const variance = squaredDifferences.reduce((acc, val) => acc + val, 0) / period;
10965
- const standardDeviation = Math.sqrt(variance);
10966
- // Calculate bands
10967
- const upperBand = sma + standardDeviation * standardDeviations;
10968
- const lowerBand = sma - standardDeviation * standardDeviations;
10969
- result.push({
10970
- date: priceData[i].date,
10971
- middle: parseFloat(sma.toFixed(2)),
10972
- upper: parseFloat(upperBand.toFixed(2)),
10973
- lower: parseFloat(lowerBand.toFixed(2)),
10974
- close: priceData[i].close,
10975
- });
10976
- }
10977
- // logIfDebug(`Calculated Bollinger Bands for ${result.length} periods`);
10978
- return result;
10979
- }
10980
- /**
10981
- * Calculates the Exponential Moving Average (EMA) for a given set of price data.
10982
- * The EMA gives more weight to recent prices, making it more responsive to new information.
10983
- *
10984
- * @param priceData - An array of price data objects containing closing prices.
10985
- * @param params - An object containing optional parameters for the calculation.
10986
- * @param params.period - The number of periods to use for the EMA (default is 20).
10987
- * @param params.period2 - An optional second period for a second EMA (default is 9).
10988
- * @returns An array of EMAData objects containing the calculated EMA values.
10989
- */
10990
- function calculateEMA(priceData, { period = 20, period2 = 9 } = {}) {
10991
- if (priceData.length < period || (period2 && priceData.length < period2)) {
10992
- logIfDebug(`Insufficient data for EMA calculation: required periods: ${period}, ${period2}, but only received ${priceData.length} periods of data`);
10993
- return [];
10994
- }
10995
- const result = [];
10996
- const multiplier = 2 / (period + 1);
10997
- const multiplier2 = period2 ? 2 / (period2 + 1) : 0;
10998
- // Calculate initial SMA for first period
10999
- let sum = 0;
11000
- for (let i = 0; i < period; i++) {
11001
- sum += priceData[i].close;
11002
- }
11003
- let prevEMA = sum / period;
11004
- // Calculate initial SMA for second period if needed
11005
- let prevEMA2;
11006
- if (period2) {
11007
- sum = 0;
11008
- for (let i = 0; i < period2; i++) {
11009
- sum += priceData[i].close;
11010
- }
11011
- prevEMA2 = sum / period2;
11012
- }
11013
- // Add first EMA(s)
11014
- const firstEntry = {
11015
- date: priceData[Math.max(period, period2 || 0) - 1].date,
11016
- ema: parseFloat(prevEMA.toFixed(2)),
11017
- close: priceData[Math.max(period, period2 || 0) - 1].close,
11018
- };
11019
- if (period2) {
11020
- firstEntry.ema2 = parseFloat(prevEMA2.toFixed(2));
11021
- }
11022
- result.push(firstEntry);
11023
- // Calculate EMA for remaining periods
11024
- for (let i = Math.max(period, period2 || 0); i < priceData.length; i++) {
11025
- const currentClose = priceData[i].close;
11026
- const currentEMA = (currentClose - prevEMA) * multiplier + prevEMA;
11027
- prevEMA = currentEMA;
11028
- const entry = {
11029
- date: priceData[i].date,
11030
- ema: parseFloat(currentEMA.toFixed(2)),
11031
- close: currentClose,
11032
- };
11033
- if (period2) {
11034
- const currentEMA2 = (currentClose - prevEMA2) * multiplier2 + prevEMA2;
11035
- prevEMA2 = currentEMA2;
11036
- entry.ema2 = parseFloat(currentEMA2.toFixed(2));
11037
- }
11038
- result.push(entry);
11039
- }
11040
- // logIfDebug(`Calculated EMA for ${result.length} periods`);
11041
- return result;
11042
- }
11043
- /**
11044
- * Calculates Fibonacci retracement and extension levels based on price data.
11045
- * Fibonacci levels are used to identify potential support and resistance levels.
11046
- *
11047
- * @param priceData - An array of price data objects containing high and low prices.
11048
- * @param params - An object containing optional parameters for the calculation.
11049
- * @param params.lookbackPeriod - The number of periods to look back for swing high/low (default is 20).
11050
- * @param params.retracementLevels - An array of retracement levels to calculate (default is [0.236, 0.382, 0.5, 0.618, 0.786]).
11051
- * @param params.extensionLevels - An array of extension levels to calculate (default is [1.272, 1.618, 2.618]).
11052
- * @param params.reverseDirection - A boolean indicating if the trend is reversed (default is false).
11053
- * @returns An array of FibonacciData objects containing the calculated levels.
11054
- */
11055
- function calculateFibonacciLevels(priceData, { lookbackPeriod = 20, retracementLevels = [0.236, 0.382, 0.5, 0.618, 0.786], extensionLevels = [1.272, 1.618, 2.618], reverseDirection = false, } = {}) {
11056
- const result = [];
11057
- for (let i = 0; i < priceData.length; i++) {
11058
- const periodSlice = priceData.slice(Math.max(0, i - lookbackPeriod + 1), i + 1);
11059
- const swingHigh = Math.max(...periodSlice.map((d) => d.high));
11060
- const swingLow = Math.min(...periodSlice.map((d) => d.low));
11061
- const priceRange = swingHigh - swingLow;
11062
- const trend = reverseDirection ? 'downtrend' : 'uptrend';
11063
- let levels = [];
11064
- if (priceRange > 0) {
11065
- // Calculate retracement levels
11066
- retracementLevels.forEach((level) => {
11067
- const price = reverseDirection ? swingLow + priceRange * level : swingHigh - priceRange * level;
11068
- levels.push({
11069
- level,
11070
- price: parseFloat(price.toFixed(2)),
11071
- type: 'retracement',
11072
- });
11073
- });
11074
- // Calculate extension levels
11075
- extensionLevels.forEach((level) => {
11076
- const price = reverseDirection
11077
- ? swingHigh - priceRange * (level - 1) // For downtrend
11078
- : swingHigh + priceRange * (level - 1); // For uptrend
11079
- levels.push({
11080
- level,
11081
- price: parseFloat(price.toFixed(2)),
11082
- type: 'extension',
11083
- });
11084
- });
11085
- // Sort levels by price
11086
- levels.sort((a, b) => (reverseDirection ? b.price - a.price : a.price - b.price));
11087
- }
11088
- else {
11089
- logIfDebug(`Price range is zero on date ${priceData[i].date}; no levels calculated.`);
11090
- }
11091
- result.push({
11092
- date: priceData[i].date,
11093
- levels,
11094
- swingHigh,
11095
- swingLow,
11096
- trend,
11097
- close: priceData[i].close,
11098
- });
11099
- }
11100
- // logIfDebug(`Calculated Fibonacci levels for ${result.length} periods`);
11101
- return result;
11102
- }
11103
- /**
11104
- * Calculates the Moving Average Convergence Divergence (MACD) for a given set of price data.
11105
- * MACD is a trend-following momentum indicator that shows the relationship between two EMAs.
11106
- *
11107
- * @param priceData - An array of price data objects containing closing prices.
11108
- * @param params - An object containing optional parameters for the calculation.
11109
- * @param params.shortPeriod - The short EMA period (default is 12).
11110
- * @param params.longPeriod - The long EMA period (default is 26).
11111
- * @param params.signalPeriod - The signal line period (default is 9).
11112
- * @returns An array of MACDData objects containing the calculated MACD values.
11113
- */
11114
- function calculateMACD(priceData, { shortPeriod = 12, longPeriod = 26, signalPeriod = 9 } = {}) {
11115
- if (priceData.length < longPeriod + signalPeriod) {
11116
- logIfDebug(`Insufficient data for MACD calculation: required periods: ${longPeriod + signalPeriod}, but only received ${priceData.length} periods of data`);
11117
- return [];
11118
- }
11119
- const emaShort = calculateEMA(priceData, { period: shortPeriod });
11120
- const emaLong = calculateEMA(priceData, { period: longPeriod });
11121
- // Align EMAs by trimming the beginning of emaShort to match emaLong length
11122
- if (emaShort.length < emaLong.length) {
11123
- logIfDebug('Short EMA length is less than Long EMA length for MACD calculation');
11124
- return [];
11125
- }
11126
- const emaShortAligned = emaShort.slice(emaShort.length - emaLong.length);
11127
- const macdLine = emaShortAligned.map((short, i) => short.ema - emaLong[i].ema);
11128
- const result = [];
11129
- if (macdLine.length < signalPeriod) {
11130
- logIfDebug(`Insufficient MACD data for Signal Line calculation: required periods: ${signalPeriod}, but only received ${macdLine.length} periods of data`);
11131
- return [];
11132
- }
11133
- const signalMultiplier = 2 / (signalPeriod + 1);
11134
- let signalEMA = macdLine.slice(0, signalPeriod).reduce((sum, val) => sum + val, 0) / signalPeriod;
11135
- for (let i = signalPeriod; i < macdLine.length; i++) {
11136
- const macdValue = macdLine[i];
11137
- signalEMA = (macdValue - signalEMA) * signalMultiplier + signalEMA;
11138
- const hist = macdValue - signalEMA;
11139
- result.push({
11140
- date: emaLong[i].date, // Use emaLong's date for alignment
11141
- macd: parseFloat(macdValue.toFixed(2)),
11142
- signal: parseFloat(signalEMA.toFixed(2)),
11143
- histogram: parseFloat(hist.toFixed(2)),
11144
- close: emaLong[i].close,
11145
- });
11146
- }
11147
- // logIfDebug(`Calculated MACD for ${result.length} periods`);
11148
- return result;
11149
- }
11150
- /**
11151
- * Calculates the Relative Strength Index (RSI) for a given set of price data.
11152
- * RSI is a momentum oscillator that measures the speed and change of price movements.
11153
- *
11154
- * @param priceData - An array of price data objects containing closing prices.
11155
- * @param params - An object containing optional parameters for the calculation.
11156
- * @param params.period - The number of periods to use for the RSI (default is 14).
11157
- * @returns An array of RSIData objects containing the calculated RSI values.
11158
- */
11159
- function calculateRSI(priceData, { period = 14 } = {}) {
11160
- if (priceData.length < period + 1) {
11161
- logIfDebug(`Insufficient data for RSI calculation: required periods: ${period + 1}, but only received ${priceData.length} periods of data`);
11162
- return [];
11163
- }
11164
- const result = [];
11165
- let avgGain = 0;
11166
- let avgLoss = 0;
11167
- // Calculate first average gain and loss
11168
- for (let i = 1; i <= period; i++) {
11169
- const change = priceData[i].close - priceData[i - 1].close;
11170
- if (change >= 0) {
11171
- avgGain += change;
11172
- }
11173
- else {
11174
- avgLoss += Math.abs(change);
11175
- }
11176
- }
11177
- avgGain = avgGain / period;
11178
- avgLoss = avgLoss / period;
11179
- // Calculate RSI for the first period
11180
- let rs = avgGain / avgLoss;
11181
- let rsi = 100 - 100 / (1 + rs);
11182
- result.push({
11183
- date: priceData[period].date,
11184
- rsi: parseFloat(rsi.toFixed(2)),
11185
- close: priceData[period].close,
11186
- });
11187
- // Calculate subsequent periods using smoothed averages
11188
- for (let i = period + 1; i < priceData.length; i++) {
11189
- const change = priceData[i].close - priceData[i - 1].close;
11190
- const gain = change >= 0 ? change : 0;
11191
- const loss = change < 0 ? Math.abs(change) : 0;
11192
- // Use smoothed averages
11193
- avgGain = (avgGain * (period - 1) + gain) / period;
11194
- avgLoss = (avgLoss * (period - 1) + loss) / period;
11195
- rs = avgGain / avgLoss;
11196
- rsi = 100 - 100 / (1 + rs);
11197
- result.push({
11198
- date: priceData[i].date,
11199
- rsi: parseFloat(rsi.toFixed(2)),
11200
- close: priceData[i].close,
11201
- });
11202
- }
11203
- // logIfDebug(`Calculated RSI for ${result.length} periods`);
11204
- return result;
11205
- }
11206
- /**
11207
- * Calculates the Stochastic Oscillator for a given set of price data.
11208
- * The Stochastic Oscillator compares a particular closing price of a security to a range of its prices over a certain period of time.
11209
- *
11210
- * @param priceData - An array of price data objects containing high, low, and closing prices.
11211
- * @param params - An object containing optional parameters for the calculation.
11212
- * @param params.lookbackPeriod - The number of periods to look back for the calculation of %K (default is 5).
11213
- * @param params.signalPeriod - The number of periods for the %D signal line (default is 3).
11214
- * @param params.smoothingFactor - The smoothing factor for %K (default is 3).
11215
- * @returns An array of StochData objects containing the calculated %K and %D values.
11216
- */
11217
- function calculateStochasticOscillator(priceData, { lookbackPeriod = 5, signalPeriod = 3, smoothingFactor = 3 } = {}) {
11218
- if (priceData.length < lookbackPeriod) {
11219
- logIfDebug(`Insufficient data for Stochastic Oscillator calculation: required periods: ${lookbackPeriod}, but only received ${priceData.length} periods of data`);
11220
- return [];
11221
- }
11222
- const kValues = [];
11223
- const result = [];
11224
- let kSum = 0;
11225
- let dSum = 0;
11226
- for (let i = lookbackPeriod - 1; i < priceData.length; i++) {
11227
- const periodSlice = priceData.slice(i - lookbackPeriod + 1, i + 1);
11228
- const currentClose = periodSlice[periodSlice.length - 1].close;
11229
- const highPrices = periodSlice.map((d) => d.high);
11230
- const lowPrices = periodSlice.map((d) => d.low);
11231
- const highestHigh = Math.max(...highPrices);
11232
- const lowestLow = Math.min(...lowPrices);
11233
- const k = highestHigh === lowestLow ? 0 : ((currentClose - lowestLow) / (highestHigh - lowestLow)) * 100;
11234
- kValues.push(k);
11235
- kSum += k;
11236
- if (kValues.length > smoothingFactor)
11237
- kSum -= kValues[kValues.length - smoothingFactor - 1];
11238
- const smoothedK = kSum / Math.min(kValues.length, smoothingFactor);
11239
- dSum += smoothedK;
11240
- if (kValues.length > smoothingFactor + signalPeriod - 1)
11241
- dSum -= kValues[kValues.length - smoothingFactor - signalPeriod];
11242
- const smoothedD = dSum / Math.min(kValues.length - smoothingFactor + 1, signalPeriod);
11243
- if (kValues.length >= smoothingFactor + signalPeriod - 1) {
11244
- result.push({
11245
- date: priceData[i].date,
11246
- slowK: parseFloat(smoothedK.toFixed(2)),
11247
- slowD: parseFloat(smoothedD.toFixed(2)),
11248
- close: currentClose,
11249
- });
11250
- }
11251
- }
11252
- // logIfDebug(`Calculated Stochastic Oscillator for ${result.length} periods`);
11253
- return result;
11254
- }
11255
- /**
11256
- * Calculates support and resistance levels based on price data.
11257
- * Support and resistance levels are price levels at which a stock tends to stop and reverse.
11258
- *
11259
- * @param priceData - An array of price data objects containing high, low, and closing prices.
11260
- * @param params - An object containing optional parameters for the calculation.
11261
- * @param params.maxLevels - The maximum number of support/resistance levels to return (default is 5).
11262
- * @param params.lookbackPeriod - The number of periods to look back for pivot points (default is 10).
11263
- * @returns An array of SupportResistanceData objects containing the calculated levels.
11264
- */
11265
- function calculateSupportAndResistance(priceData, { maxLevels = 5, lookbackPeriod = 10 } = {}) {
11266
- const result = [];
11267
- for (let i = 0; i < priceData.length; i++) {
11268
- const startIdx = Math.max(0, i - lookbackPeriod);
11269
- const analysisWindow = priceData.slice(startIdx, i + 1);
11270
- const pivotPoints = [];
11271
- // **Compute Volatility Metrics**
11272
- const priceChanges = analysisWindow.slice(1).map((bar, idx) => Math.abs(bar.close - analysisWindow[idx].close));
11273
- const avgPriceChange = priceChanges.reduce((sum, change) => sum + change, 0) / priceChanges.length;
11274
- const volatility = avgPriceChange / analysisWindow[0].close; // Relative volatility
11275
- // **Adjust Sensitivity and minGapBetweenLevels Dynamically**
11276
- const sensitivity = volatility * 2; // Adjust the multiplier as needed
11277
- const minGapBetweenLevels = volatility * 100; // Convert to percentage
11278
- // Analyze each point in window for pivot status
11279
- for (let j = 1; j < analysisWindow.length - 1; j++) {
11280
- const curr = analysisWindow[j];
11281
- const prevBar = analysisWindow[j - 1];
11282
- const nextBar = analysisWindow[j + 1];
11283
- // Check for high pivot
11284
- if (curr.high > prevBar.high && curr.high > nextBar.high) {
11285
- const existingPivot = pivotPoints.find((p) => Math.abs(p.price - curr.high) / curr.high < sensitivity);
11286
- if (existingPivot) {
11287
- existingPivot.count++;
11288
- existingPivot.volume += curr.vol; // **Include Volume**
11289
- }
11290
- else {
11291
- pivotPoints.push({ price: curr.high, count: 1, volume: curr.vol });
11292
- }
11293
- }
11294
- // Check for low pivot
11295
- if (curr.low < prevBar.low && curr.low < nextBar.low) {
11296
- const existingPivot = pivotPoints.find((p) => Math.abs(p.price - curr.low) / curr.low < sensitivity);
11297
- if (existingPivot) {
11298
- existingPivot.count++;
11299
- existingPivot.volume += curr.vol; // **Include Volume**
11300
- }
11301
- else {
11302
- pivotPoints.push({ price: curr.low, count: 1, volume: curr.vol });
11303
- }
11304
- }
11305
- }
11306
- // Group nearby levels
11307
- const currentPrice = priceData[i].close;
11308
- const levels = [];
11309
- // Sort pivots by price
11310
- pivotPoints.sort((a, b) => a.price - b.price);
11311
- // Group close pivots
11312
- let currentGroup = [];
11313
- for (let j = 0; j < pivotPoints.length; j++) {
11314
- if (currentGroup.length === 0) {
11315
- currentGroup.push(pivotPoints[j]);
11316
- }
11317
- else {
11318
- const lastPrice = currentGroup[currentGroup.length - 1].price;
11319
- if ((Math.abs(pivotPoints[j].price - lastPrice) / lastPrice) * 100 <= minGapBetweenLevels) {
11320
- currentGroup.push(pivotPoints[j]);
11321
- }
11322
- else {
11323
- // Process current group
11324
- if (currentGroup.length > 0) {
11325
- const totalVolume = currentGroup.reduce((sum, p) => sum + p.volume, 0);
11326
- const avgPrice = currentGroup.reduce((sum, p) => sum + p.price * p.volume, 0) / totalVolume;
11327
- const totalStrength = currentGroup.reduce((sum, p) => sum + p.count * (p.volume / totalVolume), 0);
11328
- levels.push({
11329
- price: parseFloat(avgPrice.toFixed(2)),
11330
- strength: parseFloat(totalStrength.toFixed(2)),
11331
- type: avgPrice > currentPrice ? 'resistance' : 'support',
11332
- });
11333
- }
11334
- currentGroup = [pivotPoints[j]];
11335
- }
11336
- }
11337
- }
11338
- // Process final group
11339
- if (currentGroup.length > 0) {
11340
- const totalVolume = currentGroup.reduce((sum, p) => sum + p.volume, 0);
11341
- const avgPrice = currentGroup.reduce((sum, p) => sum + p.price * p.volume, 0) / totalVolume;
11342
- const totalStrength = currentGroup.reduce((sum, p) => sum + p.count * (p.volume / totalVolume), 0);
11343
- levels.push({
11344
- price: parseFloat(avgPrice.toFixed(2)),
11345
- strength: parseFloat(totalStrength.toFixed(2)),
11346
- type: avgPrice > currentPrice ? 'resistance' : 'support',
11347
- });
11348
- }
11349
- // Sort by strength and limit
11350
- const finalLevels = levels.sort((a, b) => b.strength - a.strength).slice(0, maxLevels);
11351
- result.push({
11352
- date: priceData[i].date,
11353
- levels: finalLevels,
11354
- close: currentPrice,
11355
- });
11356
- }
11357
- logIfDebug(`Found ${result.reduce((sum, r) => sum + r.levels.length, 0)} support/resistance levels across ${result.length} periods`);
11358
- return result;
11359
- }
11360
-
11361
10135
  function getDefaultExportFromCjs (x) {
11362
10136
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
11363
10137
  }
@@ -16342,7 +15116,7 @@ var config = {};
16342
15116
 
16343
15117
  var main = {exports: {}};
16344
15118
 
16345
- var version = "17.2.3";
15119
+ var version = "17.3.1";
16346
15120
  var require$$4 = {
16347
15121
  version: version};
16348
15122
 
@@ -16364,12 +15138,9 @@ function requireMain () {
16364
15138
  '🔐 encrypt with Dotenvx: https://dotenvx.com',
16365
15139
  '🔐 prevent committing .env to code: https://dotenvx.com/precommit',
16366
15140
  '🔐 prevent building .env in docker: https://dotenvx.com/prebuild',
16367
- '📡 add observability to secrets: https://dotenvx.com/ops',
16368
- '👥 sync secrets across teammates & machines: https://dotenvx.com/ops',
16369
- '🗂️ backup and recover secrets: https://dotenvx.com/ops',
16370
- '✅ audit secrets and track compliance: https://dotenvx.com/ops',
16371
- '🔄 add secrets lifecycle management: https://dotenvx.com/ops',
16372
- '🔑 add access controls to secrets: https://dotenvx.com/ops',
15141
+ '🤖 agentic secret storage: https://dotenvx.com/as2',
15142
+ '⚡️ secrets for agents: https://dotenvx.com/as2',
15143
+ '🛡️ auth for agents: https://vestauth.com',
16373
15144
  '🛠️ run anywhere with `dotenvx run -- yourcommand`',
16374
15145
  '⚙️ specify custom .env file path with { path: \'/custom/path/.env\' }',
16375
15146
  '⚙️ enable debug logging with { debug: true }',
@@ -19766,40 +18537,12 @@ const disco = {
19766
18537
  pct: formatPercentage,
19767
18538
  dateTimeForGS: dateTimeForGS,
19768
18539
  },
19769
- indices: {
19770
- fetchAggregates: fetchIndicesAggregates,
19771
- fetchPreviousClose: fetchIndicesPreviousClose,
19772
- fetchDailyOpenClose: fetchIndicesDailyOpenClose,
19773
- fetchSnapshot: fetchIndicesSnapshot,
19774
- fetchUniversalSnapshot: fetchUniversalSnapshot,
19775
- formatBarData: formatIndicesBarData,
19776
- },
19777
18540
  llm: {
19778
18541
  call: makeLLMCall,
19779
18542
  seek: makeDeepseekCall,
19780
18543
  images: makeImagesCall,
19781
18544
  open: makeOpenRouterCall,
19782
18545
  },
19783
- polygon: {
19784
- fetchTickerInfo: fetchTickerInfo,
19785
- fetchGroupedDaily: fetchGroupedDaily,
19786
- fetchLastTrade: fetchLastTrade,
19787
- fetchTrades: fetchTrades,
19788
- fetchPrices: fetchPrices,
19789
- analysePolygonPriceData: analysePolygonPriceData,
19790
- formatPriceData: formatPriceData,
19791
- fetchDailyOpenClose: fetchDailyOpenClose,
19792
- getPreviousClose: getPreviousClose,
19793
- },
19794
- ta: {
19795
- calculateEMA: calculateEMA,
19796
- calculateMACD: calculateMACD,
19797
- calculateRSI: calculateRSI,
19798
- calculateStochasticOscillator: calculateStochasticOscillator,
19799
- calculateBollingerBands: calculateBollingerBands,
19800
- calculateSupportAndResistance: calculateSupportAndResistance,
19801
- calculateFibonacciLevels: calculateFibonacciLevels,
19802
- },
19803
18546
  time: {
19804
18547
  convertDateToMarketTimeZone: convertDateToMarketTimeZone,
19805
18548
  getStartAndEndDates: getStartAndEndDates,
@@ -19822,7 +18565,6 @@ const disco = {
19822
18565
  utils: {
19823
18566
  logIfDebug: logIfDebug,
19824
18567
  fetchWithRetry: fetchWithRetry,
19825
- validatePolygonApiKey: validatePolygonApiKey,
19826
18568
  Timer: PerformanceTimer,
19827
18569
  },
19828
18570
  };