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