@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.cjs
CHANGED
|
@@ -7847,24 +7847,27 @@ const rateLimiters = {
|
|
|
7847
7847
|
/**
|
|
7848
7848
|
* Alpaca API rate limiter
|
|
7849
7849
|
*
|
|
7850
|
-
* Configured for
|
|
7850
|
+
* Configured for 1000 requests per minute (paid tier).
|
|
7851
|
+
* The token bucket allows burst up to maxTokens, then refills at the steady rate.
|
|
7851
7852
|
* See: https://alpaca.markets/docs/api-references/trading-api/#rate-limit
|
|
7852
7853
|
*/
|
|
7853
7854
|
alpaca: new TokenBucketRateLimiter({
|
|
7854
|
-
maxTokens:
|
|
7855
|
-
refillRate:
|
|
7855
|
+
maxTokens: 1000,
|
|
7856
|
+
refillRate: 1000 / 60, // 1000 requests per 60 seconds (~16.67/sec)
|
|
7856
7857
|
label: "alpaca",
|
|
7857
7858
|
timeoutMs: 60000,
|
|
7858
7859
|
}),
|
|
7859
7860
|
/**
|
|
7860
7861
|
* Massive.com API rate limiter
|
|
7861
7862
|
*
|
|
7862
|
-
* Configured for
|
|
7863
|
-
*
|
|
7863
|
+
* Configured generously for paid unlimited tier. The bucket exists only as a
|
|
7864
|
+
* safety net against runaway loops — the 1000 token burst and 500/sec refill
|
|
7865
|
+
* should never be hit under normal operation. If the paid plan truly has no
|
|
7866
|
+
* hard limit, this just prevents accidental self-DDoS.
|
|
7864
7867
|
*/
|
|
7865
7868
|
massive: new TokenBucketRateLimiter({
|
|
7866
|
-
maxTokens:
|
|
7867
|
-
refillRate:
|
|
7869
|
+
maxTokens: 1000,
|
|
7870
|
+
refillRate: 500, // 500 tokens/sec refill — effectively unlimited for paid tier
|
|
7868
7871
|
label: "massive",
|
|
7869
7872
|
timeoutMs: 30000,
|
|
7870
7873
|
}),
|
|
@@ -8018,8 +8021,9 @@ const fetchTickerInfo = async (symbol, options) => {
|
|
|
8018
8021
|
apiKey,
|
|
8019
8022
|
});
|
|
8020
8023
|
return massiveLimit(async () => {
|
|
8024
|
+
await rateLimiters.massive.acquire();
|
|
8021
8025
|
try {
|
|
8022
|
-
const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, {}, 3, 1000);
|
|
8026
|
+
const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 1000);
|
|
8023
8027
|
const data = await response.json();
|
|
8024
8028
|
// Check for "NOT_FOUND" status and return null
|
|
8025
8029
|
if (data.status === "NOT_FOUND") {
|
|
@@ -8130,8 +8134,9 @@ const fetchLastTradeImpl = async (symbol, options) => {
|
|
|
8130
8134
|
order: "desc",
|
|
8131
8135
|
});
|
|
8132
8136
|
return massiveLimit(async () => {
|
|
8137
|
+
await rateLimiters.massive.acquire();
|
|
8133
8138
|
try {
|
|
8134
|
-
const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, {}, 3, 1000);
|
|
8139
|
+
const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 1000);
|
|
8135
8140
|
const data = (await response.json());
|
|
8136
8141
|
if ("message" in data) {
|
|
8137
8142
|
throw new Error(`Massive.com API error: ${data.message}`);
|
|
@@ -8200,8 +8205,9 @@ const fetchLastQuote = async (symbol, options) => {
|
|
|
8200
8205
|
order: "desc",
|
|
8201
8206
|
});
|
|
8202
8207
|
return massiveLimit(async () => {
|
|
8208
|
+
await rateLimiters.massive.acquire();
|
|
8203
8209
|
try {
|
|
8204
|
-
const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, {}, 3, 1000);
|
|
8210
|
+
const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 1000);
|
|
8205
8211
|
const data = (await response.json());
|
|
8206
8212
|
if ("message" in data) {
|
|
8207
8213
|
throw new Error(`Massive.com API error: ${data.message}`);
|
|
@@ -8284,7 +8290,7 @@ const fetchPrices = async (params, options) => {
|
|
|
8284
8290
|
while (nextUrl) {
|
|
8285
8291
|
//getLogger().info(`Debug: Fetching ${nextUrl}`);
|
|
8286
8292
|
await rateLimiters.massive.acquire();
|
|
8287
|
-
const response = await fetchWithRetry(nextUrl, {}, 3, 1000);
|
|
8293
|
+
const response = await fetchWithRetry(nextUrl, { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 1000);
|
|
8288
8294
|
const data = await response.json();
|
|
8289
8295
|
if (!MASSIVE_VALID_STATUSES.has(data.status)) {
|
|
8290
8296
|
throw new Error(`Massive.com API responded with status: ${data.status}`);
|
|
@@ -8405,8 +8411,9 @@ const fetchGroupedDaily = async (date, options) => {
|
|
|
8405
8411
|
include_otc: options?.includeOTC ? "true" : "false",
|
|
8406
8412
|
});
|
|
8407
8413
|
return massiveLimit(async () => {
|
|
8414
|
+
await rateLimiters.massive.acquire();
|
|
8408
8415
|
try {
|
|
8409
|
-
const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, {}, 3, 1000);
|
|
8416
|
+
const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 1000);
|
|
8410
8417
|
const data = await response.json();
|
|
8411
8418
|
if (!MASSIVE_VALID_STATUSES.has(data.status)) {
|
|
8412
8419
|
throw new Error(`Massive.com API responded with status: ${data.status}`);
|
|
@@ -8498,12 +8505,20 @@ symbol, date = new Date(), options) => {
|
|
|
8498
8505
|
adjusted: (options?.adjusted ?? true).toString(),
|
|
8499
8506
|
});
|
|
8500
8507
|
return massiveLimit(async () => {
|
|
8501
|
-
|
|
8502
|
-
|
|
8503
|
-
|
|
8504
|
-
|
|
8508
|
+
await rateLimiters.massive.acquire();
|
|
8509
|
+
try {
|
|
8510
|
+
const response = await fetchWithRetry(`${baseUrl}?${params.toString()}`, { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 1000);
|
|
8511
|
+
const data = await response.json();
|
|
8512
|
+
if (!MASSIVE_VALID_STATUSES.has(data.status)) {
|
|
8513
|
+
throw new Error(`Failed to fetch daily open/close data for ${symbol}: ${data.status}`);
|
|
8514
|
+
}
|
|
8515
|
+
return data;
|
|
8516
|
+
}
|
|
8517
|
+
catch (error) {
|
|
8518
|
+
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
8519
|
+
getLogger().error(`Error fetching daily open/close for ${symbol}: ${errorMessage}`);
|
|
8520
|
+
throw error;
|
|
8505
8521
|
}
|
|
8506
|
-
return data;
|
|
8507
8522
|
});
|
|
8508
8523
|
};
|
|
8509
8524
|
/**
|
|
@@ -8564,10 +8579,11 @@ const fetchTrades = async (symbol, options) => {
|
|
|
8564
8579
|
if (options?.sort)
|
|
8565
8580
|
params.append("sort", options.sort);
|
|
8566
8581
|
return massiveLimit(async () => {
|
|
8582
|
+
await rateLimiters.massive.acquire();
|
|
8567
8583
|
const url = `${baseUrl}?${params.toString()}`;
|
|
8568
8584
|
try {
|
|
8569
8585
|
logIfDebug(`Fetching trades for ${symbol} from ${url}`);
|
|
8570
|
-
const response = await fetchWithRetry(url, {}, 3, 1000);
|
|
8586
|
+
const response = await fetchWithRetry(url, { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 1000);
|
|
8571
8587
|
const data = (await response.json());
|
|
8572
8588
|
if ("message" in data) {
|
|
8573
8589
|
// This is an error response
|
|
@@ -8643,8 +8659,9 @@ const fetchIndicesAggregates = async (params, options) => {
|
|
|
8643
8659
|
}
|
|
8644
8660
|
url.search = queryParams.toString();
|
|
8645
8661
|
return massiveIndicesLimit(async () => {
|
|
8662
|
+
await rateLimiters.massive.acquire();
|
|
8646
8663
|
try {
|
|
8647
|
-
const response = await fetchWithRetry(url.toString(), {}, 3, 300);
|
|
8664
|
+
const response = await fetchWithRetry(url.toString(), { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 300);
|
|
8648
8665
|
const data = await response.json();
|
|
8649
8666
|
if (data.status === "ERROR") {
|
|
8650
8667
|
throw new Error(`Massive API Error: ${data.error}`);
|
|
@@ -8672,8 +8689,9 @@ const fetchIndicesPreviousClose = async (indicesTicker, options) => {
|
|
|
8672
8689
|
queryParams.append("apiKey", apiKey);
|
|
8673
8690
|
url.search = queryParams.toString();
|
|
8674
8691
|
return massiveIndicesLimit(async () => {
|
|
8692
|
+
await rateLimiters.massive.acquire();
|
|
8675
8693
|
try {
|
|
8676
|
-
const response = await fetchWithRetry(url.toString(), {}, 3, 300);
|
|
8694
|
+
const response = await fetchWithRetry(url.toString(), { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 300);
|
|
8677
8695
|
const data = await response.json();
|
|
8678
8696
|
if (data.status === "ERROR") {
|
|
8679
8697
|
throw new Error(`Massive API Error: ${data.error}`);
|
|
@@ -8702,8 +8720,9 @@ const fetchIndicesDailyOpenClose = async (indicesTicker, date, options) => {
|
|
|
8702
8720
|
queryParams.append("apiKey", apiKey);
|
|
8703
8721
|
url.search = queryParams.toString();
|
|
8704
8722
|
return massiveIndicesLimit(async () => {
|
|
8723
|
+
await rateLimiters.massive.acquire();
|
|
8705
8724
|
try {
|
|
8706
|
-
const response = await fetchWithRetry(url.toString(), {}, 3, 300);
|
|
8725
|
+
const response = await fetchWithRetry(url.toString(), { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 300);
|
|
8707
8726
|
const data = await response.json();
|
|
8708
8727
|
if (data.status === "ERROR") {
|
|
8709
8728
|
throw new Error(`Massive API Error: ${data.error}`);
|
|
@@ -8743,8 +8762,9 @@ const fetchIndicesSnapshot = async (params, options) => {
|
|
|
8743
8762
|
}
|
|
8744
8763
|
url.search = queryParams.toString();
|
|
8745
8764
|
return massiveIndicesLimit(async () => {
|
|
8765
|
+
await rateLimiters.massive.acquire();
|
|
8746
8766
|
try {
|
|
8747
|
-
const response = await fetchWithRetry(url.toString(), {}, 3, 300);
|
|
8767
|
+
const response = await fetchWithRetry(url.toString(), { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 300);
|
|
8748
8768
|
const data = await response.json();
|
|
8749
8769
|
if (data.status === "ERROR") {
|
|
8750
8770
|
throw new Error(`Massive API Error: ${data.error}`);
|
|
@@ -8791,8 +8811,9 @@ const fetchUniversalSnapshot = async (tickers, options) => {
|
|
|
8791
8811
|
}
|
|
8792
8812
|
url.search = queryParams.toString();
|
|
8793
8813
|
return massiveIndicesLimit(async () => {
|
|
8814
|
+
await rateLimiters.massive.acquire();
|
|
8794
8815
|
try {
|
|
8795
|
-
const response = await fetchWithRetry(url.toString(), {}, 3, 300);
|
|
8816
|
+
const response = await fetchWithRetry(url.toString(), { signal: createTimeoutSignal(DEFAULT_TIMEOUTS.MASSIVE_API) }, 3, 300);
|
|
8796
8817
|
const data = await response.json();
|
|
8797
8818
|
if (data.status === "ERROR") {
|
|
8798
8819
|
throw new Error(`Massive API Error: ${data.error}`);
|
|
@@ -48981,6 +49002,25 @@ class AlpacaClient {
|
|
|
48981
49002
|
isPaper() {
|
|
48982
49003
|
return this.config.accountType === "PAPER";
|
|
48983
49004
|
}
|
|
49005
|
+
/**
|
|
49006
|
+
* Execute an Alpaca SDK operation with rate limiting and retry.
|
|
49007
|
+
* Use this for all SDK calls to prevent rate limit breaches and handle
|
|
49008
|
+
* transient failures during market hours.
|
|
49009
|
+
*
|
|
49010
|
+
* @param operation - Async function that calls the SDK
|
|
49011
|
+
* @param label - Human-readable label for logging
|
|
49012
|
+
* @returns Result of the operation
|
|
49013
|
+
*/
|
|
49014
|
+
async executeWithRateLimit(operation, label) {
|
|
49015
|
+
await rateLimiters.alpaca.acquire();
|
|
49016
|
+
return withRetry(operation, {
|
|
49017
|
+
maxRetries: 2,
|
|
49018
|
+
baseDelayMs: 1000,
|
|
49019
|
+
maxDelayMs: 10000,
|
|
49020
|
+
retryableStatusCodes: [429, 500, 502, 503, 504],
|
|
49021
|
+
retryOnNetworkError: true,
|
|
49022
|
+
}, `Alpaca SDK: ${label}`);
|
|
49023
|
+
}
|
|
48984
49024
|
/**
|
|
48985
49025
|
* Validate credentials by fetching account info
|
|
48986
49026
|
*/
|
|
@@ -49031,6 +49071,7 @@ class AlpacaClient {
|
|
|
49031
49071
|
* @returns Response data
|
|
49032
49072
|
*/
|
|
49033
49073
|
async makeRequest(endpoint, method = "GET", body) {
|
|
49074
|
+
await rateLimiters.alpaca.acquire();
|
|
49034
49075
|
const url = `${this.apiBaseUrl}${endpoint}`;
|
|
49035
49076
|
const options = {
|
|
49036
49077
|
method,
|
|
@@ -49039,14 +49080,26 @@ class AlpacaClient {
|
|
|
49039
49080
|
if (body && (method === "POST" || method === "PUT")) {
|
|
49040
49081
|
options.body = JSON.stringify(body);
|
|
49041
49082
|
}
|
|
49042
|
-
|
|
49083
|
+
return withRetry(async () => {
|
|
49043
49084
|
const response = await fetch(url, {
|
|
49044
49085
|
...options,
|
|
49045
49086
|
signal: createTimeoutSignal(DEFAULT_TIMEOUTS.ALPACA_API),
|
|
49046
49087
|
});
|
|
49047
49088
|
if (!response.ok) {
|
|
49048
49089
|
const errorText = await response.text();
|
|
49049
|
-
|
|
49090
|
+
const statusCode = response.status;
|
|
49091
|
+
// Classify error for retry logic
|
|
49092
|
+
if (statusCode === 429) {
|
|
49093
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
49094
|
+
throw new Error(`RATE_LIMIT: ${statusCode}${retryAfter ? `:${parseInt(retryAfter, 10) * 1000}` : ""}`);
|
|
49095
|
+
}
|
|
49096
|
+
if ([500, 502, 503, 504].includes(statusCode)) {
|
|
49097
|
+
throw new Error(`SERVER_ERROR: ${statusCode}`);
|
|
49098
|
+
}
|
|
49099
|
+
if ([401, 403].includes(statusCode)) {
|
|
49100
|
+
throw new Error(`AUTH_ERROR: ${statusCode}: ${errorText}`);
|
|
49101
|
+
}
|
|
49102
|
+
throw new Error(`CLIENT_ERROR: ${statusCode}: ${errorText}`);
|
|
49050
49103
|
}
|
|
49051
49104
|
// Handle empty responses (e.g., DELETE requests)
|
|
49052
49105
|
const contentType = response.headers.get("content-type");
|
|
@@ -49055,14 +49108,13 @@ class AlpacaClient {
|
|
|
49055
49108
|
return emptyObj;
|
|
49056
49109
|
}
|
|
49057
49110
|
return (await response.json());
|
|
49058
|
-
}
|
|
49059
|
-
|
|
49060
|
-
|
|
49061
|
-
|
|
49062
|
-
|
|
49063
|
-
|
|
49064
|
-
|
|
49065
|
-
}
|
|
49111
|
+
}, {
|
|
49112
|
+
maxRetries: 2,
|
|
49113
|
+
baseDelayMs: 1000,
|
|
49114
|
+
maxDelayMs: 10000,
|
|
49115
|
+
retryableStatusCodes: [429, 500, 502, 503, 504],
|
|
49116
|
+
retryOnNetworkError: true,
|
|
49117
|
+
}, `Alpaca ${method} ${endpoint}`);
|
|
49066
49118
|
}
|
|
49067
49119
|
}
|
|
49068
49120
|
// Client cache for connection pooling
|
|
@@ -49399,7 +49451,7 @@ async function getAccountDetails(client) {
|
|
|
49399
49451
|
log$i("Fetching account details");
|
|
49400
49452
|
try {
|
|
49401
49453
|
const sdk = client.getSDK();
|
|
49402
|
-
const account = await sdk.getAccount();
|
|
49454
|
+
const account = await client.executeWithRateLimit(() => sdk.getAccount(), "getAccount");
|
|
49403
49455
|
log$i(`Account details fetched successfully for account ${account.account_number}`);
|
|
49404
49456
|
return account;
|
|
49405
49457
|
}
|
|
@@ -49418,7 +49470,7 @@ async function getAccountConfiguration(client) {
|
|
|
49418
49470
|
log$i("Fetching account configuration");
|
|
49419
49471
|
try {
|
|
49420
49472
|
const sdk = client.getSDK();
|
|
49421
|
-
const config = await sdk.getAccountConfigurations();
|
|
49473
|
+
const config = await client.executeWithRateLimit(() => sdk.getAccountConfigurations(), "getAccountConfigurations");
|
|
49422
49474
|
log$i("Account configuration fetched successfully");
|
|
49423
49475
|
return config;
|
|
49424
49476
|
}
|
|
@@ -49440,7 +49492,7 @@ async function updateAccountConfiguration(client, config) {
|
|
|
49440
49492
|
log$i("Updating account configuration");
|
|
49441
49493
|
try {
|
|
49442
49494
|
const sdk = client.getSDK();
|
|
49443
|
-
const updatedConfig = await sdk.updateAccountConfigurations(config);
|
|
49495
|
+
const updatedConfig = await client.executeWithRateLimit(() => sdk.updateAccountConfigurations(config), "updateAccountConfigurations");
|
|
49444
49496
|
log$i("Account configuration updated successfully");
|
|
49445
49497
|
return updatedConfig;
|
|
49446
49498
|
}
|
|
@@ -49462,7 +49514,7 @@ async function getPortfolioHistory(client, params) {
|
|
|
49462
49514
|
log$i(`Fetching portfolio history with period: ${params.period || "default"}, timeframe: ${params.timeframe || "default"}`);
|
|
49463
49515
|
try {
|
|
49464
49516
|
const sdk = client.getSDK();
|
|
49465
|
-
const history = await sdk.getPortfolioHistory(params);
|
|
49517
|
+
const history = await client.executeWithRateLimit(() => sdk.getPortfolioHistory(params), "getPortfolioHistory");
|
|
49466
49518
|
log$i(`Portfolio history fetched successfully with ${history.equity?.length || 0} data points`);
|
|
49467
49519
|
return history;
|
|
49468
49520
|
}
|
|
@@ -52178,7 +52230,7 @@ async function getAlpacaClock(client) {
|
|
|
52178
52230
|
log$d("Fetching market clock");
|
|
52179
52231
|
try {
|
|
52180
52232
|
const sdk = client.getSDK();
|
|
52181
|
-
const clock = await sdk.getClock();
|
|
52233
|
+
const clock = await client.executeWithRateLimit(() => sdk.getClock(), "getClock");
|
|
52182
52234
|
log$d(`Market clock fetched: is_open=${clock.is_open}, next_open=${clock.next_open}`);
|
|
52183
52235
|
return clock;
|
|
52184
52236
|
}
|
|
@@ -52223,10 +52275,10 @@ async function getAlpacaCalendar(client, options) {
|
|
|
52223
52275
|
log$d(`Fetching market calendar${startStr ? ` from ${startStr}` : ""}${endStr ? ` to ${endStr}` : ""}`);
|
|
52224
52276
|
try {
|
|
52225
52277
|
const sdk = client.getSDK();
|
|
52226
|
-
const calendar = await sdk.getCalendar({
|
|
52278
|
+
const calendar = await client.executeWithRateLimit(() => sdk.getCalendar({
|
|
52227
52279
|
start: startStr,
|
|
52228
52280
|
end: endStr,
|
|
52229
|
-
});
|
|
52281
|
+
}), "getCalendar");
|
|
52230
52282
|
log$d(`Market calendar fetched: ${calendar.length} trading days`);
|
|
52231
52283
|
return calendar;
|
|
52232
52284
|
}
|
|
@@ -52285,9 +52337,9 @@ async function getLatestQuote(client, symbol, feed) {
|
|
|
52285
52337
|
const config = client.getConfig();
|
|
52286
52338
|
const dataFeed = feed || config.dataFeed || "iex";
|
|
52287
52339
|
// Use SDK's getLatestQuote method
|
|
52288
|
-
const response = await sdk.getLatestQuote(normalizedSymbol, {
|
|
52340
|
+
const response = await client.executeWithRateLimit(() => sdk.getLatestQuote(normalizedSymbol, {
|
|
52289
52341
|
feed: dataFeed,
|
|
52290
|
-
});
|
|
52342
|
+
}), "getLatestQuote");
|
|
52291
52343
|
if (!response) {
|
|
52292
52344
|
throw new QuoteError(`No quote data returned for ${normalizedSymbol}`, "NO_DATA", normalizedSymbol);
|
|
52293
52345
|
}
|
|
@@ -52342,9 +52394,9 @@ async function getLatestQuotes(client, symbols, feed) {
|
|
|
52342
52394
|
const config = client.getConfig();
|
|
52343
52395
|
const dataFeed = feed || config.dataFeed || "iex";
|
|
52344
52396
|
// Use SDK's getLatestQuotes method
|
|
52345
|
-
const response = await sdk.getLatestQuotes(normalizedSymbols, {
|
|
52397
|
+
const response = await client.executeWithRateLimit(() => sdk.getLatestQuotes(normalizedSymbols, {
|
|
52346
52398
|
feed: dataFeed,
|
|
52347
|
-
});
|
|
52399
|
+
}), "getLatestQuotes");
|
|
52348
52400
|
if (!response) {
|
|
52349
52401
|
throw new QuoteError("No quote data returned", "NO_DATA");
|
|
52350
52402
|
}
|
|
@@ -52547,7 +52599,8 @@ async function getBars(client, params) {
|
|
|
52547
52599
|
for (const symbol of normalizedSymbols) {
|
|
52548
52600
|
result.set(symbol, []);
|
|
52549
52601
|
}
|
|
52550
|
-
//
|
|
52602
|
+
// Acquire rate limit token before starting the async iterator
|
|
52603
|
+
await client.executeWithRateLimit(() => Promise.resolve(), "getBarsV2");
|
|
52551
52604
|
const barsIterator = sdk.getBarsV2(normalizedSymbols.join(","), options);
|
|
52552
52605
|
for await (const bar of barsIterator) {
|
|
52553
52606
|
const symbol = bar.Symbol;
|
|
@@ -52597,9 +52650,9 @@ async function getLatestBars(client, symbols) {
|
|
|
52597
52650
|
const sdk = client.getSDK();
|
|
52598
52651
|
const config = client.getConfig();
|
|
52599
52652
|
const dataFeed = config.dataFeed || "iex";
|
|
52600
|
-
const response = await sdk.getLatestBars(normalizedSymbols, {
|
|
52653
|
+
const response = await client.executeWithRateLimit(() => sdk.getLatestBars(normalizedSymbols, {
|
|
52601
52654
|
feed: dataFeed,
|
|
52602
|
-
});
|
|
52655
|
+
}), "getLatestBars");
|
|
52603
52656
|
const result = new Map();
|
|
52604
52657
|
for (const [symbol, bar] of Object.entries(response)) {
|
|
52605
52658
|
const b = bar;
|
|
@@ -52887,9 +52940,9 @@ async function getLatestTrade(client, symbol, feed) {
|
|
|
52887
52940
|
const config = client.getConfig();
|
|
52888
52941
|
const dataFeed = feed || config.dataFeed || "iex";
|
|
52889
52942
|
// Use SDK's getLatestTrade method
|
|
52890
|
-
const response = await sdk.getLatestTrade(normalizedSymbol, {
|
|
52943
|
+
const response = await client.executeWithRateLimit(() => sdk.getLatestTrade(normalizedSymbol, {
|
|
52891
52944
|
feed: dataFeed,
|
|
52892
|
-
});
|
|
52945
|
+
}), "getLatestTrade");
|
|
52893
52946
|
if (!response) {
|
|
52894
52947
|
throw new TradeError(`No trade data returned for ${normalizedSymbol}`, "NO_DATA", normalizedSymbol);
|
|
52895
52948
|
}
|
|
@@ -52942,9 +52995,9 @@ async function getLatestTrades(client, symbols, feed) {
|
|
|
52942
52995
|
const config = client.getConfig();
|
|
52943
52996
|
const dataFeed = feed || config.dataFeed || "iex";
|
|
52944
52997
|
// Use SDK's getLatestTrades method
|
|
52945
|
-
const response = await sdk.getLatestTrades(normalizedSymbols, {
|
|
52998
|
+
const response = await client.executeWithRateLimit(() => sdk.getLatestTrades(normalizedSymbols, {
|
|
52946
52999
|
feed: dataFeed,
|
|
52947
|
-
});
|
|
53000
|
+
}), "getLatestTrades");
|
|
52948
53001
|
if (!response) {
|
|
52949
53002
|
throw new TradeError("No trade data returned", "NO_DATA");
|
|
52950
53003
|
}
|
|
@@ -53006,7 +53059,8 @@ async function getHistoricalTrades(client, params) {
|
|
|
53006
53059
|
options.limit = limit;
|
|
53007
53060
|
}
|
|
53008
53061
|
const trades = [];
|
|
53009
|
-
//
|
|
53062
|
+
// Acquire rate limit token before starting the async iterator
|
|
53063
|
+
await client.executeWithRateLimit(() => Promise.resolve(), "getTradesV2");
|
|
53010
53064
|
const tradesIterator = sdk.getTradesV2(normalizedSymbol, options);
|
|
53011
53065
|
for await (const trade of tradesIterator) {
|
|
53012
53066
|
trades.push({
|
|
@@ -53481,7 +53535,7 @@ async function getNews(client, params = {}) {
|
|
|
53481
53535
|
options.include_content = true;
|
|
53482
53536
|
}
|
|
53483
53537
|
// Use SDK's getNews method
|
|
53484
|
-
const response = await sdk.getNews(options);
|
|
53538
|
+
const response = await client.executeWithRateLimit(() => sdk.getNews(options), "getNews");
|
|
53485
53539
|
if (!response || !Array.isArray(response)) {
|
|
53486
53540
|
log$9("No news data returned", { type: "debug" });
|
|
53487
53541
|
return [];
|
|
@@ -55292,7 +55346,7 @@ async function createOrder(client, params) {
|
|
|
55292
55346
|
});
|
|
55293
55347
|
try {
|
|
55294
55348
|
const sdk = client.getSDK();
|
|
55295
|
-
const order = await sdk.createOrder(params);
|
|
55349
|
+
const order = await client.executeWithRateLimit(() => sdk.createOrder(params), `createOrder ${symbol}`);
|
|
55296
55350
|
log$6(`Order created successfully: ${order.id}`, {
|
|
55297
55351
|
type: "info",
|
|
55298
55352
|
symbol,
|
|
@@ -55331,7 +55385,7 @@ async function getOrder(client, orderId) {
|
|
|
55331
55385
|
log$6(`Fetching order: ${orderId}`, { type: "debug" });
|
|
55332
55386
|
try {
|
|
55333
55387
|
const sdk = client.getSDK();
|
|
55334
|
-
const order = await sdk.getOrder(orderId);
|
|
55388
|
+
const order = await client.executeWithRateLimit(() => sdk.getOrder(orderId), `getOrder ${orderId}`);
|
|
55335
55389
|
log$6(`Order retrieved: ${orderId} (${order.status})`, {
|
|
55336
55390
|
type: "debug",
|
|
55337
55391
|
symbol: order.symbol,
|
|
@@ -55394,7 +55448,7 @@ async function getOrders(client, params = {}) {
|
|
|
55394
55448
|
}
|
|
55395
55449
|
if (params.side)
|
|
55396
55450
|
queryParams.side = params.side;
|
|
55397
|
-
const orders = await sdk.getOrders(queryParams);
|
|
55451
|
+
const orders = await client.executeWithRateLimit(() => sdk.getOrders(queryParams), "getOrders");
|
|
55398
55452
|
log$6(`Retrieved ${orders.length} orders`, {
|
|
55399
55453
|
type: "debug",
|
|
55400
55454
|
metadata: { count: orders.length, status: filterDescription },
|
|
@@ -55423,7 +55477,7 @@ async function cancelOrder(client, orderId) {
|
|
|
55423
55477
|
log$6(`Canceling order: ${orderId}`, { type: "info" });
|
|
55424
55478
|
try {
|
|
55425
55479
|
const sdk = client.getSDK();
|
|
55426
|
-
await sdk.cancelOrder(orderId);
|
|
55480
|
+
await client.executeWithRateLimit(() => sdk.cancelOrder(orderId), "cancelOrder");
|
|
55427
55481
|
log$6(`Order canceled successfully: ${orderId}`, { type: "info" });
|
|
55428
55482
|
}
|
|
55429
55483
|
catch (error) {
|
|
@@ -55465,7 +55519,7 @@ async function cancelAllOrders(client) {
|
|
|
55465
55519
|
log$6("Canceling all open orders", { type: "info" });
|
|
55466
55520
|
try {
|
|
55467
55521
|
const sdk = client.getSDK();
|
|
55468
|
-
const result = await sdk.cancelAllOrders();
|
|
55522
|
+
const result = await client.executeWithRateLimit(() => sdk.cancelAllOrders(), "cancelAllOrders");
|
|
55469
55523
|
// The SDK returns an array of canceled order statuses
|
|
55470
55524
|
const canceled = Array.isArray(result) ? result.length : 0;
|
|
55471
55525
|
const failed = [];
|
|
@@ -55525,7 +55579,7 @@ async function replaceOrder(client, orderId, params) {
|
|
|
55525
55579
|
});
|
|
55526
55580
|
try {
|
|
55527
55581
|
const sdk = client.getSDK();
|
|
55528
|
-
const newOrder = await sdk.replaceOrder(orderId, params);
|
|
55582
|
+
const newOrder = await client.executeWithRateLimit(() => sdk.replaceOrder(orderId, params), "replaceOrder");
|
|
55529
55583
|
log$6(`Order replaced successfully: ${orderId} -> ${newOrder.id}`, {
|
|
55530
55584
|
type: "info",
|
|
55531
55585
|
symbol: newOrder.symbol,
|
|
@@ -55630,7 +55684,7 @@ async function getOrderByClientId(client, clientOrderId) {
|
|
|
55630
55684
|
log$6(`Fetching order by client_order_id: ${clientOrderId}`, { type: "debug" });
|
|
55631
55685
|
try {
|
|
55632
55686
|
const sdk = client.getSDK();
|
|
55633
|
-
const order = await sdk.getOrderByClientId(clientOrderId);
|
|
55687
|
+
const order = await client.executeWithRateLimit(() => sdk.getOrderByClientId(clientOrderId), "getOrderByClientId");
|
|
55634
55688
|
log$6(`Order retrieved by client_order_id: ${clientOrderId} -> ${order.id}`, {
|
|
55635
55689
|
type: "debug",
|
|
55636
55690
|
symbol: order.symbol,
|
|
@@ -58571,7 +58625,7 @@ async function getPositions(client) {
|
|
|
58571
58625
|
log("Fetching all open positions", { type: "debug" });
|
|
58572
58626
|
try {
|
|
58573
58627
|
const sdk = client.getSDK();
|
|
58574
|
-
const positions = (await sdk.getPositions());
|
|
58628
|
+
const positions = (await client.executeWithRateLimit(() => sdk.getPositions(), "getPositions"));
|
|
58575
58629
|
log(`Retrieved ${positions.length} positions`, { type: "info" });
|
|
58576
58630
|
return positions;
|
|
58577
58631
|
}
|
|
@@ -58625,7 +58679,7 @@ async function getPosition(client, symbol) {
|
|
|
58625
58679
|
log(`Fetching position for symbol: ${symbol}`, { type: "debug", symbol });
|
|
58626
58680
|
try {
|
|
58627
58681
|
const sdk = client.getSDK();
|
|
58628
|
-
const position = (await sdk.getPosition(symbol));
|
|
58682
|
+
const position = (await client.executeWithRateLimit(() => sdk.getPosition(symbol), "getPosition"));
|
|
58629
58683
|
log(`Found position for ${symbol}: ${position.qty} shares`, {
|
|
58630
58684
|
type: "info",
|
|
58631
58685
|
symbol,
|
|
@@ -58772,10 +58826,10 @@ async function closePosition(client, symbol, options) {
|
|
|
58772
58826
|
let order;
|
|
58773
58827
|
if (Object.keys(queryParams).length > 0) {
|
|
58774
58828
|
// SDK doesn't support params, use sendRequest directly
|
|
58775
|
-
order = (await sdk.sendRequest(`/positions/${encodeURIComponent(normalizedSymbol)}`, queryParams, null, "DELETE"));
|
|
58829
|
+
order = (await client.executeWithRateLimit(() => sdk.sendRequest(`/positions/${encodeURIComponent(normalizedSymbol)}`, queryParams, null, "DELETE"), "closePosition"));
|
|
58776
58830
|
}
|
|
58777
58831
|
else {
|
|
58778
|
-
order = (await sdk.closePosition(normalizedSymbol));
|
|
58832
|
+
order = (await client.executeWithRateLimit(() => sdk.closePosition(normalizedSymbol), "closePosition"));
|
|
58779
58833
|
}
|
|
58780
58834
|
log(`Position close order created for ${normalizedSymbol}: ${order.id}`, {
|
|
58781
58835
|
type: "info",
|
|
@@ -58816,7 +58870,7 @@ async function closeAllPositions(client, options) {
|
|
|
58816
58870
|
cancel_orders: cancelOrders.toString(),
|
|
58817
58871
|
};
|
|
58818
58872
|
// Use sendRequest to pass the cancel_orders parameter
|
|
58819
|
-
const response = await sdk.sendRequest("/positions", queryParams, null, "DELETE");
|
|
58873
|
+
const response = await client.executeWithRateLimit(() => sdk.sendRequest("/positions", queryParams, null, "DELETE"), "closeAllPositions");
|
|
58820
58874
|
// The SDK returns an array of objects with order info
|
|
58821
58875
|
const orders = Array.isArray(response) ? response : [];
|
|
58822
58876
|
log(`Closed ${orders.length} positions`, { type: "info" });
|
|
@@ -58851,7 +58905,7 @@ async function closeAllPositionsAfterHours(client, options) {
|
|
|
58851
58905
|
return [];
|
|
58852
58906
|
}
|
|
58853
58907
|
// First cancel all open orders
|
|
58854
|
-
await sdk.cancelAllOrders();
|
|
58908
|
+
await client.executeWithRateLimit(() => sdk.cancelAllOrders(), "cancelAllOrders");
|
|
58855
58909
|
log("Cancelled all open orders", { type: "info" });
|
|
58856
58910
|
const orders = [];
|
|
58857
58911
|
const offsetMultiplier = limitPriceOffset / 100;
|
|
@@ -58872,7 +58926,7 @@ async function closeAllPositionsAfterHours(client, options) {
|
|
|
58872
58926
|
: roundPriceForAlpaca(currentPrice * (1 + offsetMultiplier));
|
|
58873
58927
|
log(`Creating limit order to close ${position.symbol}: ${side} ${qty} shares at $${limitPrice.toFixed(2)}`, { type: "info", symbol: position.symbol });
|
|
58874
58928
|
try {
|
|
58875
|
-
const order = (await sdk.createOrder({
|
|
58929
|
+
const order = (await client.executeWithRateLimit(() => sdk.createOrder({
|
|
58876
58930
|
symbol: position.symbol,
|
|
58877
58931
|
qty: qty,
|
|
58878
58932
|
side: side,
|
|
@@ -58880,7 +58934,7 @@ async function closeAllPositionsAfterHours(client, options) {
|
|
|
58880
58934
|
time_in_force: "day",
|
|
58881
58935
|
limit_price: limitPrice,
|
|
58882
58936
|
extended_hours: true,
|
|
58883
|
-
}));
|
|
58937
|
+
}), `createOrder ${position.symbol}`));
|
|
58884
58938
|
orders.push(order);
|
|
58885
58939
|
}
|
|
58886
58940
|
catch (orderError) {
|