@adaptic/utils 0.0.994 → 0.0.996
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 +44 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +44 -6
- package/dist/index.mjs.map +1 -1
- package/dist/types/alpaca/legacy/positions.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/massive-indices.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -6947,8 +6947,38 @@ async function closePosition$1(auth, symbolOrAssetId, params) {
|
|
|
6947
6947
|
account: auth.adapticAccountId || "direct",
|
|
6948
6948
|
symbol: normalizedSymbol,
|
|
6949
6949
|
});
|
|
6950
|
-
|
|
6951
|
-
|
|
6950
|
+
try {
|
|
6951
|
+
await cancelOrder$1(auth, order.id);
|
|
6952
|
+
cancelledCount++;
|
|
6953
|
+
}
|
|
6954
|
+
catch (cancelError) {
|
|
6955
|
+
// Alpaca rejects DELETE on an order that is already in
|
|
6956
|
+
// pending_cancel / pending_replace with HTTP 422 code
|
|
6957
|
+
// 42210000 ("order pending cancel"). The order is already
|
|
6958
|
+
// dying — which is exactly what this sweep wants — so
|
|
6959
|
+
// aborting the entire position close here is wrong: it
|
|
6960
|
+
// left REDUCE/EXIT risk actions permanently blocked when a
|
|
6961
|
+
// protective stop wedged in pending_cancel at the broker
|
|
6962
|
+
// (observed live 2026-06-10: an 8-day-old pending_cancel
|
|
6963
|
+
// trailing stop on a naked short made every exit attempt
|
|
6964
|
+
// throw). Treat already-cancelling as success-in-progress
|
|
6965
|
+
// and let the subsequent close attempt get the broker's
|
|
6966
|
+
// authoritative answer on held quantity. Any other cancel
|
|
6967
|
+
// failure still aborts the close as before.
|
|
6968
|
+
const message = cancelError instanceof Error
|
|
6969
|
+
? cancelError.message
|
|
6970
|
+
: String(cancelError);
|
|
6971
|
+
const alreadyCancelling = message.includes("42210000") ||
|
|
6972
|
+
message.includes("order pending cancel");
|
|
6973
|
+
if (!alreadyCancelling) {
|
|
6974
|
+
throw cancelError;
|
|
6975
|
+
}
|
|
6976
|
+
getLogger().warn(`Order ${order.id} (${order.symbol}) is already pending cancel at the broker — proceeding with position close without it`, {
|
|
6977
|
+
account: auth.adapticAccountId || "direct",
|
|
6978
|
+
symbol: normalizedSymbol,
|
|
6979
|
+
type: "warn",
|
|
6980
|
+
});
|
|
6981
|
+
}
|
|
6952
6982
|
}
|
|
6953
6983
|
}
|
|
6954
6984
|
if (cancelledCount > 0) {
|
|
@@ -6964,12 +6994,17 @@ async function closePosition$1(auth, symbolOrAssetId, params) {
|
|
|
6964
6994
|
const verifyDelayMs = 500;
|
|
6965
6995
|
for (let attempt = 1; attempt <= maxVerifyAttempts; attempt++) {
|
|
6966
6996
|
await new Promise((r) => setTimeout(r, verifyDelayMs));
|
|
6967
|
-
const
|
|
6997
|
+
const allRemainingOrders = isCryptoSymbol$1(symbolOrAssetId)
|
|
6968
6998
|
? (await getOrders$1(auth, { status: "open" })).filter((o) => o.symbol.replace(/[-/]/g, "") === normalizedSymbol)
|
|
6969
6999
|
: await getOrders$1(auth, {
|
|
6970
7000
|
status: "open",
|
|
6971
7001
|
symbols: [normalizedSymbol],
|
|
6972
7002
|
});
|
|
7003
|
+
// Orders stuck in pending_cancel / pending_replace are already
|
|
7004
|
+
// terminalising (or wedged — see the 42210000 handling above);
|
|
7005
|
+
// waiting longer will not change them, so they must not make
|
|
7006
|
+
// the verification spin to exhaustion on every close attempt.
|
|
7007
|
+
const remainingOrders = allRemainingOrders.filter((o) => o.status !== "pending_cancel" && o.status !== "pending_replace");
|
|
6973
7008
|
if (remainingOrders.length === 0) {
|
|
6974
7009
|
getLogger().info(`Cancel verification passed for ${normalizedSymbol} (attempt ${attempt}/${maxVerifyAttempts})`, {
|
|
6975
7010
|
account: auth.adapticAccountId || "direct",
|
|
@@ -9320,8 +9355,11 @@ const fetchTrades = async (symbol, options) => {
|
|
|
9320
9355
|
*
|
|
9321
9356
|
* This module provides functions to interact with the Massive.com Indices API.
|
|
9322
9357
|
*/
|
|
9323
|
-
// Constants from environment variables
|
|
9324
|
-
|
|
9358
|
+
// Constants from environment variables.
|
|
9359
|
+
// Backward-compat: ALPACA_INDICES_API_KEY is the pre-2026-Q2 name (vendor was
|
|
9360
|
+
// renamed Alpaca → Massive); MASSIVE_INDICES_API_KEY is preferred. The fallback
|
|
9361
|
+
// stays so consumers that haven't migrated env vars don't break.
|
|
9362
|
+
const { MASSIVE_INDICES_API_KEY, ALPACA_INDICES_API_KEY } = process.env;
|
|
9325
9363
|
// Define concurrency limits for API
|
|
9326
9364
|
const MASSIVE_INDICES_CONCURRENCY_LIMIT = 5;
|
|
9327
9365
|
const massiveIndicesLimit = pLimit(MASSIVE_INDICES_CONCURRENCY_LIMIT);
|
|
@@ -9333,7 +9371,7 @@ const MASSIVE_API_BASE_URL = "https://api.massive.com";
|
|
|
9333
9371
|
* @throws {Error} If no API key is available
|
|
9334
9372
|
*/
|
|
9335
9373
|
const validateApiKey = (apiKey) => {
|
|
9336
|
-
const key = apiKey || ALPACA_INDICES_API_KEY;
|
|
9374
|
+
const key = apiKey || MASSIVE_INDICES_API_KEY || ALPACA_INDICES_API_KEY;
|
|
9337
9375
|
if (!key) {
|
|
9338
9376
|
throw new Error("Massive Indices API key is missing");
|
|
9339
9377
|
}
|