@discomedia/utils 1.0.31 → 1.0.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/alpaca-crypto-pairs-DMOvRyzw.js +571 -0
- package/dist/alpaca-crypto-pairs-DMOvRyzw.js.map +1 -0
- package/dist/index-frontend.cjs +355 -4
- package/dist/index-frontend.cjs.map +1 -1
- package/dist/index-frontend.mjs +355 -4
- package/dist/index-frontend.mjs.map +1 -1
- package/dist/index.cjs +356 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +356 -5
- package/dist/index.mjs.map +1 -1
- package/dist/package.json +4 -4
- package/dist/test.js +568 -692
- package/dist/test.js.map +1 -1
- package/dist/types/alpaca-market-data-api.d.ts +60 -1
- package/dist/types/alpaca-market-data-api.d.ts.map +1 -1
- package/dist/types/index-frontend.d.ts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/types/alpaca-crypto-pairs.d.ts +11 -0
- package/dist/types/types/alpaca-crypto-pairs.d.ts.map +1 -0
- package/dist/types/types/alpaca-types.d.ts +146 -0
- package/dist/types/types/alpaca-types.d.ts.map +1 -1
- package/dist/types-frontend/alpaca-market-data-api.d.ts +60 -1
- package/dist/types-frontend/alpaca-market-data-api.d.ts.map +1 -1
- package/dist/types-frontend/index-frontend.d.ts +1 -1
- package/dist/types-frontend/index.d.ts +1 -1
- package/dist/types-frontend/types/alpaca-crypto-pairs.d.ts +11 -0
- package/dist/types-frontend/types/alpaca-crypto-pairs.d.ts.map +1 -0
- package/dist/types-frontend/types/alpaca-types.d.ts +146 -0
- package/dist/types-frontend/types/alpaca-types.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs
CHANGED
|
@@ -1449,7 +1449,7 @@ function pLimit(concurrency) {
|
|
|
1449
1449
|
},
|
|
1450
1450
|
map: {
|
|
1451
1451
|
async value(array, function_) {
|
|
1452
|
-
const promises = array.map(value => this(function_, value));
|
|
1452
|
+
const promises = array.map((value, index) => this(function_, value, index));
|
|
1453
1453
|
return Promise.all(promises);
|
|
1454
1454
|
},
|
|
1455
1455
|
},
|
|
@@ -2395,7 +2395,7 @@ const safeJSON = (text) => {
|
|
|
2395
2395
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
2396
2396
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
2397
2397
|
|
|
2398
|
-
const VERSION = '5.
|
|
2398
|
+
const VERSION = '5.16.0'; // x-release-please-version
|
|
2399
2399
|
|
|
2400
2400
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
2401
2401
|
const isRunningInBrowser = () => {
|
|
@@ -3735,6 +3735,36 @@ class CursorPage extends AbstractPage {
|
|
|
3735
3735
|
};
|
|
3736
3736
|
}
|
|
3737
3737
|
}
|
|
3738
|
+
class ConversationCursorPage extends AbstractPage {
|
|
3739
|
+
constructor(client, response, body, options) {
|
|
3740
|
+
super(client, response, body, options);
|
|
3741
|
+
this.data = body.data || [];
|
|
3742
|
+
this.has_more = body.has_more || false;
|
|
3743
|
+
this.last_id = body.last_id || '';
|
|
3744
|
+
}
|
|
3745
|
+
getPaginatedItems() {
|
|
3746
|
+
return this.data ?? [];
|
|
3747
|
+
}
|
|
3748
|
+
hasNextPage() {
|
|
3749
|
+
if (this.has_more === false) {
|
|
3750
|
+
return false;
|
|
3751
|
+
}
|
|
3752
|
+
return super.hasNextPage();
|
|
3753
|
+
}
|
|
3754
|
+
nextPageRequestOptions() {
|
|
3755
|
+
const cursor = this.last_id;
|
|
3756
|
+
if (!cursor) {
|
|
3757
|
+
return null;
|
|
3758
|
+
}
|
|
3759
|
+
return {
|
|
3760
|
+
...this.options,
|
|
3761
|
+
query: {
|
|
3762
|
+
...maybeObj(this.options.query),
|
|
3763
|
+
after: cursor,
|
|
3764
|
+
},
|
|
3765
|
+
};
|
|
3766
|
+
}
|
|
3767
|
+
}
|
|
3738
3768
|
|
|
3739
3769
|
const checkFileSupport = () => {
|
|
3740
3770
|
if (typeof File === 'undefined') {
|
|
@@ -6825,6 +6855,74 @@ class Containers extends APIResource {
|
|
|
6825
6855
|
}
|
|
6826
6856
|
Containers.Files = Files$2;
|
|
6827
6857
|
|
|
6858
|
+
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
6859
|
+
class Items extends APIResource {
|
|
6860
|
+
/**
|
|
6861
|
+
* Create items in a conversation with the given ID.
|
|
6862
|
+
*/
|
|
6863
|
+
create(conversationID, params, options) {
|
|
6864
|
+
const { include, ...body } = params;
|
|
6865
|
+
return this._client.post(path `/conversations/${conversationID}/items`, {
|
|
6866
|
+
query: { include },
|
|
6867
|
+
body,
|
|
6868
|
+
...options,
|
|
6869
|
+
});
|
|
6870
|
+
}
|
|
6871
|
+
/**
|
|
6872
|
+
* Get a single item from a conversation with the given IDs.
|
|
6873
|
+
*/
|
|
6874
|
+
retrieve(itemID, params, options) {
|
|
6875
|
+
const { conversation_id, ...query } = params;
|
|
6876
|
+
return this._client.get(path `/conversations/${conversation_id}/items/${itemID}`, { query, ...options });
|
|
6877
|
+
}
|
|
6878
|
+
/**
|
|
6879
|
+
* List all items for a conversation with the given ID.
|
|
6880
|
+
*/
|
|
6881
|
+
list(conversationID, query = {}, options) {
|
|
6882
|
+
return this._client.getAPIList(path `/conversations/${conversationID}/items`, (ConversationCursorPage), { query, ...options });
|
|
6883
|
+
}
|
|
6884
|
+
/**
|
|
6885
|
+
* Delete an item from a conversation with the given IDs.
|
|
6886
|
+
*/
|
|
6887
|
+
delete(itemID, params, options) {
|
|
6888
|
+
const { conversation_id } = params;
|
|
6889
|
+
return this._client.delete(path `/conversations/${conversation_id}/items/${itemID}`, options);
|
|
6890
|
+
}
|
|
6891
|
+
}
|
|
6892
|
+
|
|
6893
|
+
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
6894
|
+
class Conversations extends APIResource {
|
|
6895
|
+
constructor() {
|
|
6896
|
+
super(...arguments);
|
|
6897
|
+
this.items = new Items(this._client);
|
|
6898
|
+
}
|
|
6899
|
+
/**
|
|
6900
|
+
* Create a conversation.
|
|
6901
|
+
*/
|
|
6902
|
+
create(body, options) {
|
|
6903
|
+
return this._client.post('/conversations', { body, ...options });
|
|
6904
|
+
}
|
|
6905
|
+
/**
|
|
6906
|
+
* Get a conversation with the given ID.
|
|
6907
|
+
*/
|
|
6908
|
+
retrieve(conversationID, options) {
|
|
6909
|
+
return this._client.get(path `/conversations/${conversationID}`, options);
|
|
6910
|
+
}
|
|
6911
|
+
/**
|
|
6912
|
+
* Update a conversation's metadata with the given ID.
|
|
6913
|
+
*/
|
|
6914
|
+
update(conversationID, body, options) {
|
|
6915
|
+
return this._client.post(path `/conversations/${conversationID}`, { body, ...options });
|
|
6916
|
+
}
|
|
6917
|
+
/**
|
|
6918
|
+
* Delete a conversation with the given ID.
|
|
6919
|
+
*/
|
|
6920
|
+
delete(conversationID, options) {
|
|
6921
|
+
return this._client.delete(path `/conversations/${conversationID}`, options);
|
|
6922
|
+
}
|
|
6923
|
+
}
|
|
6924
|
+
Conversations.Items = Items;
|
|
6925
|
+
|
|
6828
6926
|
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
|
|
6829
6927
|
class Embeddings extends APIResource {
|
|
6830
6928
|
/**
|
|
@@ -6989,7 +7087,7 @@ let Files$1 = class Files extends APIResource {
|
|
|
6989
7087
|
/**
|
|
6990
7088
|
* Upload a file that can be used across various endpoints. Individual files can be
|
|
6991
7089
|
* up to 512 MB, and the size of all files uploaded by one organization can be up
|
|
6992
|
-
* to
|
|
7090
|
+
* to 1 TB.
|
|
6993
7091
|
*
|
|
6994
7092
|
* The Assistants API supports files up to 2 million tokens and of specific file
|
|
6995
7093
|
* types. See the
|
|
@@ -8418,6 +8516,7 @@ class OpenAI {
|
|
|
8418
8516
|
this.batches = new Batches(this);
|
|
8419
8517
|
this.uploads = new Uploads(this);
|
|
8420
8518
|
this.responses = new Responses(this);
|
|
8519
|
+
this.conversations = new Conversations(this);
|
|
8421
8520
|
this.evals = new Evals(this);
|
|
8422
8521
|
this.containers = new Containers(this);
|
|
8423
8522
|
if (apiKey === undefined) {
|
|
@@ -8808,7 +8907,7 @@ class OpenAI {
|
|
|
8808
8907
|
// Preserve legacy string encoding behavior for now
|
|
8809
8908
|
headers.values.has('content-type')) ||
|
|
8810
8909
|
// `Blob` is superset of `File`
|
|
8811
|
-
body instanceof Blob ||
|
|
8910
|
+
(globalThis.Blob && body instanceof globalThis.Blob) ||
|
|
8812
8911
|
// `FormData` -> `multipart/form-data`
|
|
8813
8912
|
body instanceof FormData ||
|
|
8814
8913
|
// `URLSearchParams` -> `application/x-www-form-urlencoded`
|
|
@@ -8863,6 +8962,7 @@ OpenAI.Beta = Beta;
|
|
|
8863
8962
|
OpenAI.Batches = Batches;
|
|
8864
8963
|
OpenAI.Uploads = Uploads;
|
|
8865
8964
|
OpenAI.Responses = Responses;
|
|
8965
|
+
OpenAI.Conversations = Conversations;
|
|
8866
8966
|
OpenAI.Evals = Evals;
|
|
8867
8967
|
OpenAI.Containers = Containers;
|
|
8868
8968
|
|
|
@@ -16215,6 +16315,7 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
|
|
|
16215
16315
|
dataURL;
|
|
16216
16316
|
apiURL;
|
|
16217
16317
|
v1beta1url;
|
|
16318
|
+
v1beta3url;
|
|
16218
16319
|
stockStreamUrl = 'wss://stream.data.alpaca.markets/v2/sip'; // production values
|
|
16219
16320
|
optionStreamUrl = 'wss://stream.data.alpaca.markets/v1beta3/options'; // production values
|
|
16220
16321
|
stockWs = null;
|
|
@@ -16257,6 +16358,7 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
|
|
|
16257
16358
|
? 'https://paper-api.alpaca.markets/v2'
|
|
16258
16359
|
: 'https://api.alpaca.markets/v2'; // used by some, e.g. getAssets
|
|
16259
16360
|
this.v1beta1url = 'https://data.alpaca.markets/v1beta1'; // used for options endpoints
|
|
16361
|
+
this.v1beta3url = 'https://data.alpaca.markets/v1beta3'; // used for crypto endpoints
|
|
16260
16362
|
this.setMode('production'); // sets stockStreamUrl and optionStreamUrl
|
|
16261
16363
|
this.headers = {
|
|
16262
16364
|
'APCA-API-KEY-ID': process.env.ALPACA_API_KEY,
|
|
@@ -16394,7 +16496,9 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
|
|
|
16394
16496
|
}
|
|
16395
16497
|
}
|
|
16396
16498
|
async makeRequest(endpoint, method = 'GET', params, baseUrlName = 'data') {
|
|
16397
|
-
const baseUrl = baseUrlName === 'data' ? this.dataURL :
|
|
16499
|
+
const baseUrl = baseUrlName === 'data' ? this.dataURL :
|
|
16500
|
+
baseUrlName === 'api' ? this.apiURL :
|
|
16501
|
+
baseUrlName === 'v1beta1' ? this.v1beta1url : this.v1beta3url;
|
|
16398
16502
|
const url = new URL(`${baseUrl}${endpoint}`);
|
|
16399
16503
|
try {
|
|
16400
16504
|
if (params) {
|
|
@@ -17102,6 +17206,253 @@ class AlpacaMarketDataAPI extends require$$0$3.EventEmitter {
|
|
|
17102
17206
|
}
|
|
17103
17207
|
return newsArticles;
|
|
17104
17208
|
}
|
|
17209
|
+
// ===== CRYPTO MARKET DATA METHODS =====
|
|
17210
|
+
/**
|
|
17211
|
+
* Get historical OHLCV bars for crypto symbols
|
|
17212
|
+
* Automatically handles pagination to fetch all available data
|
|
17213
|
+
* @param params Parameters for crypto historical bars request
|
|
17214
|
+
* @returns Historical bars data with all pages combined
|
|
17215
|
+
*/
|
|
17216
|
+
async getCryptoHistoricalBars(params) {
|
|
17217
|
+
const symbols = params.symbols;
|
|
17218
|
+
const symbolsStr = symbols.join(',');
|
|
17219
|
+
let allBars = {};
|
|
17220
|
+
let pageToken = null;
|
|
17221
|
+
let hasMorePages = true;
|
|
17222
|
+
let totalBarsCount = 0;
|
|
17223
|
+
let pageCount = 0;
|
|
17224
|
+
// Initialize bar arrays for each symbol
|
|
17225
|
+
symbols.forEach((symbol) => {
|
|
17226
|
+
allBars[symbol] = [];
|
|
17227
|
+
});
|
|
17228
|
+
log(`Starting crypto historical bars fetch for ${symbols.length} symbols (${params.timeframe}, ${params.start || 'no start'} to ${params.end || 'no end'})`, { type: 'info' });
|
|
17229
|
+
while (hasMorePages) {
|
|
17230
|
+
pageCount++;
|
|
17231
|
+
const requestParams = {
|
|
17232
|
+
...params,
|
|
17233
|
+
symbols: symbolsStr,
|
|
17234
|
+
...(pageToken && { page_token: pageToken }),
|
|
17235
|
+
};
|
|
17236
|
+
const response = await this.makeRequest('/crypto/us/bars', 'GET', requestParams, 'v1beta3');
|
|
17237
|
+
if (!response.bars) {
|
|
17238
|
+
log(`No crypto bars data found in response for ${symbols.length} symbols`, { type: 'warn' });
|
|
17239
|
+
break;
|
|
17240
|
+
}
|
|
17241
|
+
// Combine bars for each symbol
|
|
17242
|
+
let pageBarsCount = 0;
|
|
17243
|
+
Object.entries(response.bars).forEach(([symbol, bars]) => {
|
|
17244
|
+
if (bars && bars.length > 0) {
|
|
17245
|
+
allBars[symbol] = [...allBars[symbol], ...bars];
|
|
17246
|
+
pageBarsCount += bars.length;
|
|
17247
|
+
}
|
|
17248
|
+
});
|
|
17249
|
+
totalBarsCount += pageBarsCount;
|
|
17250
|
+
pageToken = response.next_page_token || null;
|
|
17251
|
+
hasMorePages = !!pageToken;
|
|
17252
|
+
log(`Page ${pageCount}: Fetched ${pageBarsCount.toLocaleString()} crypto bars (total: ${totalBarsCount.toLocaleString()}) for ${symbols.length} symbols${hasMorePages ? ', more pages available' : ', complete'}`);
|
|
17253
|
+
// Prevent infinite loops
|
|
17254
|
+
if (pageCount > 1000) {
|
|
17255
|
+
log(`Stopping crypto bars pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });
|
|
17256
|
+
break;
|
|
17257
|
+
}
|
|
17258
|
+
}
|
|
17259
|
+
log(`Crypto historical bars fetch complete: ${totalBarsCount.toLocaleString()} total bars across ${pageCount} pages`, { type: 'info' });
|
|
17260
|
+
return {
|
|
17261
|
+
bars: allBars,
|
|
17262
|
+
next_page_token: null, // Always null since we fetch all pages
|
|
17263
|
+
};
|
|
17264
|
+
}
|
|
17265
|
+
/**
|
|
17266
|
+
* Get the most recent minute bar for requested crypto symbols
|
|
17267
|
+
* @param symbols Array of crypto symbols to query
|
|
17268
|
+
* @returns Latest bar data for each symbol
|
|
17269
|
+
*/
|
|
17270
|
+
async getCryptoLatestBars(symbols) {
|
|
17271
|
+
return this.makeRequest('/crypto/us/latest/bars', 'GET', { symbols: symbols.join(',') }, 'v1beta3');
|
|
17272
|
+
}
|
|
17273
|
+
/**
|
|
17274
|
+
* Get historical quotes for crypto symbols
|
|
17275
|
+
* Automatically handles pagination to fetch all available data
|
|
17276
|
+
* @param params Parameters for crypto historical quotes request
|
|
17277
|
+
* @returns Historical quotes data with all pages combined
|
|
17278
|
+
*/
|
|
17279
|
+
async getCryptoHistoricalQuotes(params) {
|
|
17280
|
+
const symbols = params.symbols;
|
|
17281
|
+
const symbolsStr = symbols.join(',');
|
|
17282
|
+
let allQuotes = {};
|
|
17283
|
+
let pageToken = null;
|
|
17284
|
+
let hasMorePages = true;
|
|
17285
|
+
let totalQuotesCount = 0;
|
|
17286
|
+
let pageCount = 0;
|
|
17287
|
+
// Initialize quotes arrays for each symbol
|
|
17288
|
+
symbols.forEach((symbol) => {
|
|
17289
|
+
allQuotes[symbol] = [];
|
|
17290
|
+
});
|
|
17291
|
+
log(`Starting crypto historical quotes fetch for ${symbols.length} symbols (${params.start || 'no start'} to ${params.end || 'no end'})`, { type: 'info' });
|
|
17292
|
+
while (hasMorePages) {
|
|
17293
|
+
pageCount++;
|
|
17294
|
+
const requestParams = {
|
|
17295
|
+
...params,
|
|
17296
|
+
symbols: symbolsStr,
|
|
17297
|
+
...(pageToken && { page_token: pageToken }),
|
|
17298
|
+
};
|
|
17299
|
+
const response = await this.makeRequest('/crypto/us/quotes', 'GET', requestParams, 'v1beta3');
|
|
17300
|
+
if (!response.quotes) {
|
|
17301
|
+
log(`No crypto quotes data found in response for ${symbols.length} symbols`, { type: 'warn' });
|
|
17302
|
+
break;
|
|
17303
|
+
}
|
|
17304
|
+
// Combine quotes for each symbol
|
|
17305
|
+
let pageQuotesCount = 0;
|
|
17306
|
+
Object.entries(response.quotes).forEach(([symbol, quotes]) => {
|
|
17307
|
+
if (quotes && quotes.length > 0) {
|
|
17308
|
+
allQuotes[symbol] = [...allQuotes[symbol], ...quotes];
|
|
17309
|
+
pageQuotesCount += quotes.length;
|
|
17310
|
+
}
|
|
17311
|
+
});
|
|
17312
|
+
totalQuotesCount += pageQuotesCount;
|
|
17313
|
+
pageToken = response.next_page_token || null;
|
|
17314
|
+
hasMorePages = !!pageToken;
|
|
17315
|
+
log(`Page ${pageCount}: Fetched ${pageQuotesCount.toLocaleString()} crypto quotes (total: ${totalQuotesCount.toLocaleString()}) for ${symbols.length} symbols${hasMorePages ? ', more pages available' : ', complete'}`);
|
|
17316
|
+
// Prevent infinite loops
|
|
17317
|
+
if (pageCount > 1000) {
|
|
17318
|
+
log(`Stopping crypto quotes pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });
|
|
17319
|
+
break;
|
|
17320
|
+
}
|
|
17321
|
+
}
|
|
17322
|
+
log(`Crypto historical quotes fetch complete: ${totalQuotesCount.toLocaleString()} total quotes across ${pageCount} pages`, { type: 'info' });
|
|
17323
|
+
return {
|
|
17324
|
+
quotes: allQuotes,
|
|
17325
|
+
next_page_token: null, // Always null since we fetch all pages
|
|
17326
|
+
};
|
|
17327
|
+
}
|
|
17328
|
+
/**
|
|
17329
|
+
* Get the most recent quotes for requested crypto symbols
|
|
17330
|
+
* @param symbols Array of crypto symbols to query
|
|
17331
|
+
* @returns Latest quote data for each symbol
|
|
17332
|
+
*/
|
|
17333
|
+
async getCryptoLatestQuotes(symbols) {
|
|
17334
|
+
if (!symbols || symbols.length === 0) {
|
|
17335
|
+
log('No symbols provided to getCryptoLatestQuotes, returning empty response', { type: 'warn' });
|
|
17336
|
+
return { quotes: {} };
|
|
17337
|
+
}
|
|
17338
|
+
return this.makeRequest('/crypto/us/latest/quotes', 'GET', { symbols: symbols.join(',') }, 'v1beta3');
|
|
17339
|
+
}
|
|
17340
|
+
/**
|
|
17341
|
+
* Get historical trades for crypto symbols
|
|
17342
|
+
* Automatically handles pagination to fetch all available data
|
|
17343
|
+
* @param params Parameters for crypto historical trades request
|
|
17344
|
+
* @returns Historical trades data with all pages combined
|
|
17345
|
+
*/
|
|
17346
|
+
async getCryptoHistoricalTrades(params) {
|
|
17347
|
+
const symbols = params.symbols;
|
|
17348
|
+
const symbolsStr = symbols.join(',');
|
|
17349
|
+
let allTrades = {};
|
|
17350
|
+
let pageToken = null;
|
|
17351
|
+
let hasMorePages = true;
|
|
17352
|
+
let totalTradesCount = 0;
|
|
17353
|
+
let pageCount = 0;
|
|
17354
|
+
// Initialize trades arrays for each symbol
|
|
17355
|
+
symbols.forEach((symbol) => {
|
|
17356
|
+
allTrades[symbol] = [];
|
|
17357
|
+
});
|
|
17358
|
+
log(`Starting crypto historical trades fetch for ${symbols.length} symbols (${params.start || 'no start'} to ${params.end || 'no end'})`, { type: 'info' });
|
|
17359
|
+
while (hasMorePages) {
|
|
17360
|
+
pageCount++;
|
|
17361
|
+
const requestParams = {
|
|
17362
|
+
...params,
|
|
17363
|
+
symbols: symbolsStr,
|
|
17364
|
+
...(pageToken && { page_token: pageToken }),
|
|
17365
|
+
};
|
|
17366
|
+
const response = await this.makeRequest('/crypto/us/trades', 'GET', requestParams, 'v1beta3');
|
|
17367
|
+
if (!response.trades) {
|
|
17368
|
+
log(`No crypto trades data found in response for ${symbols.length} symbols`, { type: 'warn' });
|
|
17369
|
+
break;
|
|
17370
|
+
}
|
|
17371
|
+
// Combine trades for each symbol
|
|
17372
|
+
let pageTradesCount = 0;
|
|
17373
|
+
Object.entries(response.trades).forEach(([symbol, trades]) => {
|
|
17374
|
+
if (trades && trades.length > 0) {
|
|
17375
|
+
allTrades[symbol] = [...allTrades[symbol], ...trades];
|
|
17376
|
+
pageTradesCount += trades.length;
|
|
17377
|
+
}
|
|
17378
|
+
});
|
|
17379
|
+
totalTradesCount += pageTradesCount;
|
|
17380
|
+
pageToken = response.next_page_token || null;
|
|
17381
|
+
hasMorePages = !!pageToken;
|
|
17382
|
+
log(`Page ${pageCount}: Fetched ${pageTradesCount.toLocaleString()} crypto trades (total: ${totalTradesCount.toLocaleString()}) for ${symbols.length} symbols${hasMorePages ? ', more pages available' : ', complete'}`);
|
|
17383
|
+
// Prevent infinite loops
|
|
17384
|
+
if (pageCount > 1000) {
|
|
17385
|
+
log(`Stopping crypto trades pagination after ${pageCount} pages to prevent infinite loop`, { type: 'warn' });
|
|
17386
|
+
break;
|
|
17387
|
+
}
|
|
17388
|
+
}
|
|
17389
|
+
log(`Crypto historical trades fetch complete: ${totalTradesCount.toLocaleString()} total trades across ${pageCount} pages`, { type: 'info' });
|
|
17390
|
+
return {
|
|
17391
|
+
trades: allTrades,
|
|
17392
|
+
next_page_token: null, // Always null since we fetch all pages
|
|
17393
|
+
};
|
|
17394
|
+
}
|
|
17395
|
+
/**
|
|
17396
|
+
* Get the most recent trades for requested crypto symbols
|
|
17397
|
+
* @param symbols Array of crypto symbols to query
|
|
17398
|
+
* @returns Latest trade data for each symbol
|
|
17399
|
+
*/
|
|
17400
|
+
async getCryptoLatestTrades(symbols) {
|
|
17401
|
+
if (!symbols || symbols.length === 0) {
|
|
17402
|
+
log('No symbols provided to getCryptoLatestTrades, returning empty response', { type: 'warn' });
|
|
17403
|
+
return { trades: {} };
|
|
17404
|
+
}
|
|
17405
|
+
return this.makeRequest('/crypto/us/latest/trades', 'GET', { symbols: symbols.join(',') }, 'v1beta3');
|
|
17406
|
+
}
|
|
17407
|
+
/**
|
|
17408
|
+
* Get snapshots for crypto symbols
|
|
17409
|
+
* Returns the latest trade, latest quote, latest minute bar, latest daily bar, and previous daily bar data
|
|
17410
|
+
* @param symbols Array of crypto symbols to query
|
|
17411
|
+
* @returns Snapshot data for each symbol
|
|
17412
|
+
*/
|
|
17413
|
+
async getCryptoSnapshots(symbols) {
|
|
17414
|
+
if (!symbols || symbols.length === 0) {
|
|
17415
|
+
log('No symbols provided to getCryptoSnapshots, returning empty response', { type: 'warn' });
|
|
17416
|
+
return { snapshots: {} };
|
|
17417
|
+
}
|
|
17418
|
+
return this.makeRequest('/crypto/us/snapshots', 'GET', { symbols: symbols.join(',') }, 'v1beta3');
|
|
17419
|
+
}
|
|
17420
|
+
/**
|
|
17421
|
+
* Get the latest orderbook for requested crypto symbols
|
|
17422
|
+
* @param symbols Array of crypto symbols to query
|
|
17423
|
+
* @returns Latest orderbook data for each symbol
|
|
17424
|
+
*/
|
|
17425
|
+
async getCryptoLatestOrderbooks(symbols) {
|
|
17426
|
+
if (!symbols || symbols.length === 0) {
|
|
17427
|
+
log('No symbols provided to getCryptoLatestOrderbooks, returning empty response', { type: 'warn' });
|
|
17428
|
+
return { orderbooks: {} };
|
|
17429
|
+
}
|
|
17430
|
+
return this.makeRequest('/crypto/us/latest/orderbooks', 'GET', { symbols: symbols.join(',') }, 'v1beta3');
|
|
17431
|
+
}
|
|
17432
|
+
/**
|
|
17433
|
+
* Analyzes an array of crypto bars and returns a summary string
|
|
17434
|
+
* @param bars Array of crypto bars to analyze
|
|
17435
|
+
* @returns A string summarizing the crypto price data
|
|
17436
|
+
*/
|
|
17437
|
+
static analyzeCryptoBars(bars) {
|
|
17438
|
+
if (!bars || bars.length === 0) {
|
|
17439
|
+
return 'No crypto price data available';
|
|
17440
|
+
}
|
|
17441
|
+
const firstBar = bars[0];
|
|
17442
|
+
const lastBar = bars[bars.length - 1];
|
|
17443
|
+
const priceChange = lastBar.c - firstBar.o;
|
|
17444
|
+
const percentChange = (priceChange / firstBar.o) * 100;
|
|
17445
|
+
const volumeChange = lastBar.v - firstBar.v;
|
|
17446
|
+
const percentVolumeChange = firstBar.v > 0 ? (volumeChange / firstBar.v) * 100 : 0;
|
|
17447
|
+
const high = Math.max(...bars.map((bar) => bar.h));
|
|
17448
|
+
const low = Math.min(...bars.map((bar) => bar.l));
|
|
17449
|
+
const totalVolume = bars.reduce((sum, bar) => sum + bar.v, 0);
|
|
17450
|
+
const avgVolume = totalVolume / bars.length;
|
|
17451
|
+
return (`Crypto Price: $${firstBar.o.toFixed(6)} -> $${lastBar.c.toFixed(6)} (${percentChange.toFixed(2)}%), ` +
|
|
17452
|
+
`Volume: ${firstBar.v.toLocaleString()} -> ${lastBar.v.toLocaleString()} (${percentVolumeChange.toFixed(2)}%), ` +
|
|
17453
|
+
`High: $${high.toFixed(6)}, Low: $${low.toFixed(6)}, ` +
|
|
17454
|
+
`Avg Volume: ${avgVolume.toLocaleString()}`);
|
|
17455
|
+
}
|
|
17105
17456
|
}
|
|
17106
17457
|
// Export the singleton instance
|
|
17107
17458
|
const marketDataAPI = AlpacaMarketDataAPI.getInstance();
|