@adaptic/utils 0.0.961 → 0.0.963
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/index.cjs +122 -68
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +122 -68
- package/dist/index.mjs.map +1 -1
- package/dist/types/alpaca/client.d.ts +10 -0
- package/dist/types/alpaca/client.d.ts.map +1 -1
- package/dist/types/alpaca/market-data/bars.d.ts.map +1 -1
- package/dist/types/alpaca/market-data/quotes.d.ts.map +1 -1
- package/dist/types/alpaca/market-data/trades.d.ts.map +1 -1
- package/dist/types/alpaca/trading/clock.d.ts.map +1 -1
- package/dist/types/alpaca/trading/orders.d.ts.map +1 -1
- package/dist/types/alpaca/trading/positions.d.ts.map +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/massive-indices.d.ts.map +1 -1
- package/dist/types/massive.d.ts.map +1 -1
- package/dist/types/rate-limiter.d.ts +6 -3
- package/dist/types/rate-limiter.d.ts.map +1 -1
- package/dist/types/trading-policy/schemas/effective-policy.schema.d.ts +6 -6
- package/dist/types/trading-policy/schemas/overlay-response-prefs.schema.d.ts +8 -8
- package/dist/types/trading-policy/schemas/policy-mutation.schema.d.ts +12 -12
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -7845,24 +7845,27 @@ const rateLimiters = {
|
|
|
7845
7845
|
/**
|
|
7846
7846
|
* Alpaca API rate limiter
|
|
7847
7847
|
*
|
|
7848
|
-
* Configured for
|
|
7848
|
+
* Configured for 1000 requests per minute (paid tier).
|
|
7849
|
+
* The token bucket allows burst up to maxTokens, then refills at the steady rate.
|
|
7849
7850
|
* See: https://alpaca.markets/docs/api-references/trading-api/#rate-limit
|
|
7850
7851
|
*/
|
|
7851
7852
|
alpaca: new TokenBucketRateLimiter({
|
|
7852
|
-
maxTokens:
|
|
7853
|
-
refillRate:
|
|
7853
|
+
maxTokens: 1000,
|
|
7854
|
+
refillRate: 1000 / 60, // 1000 requests per 60 seconds (~16.67/sec)
|
|
7854
7855
|
label: "alpaca",
|
|
7855
7856
|
timeoutMs: 60000,
|
|
7856
7857
|
}),
|
|
7857
7858
|
/**
|
|
7858
7859
|
* Massive.com API rate limiter
|
|
7859
7860
|
*
|
|
7860
|
-
* Configured for
|
|
7861
|
-
*
|
|
7861
|
+
* Configured generously for paid unlimited tier. The bucket exists only as a
|
|
7862
|
+
* safety net against runaway loops — the 1000 token burst and 500/sec refill
|
|
7863
|
+
* should never be hit under normal operation. If the paid plan truly has no
|
|
7864
|
+
* hard limit, this just prevents accidental self-DDoS.
|
|
7862
7865
|
*/
|
|
7863
7866
|
massive: new TokenBucketRateLimiter({
|
|
7864
|
-
maxTokens:
|
|
7865
|
-
refillRate:
|
|
7867
|
+
maxTokens: 1000,
|
|
7868
|
+
refillRate: 500, // 500 tokens/sec refill — effectively unlimited for paid tier
|
|
7866
7869
|
label: "massive",
|
|
7867
7870
|
timeoutMs: 30000,
|
|
7868
7871
|
}),
|
|
@@ -8016,8 +8019,9 @@ const fetchTickerInfo = async (symbol, options) => {
|
|
|
8016
8019
|
apiKey,
|
|
8017
8020
|
});
|
|
8018
8021
|
return massiveLimit(async () => {
|
|
8022
|
+
await rateLimiters.massive.acquire();
|
|
8019
8023
|
try {
|
|
8020
|
-
const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, {}, 3, 1000);
|
|
8024
|
+
const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 1000);
|
|
8021
8025
|
const data = await response.json();
|
|
8022
8026
|
// Check for "NOT_FOUND" status and return null
|
|
8023
8027
|
if (data.status === "NOT_FOUND") {
|
|
@@ -8128,8 +8132,9 @@ const fetchLastTradeImpl = async (symbol, options) => {
|
|
|
8128
8132
|
order: "desc",
|
|
8129
8133
|
});
|
|
8130
8134
|
return massiveLimit(async () => {
|
|
8135
|
+
await rateLimiters.massive.acquire();
|
|
8131
8136
|
try {
|
|
8132
|
-
const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, {}, 3, 1000);
|
|
8137
|
+
const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 1000);
|
|
8133
8138
|
const data = (await response.json());
|
|
8134
8139
|
if ("message" in data) {
|
|
8135
8140
|
throw new Error(`Massive.com API error: ${data.message}`);
|
|
@@ -8198,8 +8203,9 @@ const fetchLastQuote = async (symbol, options) => {
|
|
|
8198
8203
|
order: "desc",
|
|
8199
8204
|
});
|
|
8200
8205
|
return massiveLimit(async () => {
|
|
8206
|
+
await rateLimiters.massive.acquire();
|
|
8201
8207
|
try {
|
|
8202
|
-
const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, {}, 3, 1000);
|
|
8208
|
+
const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 1000);
|
|
8203
8209
|
const data = (await response.json());
|
|
8204
8210
|
if ("message" in data) {
|
|
8205
8211
|
throw new Error(`Massive.com API error: ${data.message}`);
|
|
@@ -8282,7 +8288,7 @@ const fetchPrices = async (params, options) => {
|
|
|
8282
8288
|
while (nextUrl) {
|
|
8283
8289
|
//getLogger().info(`Debug: Fetching ${nextUrl}`);
|
|
8284
8290
|
await rateLimiters.massive.acquire();
|
|
8285
|
-
const response = await fetchWithRetry(nextUrl, {}, 3, 1000);
|
|
8291
|
+
const response = await fetchWithRetry(nextUrl, { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 1000);
|
|
8286
8292
|
const data = await response.json();
|
|
8287
8293
|
if (!MASSIVE_VALID_STATUSES.has(data.status)) {
|
|
8288
8294
|
throw new Error(`Massive.com API responded with status: ${data.status}`);
|
|
@@ -8403,8 +8409,9 @@ const fetchGroupedDaily = async (date, options) => {
|
|
|
8403
8409
|
include_otc: options?.includeOTC ? "true" : "false",
|
|
8404
8410
|
});
|
|
8405
8411
|
return massiveLimit(async () => {
|
|
8412
|
+
await rateLimiters.massive.acquire();
|
|
8406
8413
|
try {
|
|
8407
|
-
const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, {}, 3, 1000);
|
|
8414
|
+
const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 1000);
|
|
8408
8415
|
const data = await response.json();
|
|
8409
8416
|
if (!MASSIVE_VALID_STATUSES.has(data.status)) {
|
|
8410
8417
|
throw new Error(`Massive.com API responded with status: ${data.status}`);
|
|
@@ -8496,12 +8503,20 @@ symbol, date = new Date(), options) => {
|
|
|
8496
8503
|
adjusted: (options?.adjusted ?? true).toString(),
|
|
8497
8504
|
});
|
|
8498
8505
|
return massiveLimit(async () => {
|
|
8499
|
-
|
|
8500
|
-
|
|
8501
|
-
|
|
8502
|
-
|
|
8506
|
+
await rateLimiters.massive.acquire();
|
|
8507
|
+
try {
|
|
8508
|
+
const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 1000);
|
|
8509
|
+
const data = await response.json();
|
|
8510
|
+
if (!MASSIVE_VALID_STATUSES.has(data.status)) {
|
|
8511
|
+
throw new Error(`Failed to fetch daily open/close data for ${symbol}: ${data.status}`);
|
|
8512
|
+
}
|
|
8513
|
+
return data;
|
|
8514
|
+
}
|
|
8515
|
+
catch (error) {
|
|
8516
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
8517
|
+
getLogger().error(`Error fetching daily open/close for ${symbol}: ${errorMessage}`);
|
|
8518
|
+
throw error;
|
|
8503
8519
|
}
|
|
8504
|
-
return data;
|
|
8505
8520
|
});
|
|
8506
8521
|
};
|
|
8507
8522
|
/**
|
|
@@ -8562,10 +8577,11 @@ const fetchTrades = async (symbol, options) => {
|
|
|
8562
8577
|
if (options?.sort)
|
|
8563
8578
|
params.append("sort", options.sort);
|
|
8564
8579
|
return massiveLimit(async () => {
|
|
8580
|
+
await rateLimiters.massive.acquire();
|
|
8565
8581
|
const url = `${baseUrl}?${params.toString()}`;
|
|
8566
8582
|
try {
|
|
8567
8583
|
logIfDebug(`Fetching trades for ${symbol} from ${url}`);
|
|
8568
|
-
const response = await fetchWithRetry(url, {}, 3, 1000);
|
|
8584
|
+
const response = await fetchWithRetry(url, { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 1000);
|
|
8569
8585
|
const data = (await response.json());
|
|
8570
8586
|
if ("message" in data) {
|
|
8571
8587
|
// This is an error response
|
|
@@ -8641,8 +8657,9 @@ const fetchIndicesAggregates = async (params, options) => {
|
|
|
8641
8657
|
}
|
|
8642
8658
|
url.search = queryParams.toString();
|
|
8643
8659
|
return massiveIndicesLimit(async () => {
|
|
8660
|
+
await rateLimiters.massive.acquire();
|
|
8644
8661
|
try {
|
|
8645
|
-
const response = await fetchWithRetry(url.toString(), {}, 3, 300);
|
|
8662
|
+
const response = await fetchWithRetry(url.toString(), { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 300);
|
|
8646
8663
|
const data = await response.json();
|
|
8647
8664
|
if (data.status === "ERROR") {
|
|
8648
8665
|
throw new Error(`Massive API Error: ${data.error}`);
|
|
@@ -8670,8 +8687,9 @@ const fetchIndicesPreviousClose = async (indicesTicker, options) => {
|
|
|
8670
8687
|
queryParams.append("apiKey", apiKey);
|
|
8671
8688
|
url.search = queryParams.toString();
|
|
8672
8689
|
return massiveIndicesLimit(async () => {
|
|
8690
|
+
await rateLimiters.massive.acquire();
|
|
8673
8691
|
try {
|
|
8674
|
-
const response = await fetchWithRetry(url.toString(), {}, 3, 300);
|
|
8692
|
+
const response = await fetchWithRetry(url.toString(), { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 300);
|
|
8675
8693
|
const data = await response.json();
|
|
8676
8694
|
if (data.status === "ERROR") {
|
|
8677
8695
|
throw new Error(`Massive API Error: ${data.error}`);
|
|
@@ -8700,8 +8718,9 @@ const fetchIndicesDailyOpenClose = async (indicesTicker, date, options) => {
|
|
|
8700
8718
|
queryParams.append("apiKey", apiKey);
|
|
8701
8719
|
url.search = queryParams.toString();
|
|
8702
8720
|
return massiveIndicesLimit(async () => {
|
|
8721
|
+
await rateLimiters.massive.acquire();
|
|
8703
8722
|
try {
|
|
8704
|
-
const response = await fetchWithRetry(url.toString(), {}, 3, 300);
|
|
8723
|
+
const response = await fetchWithRetry(url.toString(), { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 300);
|
|
8705
8724
|
const data = await response.json();
|
|
8706
8725
|
if (data.status === "ERROR") {
|
|
8707
8726
|
throw new Error(`Massive API Error: ${data.error}`);
|
|
@@ -8741,8 +8760,9 @@ const fetchIndicesSnapshot = async (params, options) => {
|
|
|
8741
8760
|
}
|
|
8742
8761
|
url.search = queryParams.toString();
|
|
8743
8762
|
return massiveIndicesLimit(async () => {
|
|
8763
|
+
await rateLimiters.massive.acquire();
|
|
8744
8764
|
try {
|
|
8745
|
-
const response = await fetchWithRetry(url.toString(), {}, 3, 300);
|
|
8765
|
+
const response = await fetchWithRetry(url.toString(), { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 300);
|
|
8746
8766
|
const data = await response.json();
|
|
8747
8767
|
if (data.status === "ERROR") {
|
|
8748
8768
|
throw new Error(`Massive API Error: ${data.error}`);
|
|
@@ -8789,8 +8809,9 @@ const fetchUniversalSnapshot = async (tickers, options) => {
|
|
|
8789
8809
|
}
|
|
8790
8810
|
url.search = queryParams.toString();
|
|
8791
8811
|
return massiveIndicesLimit(async () => {
|
|
8812
|
+
await rateLimiters.massive.acquire();
|
|
8792
8813
|
try {
|
|
8793
|
-
const response = await fetchWithRetry(url.toString(), {}, 3, 300);
|
|
8814
|
+
const response = await fetchWithRetry(url.toString(), { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 300);
|
|
8794
8815
|
const data = await response.json();
|
|
8795
8816
|
if (data.status === "ERROR") {
|
|
8796
8817
|
throw new Error(`Massive API Error: ${data.error}`);
|
|
@@ -48979,6 +49000,25 @@ class AlpacaClient {
|
|
|
48979
49000
|
isPaper() {
|
|
48980
49001
|
return this.config.accountType === "PAPER";
|
|
48981
49002
|
}
|
|
49003
|
+
/**
|
|
49004
|
+
* Execute an Alpaca SDK operation with rate limiting and retry.
|
|
49005
|
+
* Use this for all SDK calls to prevent rate limit breaches and handle
|
|
49006
|
+
* transient failures during market hours.
|
|
49007
|
+
*
|
|
49008
|
+
* @param operation - Async function that calls the SDK
|
|
49009
|
+
* @param label - Human-readable label for logging
|
|
49010
|
+
* @returns Result of the operation
|
|
49011
|
+
*/
|
|
49012
|
+
async executeWithRateLimit(operation, label) {
|
|
49013
|
+
await rateLimiters.alpaca.acquire();
|
|
49014
|
+
return withRetry(operation, {
|
|
49015
|
+
maxRetries: 2,
|
|
49016
|
+
baseDelayMs: 1000,
|
|
49017
|
+
maxDelayMs: 10000,
|
|
49018
|
+
retryableStatusCodes: [429, 500, 502, 503, 504],
|
|
49019
|
+
retryOnNetworkError: true,
|
|
49020
|
+
}, `Alpaca SDK: ${label}`);
|
|
49021
|
+
}
|
|
48982
49022
|
/**
|
|
48983
49023
|
* Validate credentials by fetching account info
|
|
48984
49024
|
*/
|
|
@@ -49029,6 +49069,7 @@ class AlpacaClient {
|
|
|
49029
49069
|
* @returns Response data
|
|
49030
49070
|
*/
|
|
49031
49071
|
async makeRequest(endpoint, method = "GET", body) {
|
|
49072
|
+
await rateLimiters.alpaca.acquire();
|
|
49032
49073
|
const url = `${this.apiBaseUrl}${endpoint}`;
|
|
49033
49074
|
const options = {
|
|
49034
49075
|
method,
|
|
@@ -49037,14 +49078,26 @@ class AlpacaClient {
|
|
|
49037
49078
|
if (body && (method === "POST" || method === "PUT")) {
|
|
49038
49079
|
options.body = JSON.stringify(body);
|
|
49039
49080
|
}
|
|
49040
|
-
|
|
49081
|
+
return withRetry(async () => {
|
|
49041
49082
|
const response = await fetch(url, {
|
|
49042
49083
|
...options,
|
|
49043
49084
|
signal: createTimeoutSignal(DEFAULT_TIMEOUTS.ALPACA_API),
|
|
49044
49085
|
});
|
|
49045
49086
|
if (!response.ok) {
|
|
49046
49087
|
const errorText = await response.text();
|
|
49047
|
-
|
|
49088
|
+
const statusCode = response.status;
|
|
49089
|
+
// Classify error for retry logic
|
|
49090
|
+
if (statusCode === 429) {
|
|
49091
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
49092
|
+
throw new Error(`RATE_LIMIT: ${statusCode}${retryAfter ? `:${parseInt(retryAfter, 10) * 1000}` : ""}`);
|
|
49093
|
+
}
|
|
49094
|
+
if ([500, 502, 503, 504].includes(statusCode)) {
|
|
49095
|
+
throw new Error(`SERVER_ERROR: ${statusCode}`);
|
|
49096
|
+
}
|
|
49097
|
+
if ([401, 403].includes(statusCode)) {
|
|
49098
|
+
throw new Error(`AUTH_ERROR: ${statusCode}: ${errorText}`);
|
|
49099
|
+
}
|
|
49100
|
+
throw new Error(`CLIENT_ERROR: ${statusCode}: ${errorText}`);
|
|
49048
49101
|
}
|
|
49049
49102
|
// Handle empty responses (e.g., DELETE requests)
|
|
49050
49103
|
const contentType = response.headers.get("content-type");
|
|
@@ -49053,14 +49106,13 @@ class AlpacaClient {
|
|
|
49053
49106
|
return emptyObj;
|
|
49054
49107
|
}
|
|
49055
49108
|
return (await response.json());
|
|
49056
|
-
}
|
|
49057
|
-
|
|
49058
|
-
|
|
49059
|
-
|
|
49060
|
-
|
|
49061
|
-
|
|
49062
|
-
|
|
49063
|
-
}
|
|
49109
|
+
}, {
|
|
49110
|
+
maxRetries: 2,
|
|
49111
|
+
baseDelayMs: 1000,
|
|
49112
|
+
maxDelayMs: 10000,
|
|
49113
|
+
retryableStatusCodes: [429, 500, 502, 503, 504],
|
|
49114
|
+
retryOnNetworkError: true,
|
|
49115
|
+
}, `Alpaca ${method} ${endpoint}`);
|
|
49064
49116
|
}
|
|
49065
49117
|
}
|
|
49066
49118
|
// Client cache for connection pooling
|
|
@@ -49397,7 +49449,7 @@ async function getAccountDetails(client) {
|
|
|
49397
49449
|
log$i("Fetching account details");
|
|
49398
49450
|
try {
|
|
49399
49451
|
const sdk = client.getSDK();
|
|
49400
|
-
const account = await sdk.getAccount();
|
|
49452
|
+
const account = await client.executeWithRateLimit(() => sdk.getAccount(), "getAccount");
|
|
49401
49453
|
log$i(`Account details fetched successfully for account ${account.account_number}`);
|
|
49402
49454
|
return account;
|
|
49403
49455
|
}
|
|
@@ -49416,7 +49468,7 @@ async function getAccountConfiguration(client) {
|
|
|
49416
49468
|
log$i("Fetching account configuration");
|
|
49417
49469
|
try {
|
|
49418
49470
|
const sdk = client.getSDK();
|
|
49419
|
-
const config = await sdk.getAccountConfigurations();
|
|
49471
|
+
const config = await client.executeWithRateLimit(() => sdk.getAccountConfigurations(), "getAccountConfigurations");
|
|
49420
49472
|
log$i("Account configuration fetched successfully");
|
|
49421
49473
|
return config;
|
|
49422
49474
|
}
|
|
@@ -49438,7 +49490,7 @@ async function updateAccountConfiguration(client, config) {
|
|
|
49438
49490
|
log$i("Updating account configuration");
|
|
49439
49491
|
try {
|
|
49440
49492
|
const sdk = client.getSDK();
|
|
49441
|
-
const updatedConfig = await sdk.updateAccountConfigurations(config);
|
|
49493
|
+
const updatedConfig = await client.executeWithRateLimit(() => sdk.updateAccountConfigurations(config), "updateAccountConfigurations");
|
|
49442
49494
|
log$i("Account configuration updated successfully");
|
|
49443
49495
|
return updatedConfig;
|
|
49444
49496
|
}
|
|
@@ -49460,7 +49512,7 @@ async function getPortfolioHistory(client, params) {
|
|
|
49460
49512
|
log$i(`Fetching portfolio history with period: ${params.period || "default"}, timeframe: ${params.timeframe || "default"}`);
|
|
49461
49513
|
try {
|
|
49462
49514
|
const sdk = client.getSDK();
|
|
49463
|
-
const history = await sdk.getPortfolioHistory(params);
|
|
49515
|
+
const history = await client.executeWithRateLimit(() => sdk.getPortfolioHistory(params), "getPortfolioHistory");
|
|
49464
49516
|
log$i(`Portfolio history fetched successfully with ${history.equity?.length || 0} data points`);
|
|
49465
49517
|
return history;
|
|
49466
49518
|
}
|
|
@@ -52176,7 +52228,7 @@ async function getAlpacaClock(client) {
|
|
|
52176
52228
|
log$d("Fetching market clock");
|
|
52177
52229
|
try {
|
|
52178
52230
|
const sdk = client.getSDK();
|
|
52179
|
-
const clock = await sdk.getClock();
|
|
52231
|
+
const clock = await client.executeWithRateLimit(() => sdk.getClock(), "getClock");
|
|
52180
52232
|
log$d(`Market clock fetched: is_open=${clock.is_open}, next_open=${clock.next_open}`);
|
|
52181
52233
|
return clock;
|
|
52182
52234
|
}
|
|
@@ -52221,10 +52273,10 @@ async function getAlpacaCalendar(client, options) {
|
|
|
52221
52273
|
log$d(`Fetching market calendar${startStr ? ` from ${startStr}` : ""}${endStr ? ` to ${endStr}` : ""}`);
|
|
52222
52274
|
try {
|
|
52223
52275
|
const sdk = client.getSDK();
|
|
52224
|
-
const calendar = await sdk.getCalendar({
|
|
52276
|
+
const calendar = await client.executeWithRateLimit(() => sdk.getCalendar({
|
|
52225
52277
|
start: startStr,
|
|
52226
52278
|
end: endStr,
|
|
52227
|
-
});
|
|
52279
|
+
}), "getCalendar");
|
|
52228
52280
|
log$d(`Market calendar fetched: ${calendar.length} trading days`);
|
|
52229
52281
|
return calendar;
|
|
52230
52282
|
}
|
|
@@ -52283,9 +52335,9 @@ async function getLatestQuote(client, symbol, feed) {
|
|
|
52283
52335
|
const config = client.getConfig();
|
|
52284
52336
|
const dataFeed = feed || config.dataFeed || "iex";
|
|
52285
52337
|
// Use SDK's getLatestQuote method
|
|
52286
|
-
const response = await sdk.getLatestQuote(normalizedSymbol, {
|
|
52338
|
+
const response = await client.executeWithRateLimit(() => sdk.getLatestQuote(normalizedSymbol, {
|
|
52287
52339
|
feed: dataFeed,
|
|
52288
|
-
});
|
|
52340
|
+
}), "getLatestQuote");
|
|
52289
52341
|
if (!response) {
|
|
52290
52342
|
throw new QuoteError(`No quote data returned for ${normalizedSymbol}`, "NO_DATA", normalizedSymbol);
|
|
52291
52343
|
}
|
|
@@ -52340,9 +52392,9 @@ async function getLatestQuotes(client, symbols, feed) {
|
|
|
52340
52392
|
const config = client.getConfig();
|
|
52341
52393
|
const dataFeed = feed || config.dataFeed || "iex";
|
|
52342
52394
|
// Use SDK's getLatestQuotes method
|
|
52343
|
-
const response = await sdk.getLatestQuotes(normalizedSymbols, {
|
|
52395
|
+
const response = await client.executeWithRateLimit(() => sdk.getLatestQuotes(normalizedSymbols, {
|
|
52344
52396
|
feed: dataFeed,
|
|
52345
|
-
});
|
|
52397
|
+
}), "getLatestQuotes");
|
|
52346
52398
|
if (!response) {
|
|
52347
52399
|
throw new QuoteError("No quote data returned", "NO_DATA");
|
|
52348
52400
|
}
|
|
@@ -52545,7 +52597,8 @@ async function getBars(client, params) {
|
|
|
52545
52597
|
for (const symbol of normalizedSymbols) {
|
|
52546
52598
|
result.set(symbol, []);
|
|
52547
52599
|
}
|
|
52548
|
-
//
|
|
52600
|
+
// Acquire rate limit token before starting the async iterator
|
|
52601
|
+
await client.executeWithRateLimit(() => Promise.resolve(), "getBarsV2");
|
|
52549
52602
|
const barsIterator = sdk.getBarsV2(normalizedSymbols.join(","), options);
|
|
52550
52603
|
for await (const bar of barsIterator) {
|
|
52551
52604
|
const symbol = bar.Symbol;
|
|
@@ -52595,9 +52648,9 @@ async function getLatestBars(client, symbols) {
|
|
|
52595
52648
|
const sdk = client.getSDK();
|
|
52596
52649
|
const config = client.getConfig();
|
|
52597
52650
|
const dataFeed = config.dataFeed || "iex";
|
|
52598
|
-
const response = await sdk.getLatestBars(normalizedSymbols, {
|
|
52651
|
+
const response = await client.executeWithRateLimit(() => sdk.getLatestBars(normalizedSymbols, {
|
|
52599
52652
|
feed: dataFeed,
|
|
52600
|
-
});
|
|
52653
|
+
}), "getLatestBars");
|
|
52601
52654
|
const result = new Map();
|
|
52602
52655
|
for (const [symbol, bar] of Object.entries(response)) {
|
|
52603
52656
|
const b = bar;
|
|
@@ -52885,9 +52938,9 @@ async function getLatestTrade(client, symbol, feed) {
|
|
|
52885
52938
|
const config = client.getConfig();
|
|
52886
52939
|
const dataFeed = feed || config.dataFeed || "iex";
|
|
52887
52940
|
// Use SDK's getLatestTrade method
|
|
52888
|
-
const response = await sdk.getLatestTrade(normalizedSymbol, {
|
|
52941
|
+
const response = await client.executeWithRateLimit(() => sdk.getLatestTrade(normalizedSymbol, {
|
|
52889
52942
|
feed: dataFeed,
|
|
52890
|
-
});
|
|
52943
|
+
}), "getLatestTrade");
|
|
52891
52944
|
if (!response) {
|
|
52892
52945
|
throw new TradeError(`No trade data returned for ${normalizedSymbol}`, "NO_DATA", normalizedSymbol);
|
|
52893
52946
|
}
|
|
@@ -52940,9 +52993,9 @@ async function getLatestTrades(client, symbols, feed) {
|
|
|
52940
52993
|
const config = client.getConfig();
|
|
52941
52994
|
const dataFeed = feed || config.dataFeed || "iex";
|
|
52942
52995
|
// Use SDK's getLatestTrades method
|
|
52943
|
-
const response = await sdk.getLatestTrades(normalizedSymbols, {
|
|
52996
|
+
const response = await client.executeWithRateLimit(() => sdk.getLatestTrades(normalizedSymbols, {
|
|
52944
52997
|
feed: dataFeed,
|
|
52945
|
-
});
|
|
52998
|
+
}), "getLatestTrades");
|
|
52946
52999
|
if (!response) {
|
|
52947
53000
|
throw new TradeError("No trade data returned", "NO_DATA");
|
|
52948
53001
|
}
|
|
@@ -53004,7 +53057,8 @@ async function getHistoricalTrades(client, params) {
|
|
|
53004
53057
|
options.limit = limit;
|
|
53005
53058
|
}
|
|
53006
53059
|
const trades = [];
|
|
53007
|
-
//
|
|
53060
|
+
// Acquire rate limit token before starting the async iterator
|
|
53061
|
+
await client.executeWithRateLimit(() => Promise.resolve(), "getTradesV2");
|
|
53008
53062
|
const tradesIterator = sdk.getTradesV2(normalizedSymbol, options);
|
|
53009
53063
|
for await (const trade of tradesIterator) {
|
|
53010
53064
|
trades.push({
|
|
@@ -53479,7 +53533,7 @@ async function getNews(client, params = {}) {
|
|
|
53479
53533
|
options.include_content = true;
|
|
53480
53534
|
}
|
|
53481
53535
|
// Use SDK's getNews method
|
|
53482
|
-
const response = await sdk.getNews(options);
|
|
53536
|
+
const response = await client.executeWithRateLimit(() => sdk.getNews(options), "getNews");
|
|
53483
53537
|
if (!response || !Array.isArray(response)) {
|
|
53484
53538
|
log$9("No news data returned", { type: "debug" });
|
|
53485
53539
|
return [];
|
|
@@ -55290,7 +55344,7 @@ async function createOrder(client, params) {
|
|
|
55290
55344
|
});
|
|
55291
55345
|
try {
|
|
55292
55346
|
const sdk = client.getSDK();
|
|
55293
|
-
const order = await sdk.createOrder(params);
|
|
55347
|
+
const order = await client.executeWithRateLimit(() => sdk.createOrder(params), `createOrder ${symbol}`);
|
|
55294
55348
|
log$6(`Order created successfully: ${order.id}`, {
|
|
55295
55349
|
type: "info",
|
|
55296
55350
|
symbol,
|
|
@@ -55329,7 +55383,7 @@ async function getOrder(client, orderId) {
|
|
|
55329
55383
|
log$6(`Fetching order: ${orderId}`, { type: "debug" });
|
|
55330
55384
|
try {
|
|
55331
55385
|
const sdk = client.getSDK();
|
|
55332
|
-
const order = await sdk.getOrder(orderId);
|
|
55386
|
+
const order = await client.executeWithRateLimit(() => sdk.getOrder(orderId), `getOrder ${orderId}`);
|
|
55333
55387
|
log$6(`Order retrieved: ${orderId} (${order.status})`, {
|
|
55334
55388
|
type: "debug",
|
|
55335
55389
|
symbol: order.symbol,
|
|
@@ -55392,7 +55446,7 @@ async function getOrders(client, params = {}) {
|
|
|
55392
55446
|
}
|
|
55393
55447
|
if (params.side)
|
|
55394
55448
|
queryParams.side = params.side;
|
|
55395
|
-
const orders = await sdk.getOrders(queryParams);
|
|
55449
|
+
const orders = await client.executeWithRateLimit(() => sdk.getOrders(queryParams), "getOrders");
|
|
55396
55450
|
log$6(`Retrieved ${orders.length} orders`, {
|
|
55397
55451
|
type: "debug",
|
|
55398
55452
|
metadata: { count: orders.length, status: filterDescription },
|
|
@@ -55421,7 +55475,7 @@ async function cancelOrder(client, orderId) {
|
|
|
55421
55475
|
log$6(`Canceling order: ${orderId}`, { type: "info" });
|
|
55422
55476
|
try {
|
|
55423
55477
|
const sdk = client.getSDK();
|
|
55424
|
-
await sdk.cancelOrder(orderId);
|
|
55478
|
+
await client.executeWithRateLimit(() => sdk.cancelOrder(orderId), "cancelOrder");
|
|
55425
55479
|
log$6(`Order canceled successfully: ${orderId}`, { type: "info" });
|
|
55426
55480
|
}
|
|
55427
55481
|
catch (error) {
|
|
@@ -55463,7 +55517,7 @@ async function cancelAllOrders(client) {
|
|
|
55463
55517
|
log$6("Canceling all open orders", { type: "info" });
|
|
55464
55518
|
try {
|
|
55465
55519
|
const sdk = client.getSDK();
|
|
55466
|
-
const result = await sdk.cancelAllOrders();
|
|
55520
|
+
const result = await client.executeWithRateLimit(() => sdk.cancelAllOrders(), "cancelAllOrders");
|
|
55467
55521
|
// The SDK returns an array of canceled order statuses
|
|
55468
55522
|
const canceled = Array.isArray(result) ? result.length : 0;
|
|
55469
55523
|
const failed = [];
|
|
@@ -55523,7 +55577,7 @@ async function replaceOrder(client, orderId, params) {
|
|
|
55523
55577
|
});
|
|
55524
55578
|
try {
|
|
55525
55579
|
const sdk = client.getSDK();
|
|
55526
|
-
const newOrder = await sdk.replaceOrder(orderId, params);
|
|
55580
|
+
const newOrder = await client.executeWithRateLimit(() => sdk.replaceOrder(orderId, params), "replaceOrder");
|
|
55527
55581
|
log$6(`Order replaced successfully: ${orderId} -> ${newOrder.id}`, {
|
|
55528
55582
|
type: "info",
|
|
55529
55583
|
symbol: newOrder.symbol,
|
|
@@ -55628,7 +55682,7 @@ async function getOrderByClientId(client, clientOrderId) {
|
|
|
55628
55682
|
log$6(`Fetching order by client_order_id: ${clientOrderId}`, { type: "debug" });
|
|
55629
55683
|
try {
|
|
55630
55684
|
const sdk = client.getSDK();
|
|
55631
|
-
const order = await sdk.getOrderByClientId(clientOrderId);
|
|
55685
|
+
const order = await client.executeWithRateLimit(() => sdk.getOrderByClientId(clientOrderId), "getOrderByClientId");
|
|
55632
55686
|
log$6(`Order retrieved by client_order_id: ${clientOrderId} -> ${order.id}`, {
|
|
55633
55687
|
type: "debug",
|
|
55634
55688
|
symbol: order.symbol,
|
|
@@ -58569,7 +58623,7 @@ async function getPositions(client) {
|
|
|
58569
58623
|
log("Fetching all open positions", { type: "debug" });
|
|
58570
58624
|
try {
|
|
58571
58625
|
const sdk = client.getSDK();
|
|
58572
|
-
const positions = (await sdk.getPositions());
|
|
58626
|
+
const positions = (await client.executeWithRateLimit(() => sdk.getPositions(), "getPositions"));
|
|
58573
58627
|
log(`Retrieved ${positions.length} positions`, { type: "info" });
|
|
58574
58628
|
return positions;
|
|
58575
58629
|
}
|
|
@@ -58623,7 +58677,7 @@ async function getPosition(client, symbol) {
|
|
|
58623
58677
|
log(`Fetching position for symbol: ${symbol}`, { type: "debug", symbol });
|
|
58624
58678
|
try {
|
|
58625
58679
|
const sdk = client.getSDK();
|
|
58626
|
-
const position = (await sdk.getPosition(symbol));
|
|
58680
|
+
const position = (await client.executeWithRateLimit(() => sdk.getPosition(symbol), "getPosition"));
|
|
58627
58681
|
log(`Found position for ${symbol}: ${position.qty} shares`, {
|
|
58628
58682
|
type: "info",
|
|
58629
58683
|
symbol,
|
|
@@ -58770,10 +58824,10 @@ async function closePosition(client, symbol, options) {
|
|
|
58770
58824
|
let order;
|
|
58771
58825
|
if (Object.keys(queryParams).length > 0) {
|
|
58772
58826
|
// SDK doesn't support params, use sendRequest directly
|
|
58773
|
-
order = (await sdk.sendRequest(`/positions/${encodeURIComponent(normalizedSymbol)}`, queryParams, null, "DELETE"));
|
|
58827
|
+
order = (await client.executeWithRateLimit(() => sdk.sendRequest(`/positions/${encodeURIComponent(normalizedSymbol)}`, queryParams, null, "DELETE"), "closePosition"));
|
|
58774
58828
|
}
|
|
58775
58829
|
else {
|
|
58776
|
-
order = (await sdk.closePosition(normalizedSymbol));
|
|
58830
|
+
order = (await client.executeWithRateLimit(() => sdk.closePosition(normalizedSymbol), "closePosition"));
|
|
58777
58831
|
}
|
|
58778
58832
|
log(`Position close order created for ${normalizedSymbol}: ${order.id}`, {
|
|
58779
58833
|
type: "info",
|
|
@@ -58814,7 +58868,7 @@ async function closeAllPositions(client, options) {
|
|
|
58814
58868
|
cancel_orders: cancelOrders.toString(),
|
|
58815
58869
|
};
|
|
58816
58870
|
// Use sendRequest to pass the cancel_orders parameter
|
|
58817
|
-
const response = await sdk.sendRequest("/positions", queryParams, null, "DELETE");
|
|
58871
|
+
const response = await client.executeWithRateLimit(() => sdk.sendRequest("/positions", queryParams, null, "DELETE"), "closeAllPositions");
|
|
58818
58872
|
// The SDK returns an array of objects with order info
|
|
58819
58873
|
const orders = Array.isArray(response) ? response : [];
|
|
58820
58874
|
log(`Closed ${orders.length} positions`, { type: "info" });
|
|
@@ -58849,7 +58903,7 @@ async function closeAllPositionsAfterHours(client, options) {
|
|
|
58849
58903
|
return [];
|
|
58850
58904
|
}
|
|
58851
58905
|
// First cancel all open orders
|
|
58852
|
-
await sdk.cancelAllOrders();
|
|
58906
|
+
await client.executeWithRateLimit(() => sdk.cancelAllOrders(), "cancelAllOrders");
|
|
58853
58907
|
log("Cancelled all open orders", { type: "info" });
|
|
58854
58908
|
const orders = [];
|
|
58855
58909
|
const offsetMultiplier = limitPriceOffset / 100;
|
|
@@ -58870,7 +58924,7 @@ async function closeAllPositionsAfterHours(client, options) {
|
|
|
58870
58924
|
: roundPriceForAlpaca(currentPrice * (1 + offsetMultiplier));
|
|
58871
58925
|
log(`Creating limit order to close ${position.symbol}: ${side} ${qty} shares at $${limitPrice.toFixed(2)}`, { type: "info", symbol: position.symbol });
|
|
58872
58926
|
try {
|
|
58873
|
-
const order = (await sdk.createOrder({
|
|
58927
|
+
const order = (await client.executeWithRateLimit(() => sdk.createOrder({
|
|
58874
58928
|
symbol: position.symbol,
|
|
58875
58929
|
qty: qty,
|
|
58876
58930
|
side: side,
|
|
@@ -58878,7 +58932,7 @@ async function closeAllPositionsAfterHours(client, options) {
|
|
|
58878
58932
|
time_in_force: "day",
|
|
58879
58933
|
limit_price: limitPrice,
|
|
58880
58934
|
extended_hours: true,
|
|
58881
|
-
}));
|
|
58935
|
+
}), `createOrder ${position.symbol}`));
|
|
58882
58936
|
orders.push(order);
|
|
58883
58937
|
}
|
|
58884
58938
|
catch (orderError) {
|