@adaptic/utils 0.0.959 → 0.0.961
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 +156 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +157 -26
- package/dist/index.mjs.map +1 -1
- package/dist/types/adaptic.d.ts +9 -0
- package/dist/types/adaptic.d.ts.map +1 -1
- package/dist/types/alpaca/legacy/positions.d.ts +2 -2
- package/dist/types/alpaca/legacy/positions.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -6
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/massive.d.ts.map +1 -1
- package/dist/types/price-utils.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -309,6 +309,22 @@ const fetchAssetOverview = async (symbol) => {
|
|
|
309
309
|
};
|
|
310
310
|
}
|
|
311
311
|
};
|
|
312
|
+
/**
|
|
313
|
+
* Gracefully disconnects the shared Apollo client and releases its resources.
|
|
314
|
+
* Call this during process shutdown to close keep-alive HTTP connections
|
|
315
|
+
* and drain in-flight operations.
|
|
316
|
+
*
|
|
317
|
+
* After calling `disconnectClient()`, the next call to `getSharedApolloClient()`
|
|
318
|
+
* will create a fresh instance.
|
|
319
|
+
*/
|
|
320
|
+
const disconnectClient = () => {
|
|
321
|
+
if (apolloClientInstance) {
|
|
322
|
+
apolloClientInstance = null;
|
|
323
|
+
getLogger().info("[adaptic] Shared Apollo client reference cleared");
|
|
324
|
+
}
|
|
325
|
+
// Delegate to backend-legacy's stopClient() which calls .stop() on the underlying singleton
|
|
326
|
+
adaptic$1.stopClient();
|
|
327
|
+
};
|
|
312
328
|
|
|
313
329
|
const ANSI_BACKGROUND_OFFSET = 10;
|
|
314
330
|
|
|
@@ -5557,7 +5573,7 @@ const CRYPTO_QUOTE_CURRENCIES$1 = ["USD", "USDT", "USDC", "BTC"];
|
|
|
5557
5573
|
* "BTC/USD"). Equity tickers never end with these suffixes because Alpaca
|
|
5558
5574
|
* equity symbols are plain tickers without a quote currency.
|
|
5559
5575
|
*/
|
|
5560
|
-
function isCryptoSymbol$
|
|
5576
|
+
function isCryptoSymbol$2(symbol) {
|
|
5561
5577
|
if (symbol.includes("/"))
|
|
5562
5578
|
return true;
|
|
5563
5579
|
const upper = symbol.toUpperCase();
|
|
@@ -5611,7 +5627,7 @@ async function getLatestQuotes$1(auth, params) {
|
|
|
5611
5627
|
const equitySymbols = [];
|
|
5612
5628
|
const cryptoSymbols = [];
|
|
5613
5629
|
for (const sym of symbols) {
|
|
5614
|
-
if (isCryptoSymbol$
|
|
5630
|
+
if (isCryptoSymbol$2(sym)) {
|
|
5615
5631
|
cryptoSymbols.push(sym);
|
|
5616
5632
|
}
|
|
5617
5633
|
else {
|
|
@@ -5819,7 +5835,7 @@ const CRYPTO_QUOTE_CURRENCIES = ["USD", "USDT", "USDC", "BTC"];
|
|
|
5819
5835
|
* "BTC/USD"). Equity tickers never end with these suffixes because Alpaca
|
|
5820
5836
|
* equity symbols are plain tickers without a quote currency.
|
|
5821
5837
|
*/
|
|
5822
|
-
function isCryptoSymbol(symbol) {
|
|
5838
|
+
function isCryptoSymbol$1(symbol) {
|
|
5823
5839
|
if (symbol.includes("/"))
|
|
5824
5840
|
return true;
|
|
5825
5841
|
const upper = symbol.toUpperCase();
|
|
@@ -5871,7 +5887,7 @@ async function fetchPosition(auth, symbolOrAssetId) {
|
|
|
5871
5887
|
const { APIKey, APISecret, type } = await validateAuth(auth);
|
|
5872
5888
|
const apiBaseUrl = getTradingApiUrl(type);
|
|
5873
5889
|
// Normalize crypto symbols for Alpaca API compatibility
|
|
5874
|
-
const normalizedSymbol = isCryptoSymbol(symbolOrAssetId)
|
|
5890
|
+
const normalizedSymbol = isCryptoSymbol$1(symbolOrAssetId)
|
|
5875
5891
|
? symbolOrAssetId.replace(/[-/]/g, "")
|
|
5876
5892
|
: symbolOrAssetId;
|
|
5877
5893
|
const response = await fetch(`${apiBaseUrl}/positions/${normalizedSymbol}`, {
|
|
@@ -5908,7 +5924,7 @@ async function fetchPosition(auth, symbolOrAssetId) {
|
|
|
5908
5924
|
* @param auth - The authentication details for Alpaca
|
|
5909
5925
|
* @param symbolOrAssetId - The symbol or asset ID of the position to close
|
|
5910
5926
|
* @param params - Optional parameters for closing the position
|
|
5911
|
-
* @returns The order created to close the position
|
|
5927
|
+
* @returns The order created to close the position, or null if position doesn't exist (404)
|
|
5912
5928
|
*/
|
|
5913
5929
|
async function closePosition$1(auth, symbolOrAssetId, params) {
|
|
5914
5930
|
try {
|
|
@@ -5917,7 +5933,7 @@ async function closePosition$1(auth, symbolOrAssetId, params) {
|
|
|
5917
5933
|
// Normalize crypto symbols for Alpaca API compatibility.
|
|
5918
5934
|
// Alpaca positions endpoint rejects hyphenated format (e.g., "SOL-USD")
|
|
5919
5935
|
// but accepts concatenated form (e.g., "SOLUSD").
|
|
5920
|
-
const normalizedSymbol = isCryptoSymbol(symbolOrAssetId)
|
|
5936
|
+
const normalizedSymbol = isCryptoSymbol$1(symbolOrAssetId)
|
|
5921
5937
|
? symbolOrAssetId.replace(/[-/]/g, "")
|
|
5922
5938
|
: symbolOrAssetId;
|
|
5923
5939
|
const useLimitOrder = params?.useLimitOrder ?? false;
|
|
@@ -5933,25 +5949,34 @@ async function closePosition$1(auth, symbolOrAssetId, params) {
|
|
|
5933
5949
|
// For crypto, Alpaca stores orders under "SOL/USD" (slash format) but the
|
|
5934
5950
|
// symbols filter may not match across formats reliably. Fetch all open
|
|
5935
5951
|
// orders without symbol filter and match client-side via normalization.
|
|
5936
|
-
const openOrders = isCryptoSymbol(symbolOrAssetId)
|
|
5952
|
+
const openOrders = isCryptoSymbol$1(symbolOrAssetId)
|
|
5937
5953
|
? await getOrders$1(auth, { status: "open" })
|
|
5938
|
-
: await getOrders$1(auth, {
|
|
5954
|
+
: await getOrders$1(auth, {
|
|
5955
|
+
status: "open",
|
|
5956
|
+
symbols: [normalizedSymbol],
|
|
5957
|
+
});
|
|
5939
5958
|
let cancelledCount = 0;
|
|
5940
5959
|
for (const order of openOrders) {
|
|
5941
5960
|
const orderSymbolNorm = order.symbol.replace(/[-/]/g, "");
|
|
5942
5961
|
if (orderSymbolNorm === normalizedSymbol) {
|
|
5943
|
-
getLogger().info(`Cancelling order ${order.id} (${order.symbol}) for ${normalizedSymbol}`, {
|
|
5962
|
+
getLogger().info(`Cancelling order ${order.id} (${order.symbol}) for ${normalizedSymbol}`, {
|
|
5963
|
+
account: auth.adapticAccountId || "direct",
|
|
5964
|
+
symbol: normalizedSymbol,
|
|
5965
|
+
});
|
|
5944
5966
|
await cancelOrder$1(auth, order.id);
|
|
5945
5967
|
cancelledCount++;
|
|
5946
5968
|
}
|
|
5947
5969
|
}
|
|
5948
5970
|
if (cancelledCount > 0) {
|
|
5949
|
-
getLogger().info(`Cancelled ${cancelledCount} open orders for ${normalizedSymbol}`, {
|
|
5971
|
+
getLogger().info(`Cancelled ${cancelledCount} open orders for ${normalizedSymbol}`, {
|
|
5972
|
+
account: auth.adapticAccountId || "direct",
|
|
5973
|
+
symbol: normalizedSymbol,
|
|
5974
|
+
});
|
|
5950
5975
|
}
|
|
5951
5976
|
}
|
|
5952
5977
|
// Crypto positions cannot use limit orders with SIP quotes or time_in_force="day".
|
|
5953
5978
|
// Use direct DELETE (market order) for crypto regardless of useLimitOrder flag.
|
|
5954
|
-
if (useLimitOrder && !isCryptoSymbol(symbolOrAssetId)) {
|
|
5979
|
+
if (useLimitOrder && !isCryptoSymbol$1(symbolOrAssetId)) {
|
|
5955
5980
|
// Attempt limit order closure; if quotes are unavailable (after-hours, IEX gaps),
|
|
5956
5981
|
// fall back to market order (DELETE) so the position still gets closed.
|
|
5957
5982
|
try {
|
|
@@ -6001,7 +6026,9 @@ async function closePosition$1(auth, symbolOrAssetId, params) {
|
|
|
6001
6026
|
catch (limitOrderError) {
|
|
6002
6027
|
// Quote unavailable or invalid price — fall back to market order (DELETE)
|
|
6003
6028
|
// so the position still gets closed rather than leaving it open
|
|
6004
|
-
const errMsg = limitOrderError instanceof Error
|
|
6029
|
+
const errMsg = limitOrderError instanceof Error
|
|
6030
|
+
? limitOrderError.message
|
|
6031
|
+
: String(limitOrderError);
|
|
6005
6032
|
getLogger().warn(`Limit order closure failed for ${symbolOrAssetId} (${errMsg}), falling back to market order`, {
|
|
6006
6033
|
account: auth.adapticAccountId || "direct",
|
|
6007
6034
|
symbol: symbolOrAssetId,
|
|
@@ -6012,8 +6039,11 @@ async function closePosition$1(auth, symbolOrAssetId, params) {
|
|
|
6012
6039
|
}
|
|
6013
6040
|
// Market order (DELETE) path — used when limit orders are not requested,
|
|
6014
6041
|
// for crypto symbols, or as a fallback when limit order quotes are unavailable
|
|
6015
|
-
if (isCryptoSymbol(symbolOrAssetId)) {
|
|
6016
|
-
getLogger().info(`Closing crypto position ${normalizedSymbol} via market order (DELETE endpoint)`, {
|
|
6042
|
+
if (isCryptoSymbol$1(symbolOrAssetId)) {
|
|
6043
|
+
getLogger().info(`Closing crypto position ${normalizedSymbol} via market order (DELETE endpoint)`, {
|
|
6044
|
+
account: auth.adapticAccountId || "direct",
|
|
6045
|
+
symbol: normalizedSymbol,
|
|
6046
|
+
});
|
|
6017
6047
|
}
|
|
6018
6048
|
const queryParams = new URLSearchParams();
|
|
6019
6049
|
if (params?.qty !== undefined) {
|
|
@@ -6033,6 +6063,15 @@ async function closePosition$1(auth, symbolOrAssetId, params) {
|
|
|
6033
6063
|
});
|
|
6034
6064
|
if (!response.ok) {
|
|
6035
6065
|
const errorText = await response.text();
|
|
6066
|
+
// Handle 404 (position not found) gracefully - position may have already been closed
|
|
6067
|
+
// or never existed. Return null instead of throwing to allow callers to handle this.
|
|
6068
|
+
if (response.status === 404) {
|
|
6069
|
+
getLogger().info(`Position ${normalizedSymbol} not found in Alpaca (404) - may already be closed`, {
|
|
6070
|
+
account: auth.adapticAccountId || "direct",
|
|
6071
|
+
symbol: normalizedSymbol,
|
|
6072
|
+
});
|
|
6073
|
+
return null;
|
|
6074
|
+
}
|
|
6036
6075
|
throw new Error(`Failed to close position: ${response.status} ${response.statusText} ${errorText}`);
|
|
6037
6076
|
}
|
|
6038
6077
|
return (await response.json());
|
|
@@ -6080,8 +6119,8 @@ async function closeAllPositions$1(auth, params = { cancel_orders: true, useLimi
|
|
|
6080
6119
|
return [];
|
|
6081
6120
|
}
|
|
6082
6121
|
// Separate crypto and equity positions — crypto cannot use SIP quotes or time_in_force="day"
|
|
6083
|
-
const equityPositions = allPositions.filter((p) => !isCryptoSymbol(p.symbol));
|
|
6084
|
-
const cryptoPositions = allPositions.filter((p) => isCryptoSymbol(p.symbol));
|
|
6122
|
+
const equityPositions = allPositions.filter((p) => !isCryptoSymbol$1(p.symbol));
|
|
6123
|
+
const cryptoPositions = allPositions.filter((p) => isCryptoSymbol$1(p.symbol));
|
|
6085
6124
|
getLogger().info(`Found ${allPositions.length} positions to close (${equityPositions.length} equity, ${cryptoPositions.length} crypto)`, { account: auth.adapticAccountId || "direct" });
|
|
6086
6125
|
// Close crypto positions via direct DELETE (market order) — no SIP quotes needed
|
|
6087
6126
|
for (const position of cryptoPositions) {
|
|
@@ -6104,11 +6143,17 @@ async function closeAllPositions$1(auth, params = { cancel_orders: true, useLimi
|
|
|
6104
6143
|
}
|
|
6105
6144
|
else {
|
|
6106
6145
|
const errorText = await response.text();
|
|
6107
|
-
getLogger().warn(`Failed to close crypto position ${position.symbol}: ${response.status} ${errorText}`, {
|
|
6146
|
+
getLogger().warn(`Failed to close crypto position ${position.symbol}: ${response.status} ${errorText}`, {
|
|
6147
|
+
account: auth.adapticAccountId || "direct",
|
|
6148
|
+
symbol: position.symbol,
|
|
6149
|
+
});
|
|
6108
6150
|
}
|
|
6109
6151
|
}
|
|
6110
6152
|
catch (cryptoError) {
|
|
6111
|
-
getLogger().warn(`Error closing crypto position ${position.symbol}: ${cryptoError instanceof Error ? cryptoError.message : String(cryptoError)}`, {
|
|
6153
|
+
getLogger().warn(`Error closing crypto position ${position.symbol}: ${cryptoError instanceof Error ? cryptoError.message : String(cryptoError)}`, {
|
|
6154
|
+
account: auth.adapticAccountId || "direct",
|
|
6155
|
+
symbol: position.symbol,
|
|
6156
|
+
});
|
|
6112
6157
|
}
|
|
6113
6158
|
}
|
|
6114
6159
|
// Close equity positions via limit orders with SIP quotes
|
|
@@ -6201,8 +6246,8 @@ async function closeAllPositionsAfterHours$1(auth, params = { cancel_orders: tru
|
|
|
6201
6246
|
return;
|
|
6202
6247
|
}
|
|
6203
6248
|
// Separate crypto and equity positions
|
|
6204
|
-
const equityPositions = allPositions.filter((p) => !isCryptoSymbol(p.symbol));
|
|
6205
|
-
const cryptoPositions = allPositions.filter((p) => isCryptoSymbol(p.symbol));
|
|
6249
|
+
const equityPositions = allPositions.filter((p) => !isCryptoSymbol$1(p.symbol));
|
|
6250
|
+
const cryptoPositions = allPositions.filter((p) => isCryptoSymbol$1(p.symbol));
|
|
6206
6251
|
getLogger().info(`Found ${allPositions.length} positions to close after hours (${equityPositions.length} equity, ${cryptoPositions.length} crypto)`, { account: auth.adapticAccountId || "direct" });
|
|
6207
6252
|
if (cancel_orders) {
|
|
6208
6253
|
await cancelAllOrders$1(auth);
|
|
@@ -6231,7 +6276,10 @@ async function closeAllPositionsAfterHours$1(auth, params = { cancel_orders: tru
|
|
|
6231
6276
|
}
|
|
6232
6277
|
else {
|
|
6233
6278
|
const errorText = await response.text();
|
|
6234
|
-
getLogger().warn(`Failed to close crypto position ${position.symbol}: ${response.status} ${errorText}`, {
|
|
6279
|
+
getLogger().warn(`Failed to close crypto position ${position.symbol}: ${response.status} ${errorText}`, {
|
|
6280
|
+
account: auth.adapticAccountId || "direct",
|
|
6281
|
+
symbol: position.symbol,
|
|
6282
|
+
});
|
|
6235
6283
|
}
|
|
6236
6284
|
}
|
|
6237
6285
|
catch (cryptoError) {
|
|
@@ -7873,6 +7921,84 @@ const massiveLimit = pLimit(MASSIVE_CONCURRENCY_LIMIT);
|
|
|
7873
7921
|
* request settles, so subsequent calls after resolution make a fresh request.
|
|
7874
7922
|
*/
|
|
7875
7923
|
const fetchLastTradeInflight = new Map();
|
|
7924
|
+
/**
|
|
7925
|
+
* Check if a symbol is a crypto pair based on common patterns.
|
|
7926
|
+
* Crypto symbols typically end in USD, USDT, USDC, or contain a hyphen with USD.
|
|
7927
|
+
* Examples: BTCUSD, BTC-USD, BTC/USD, LINKUSD, SOL-USD
|
|
7928
|
+
*
|
|
7929
|
+
* @param symbol - The ticker symbol to check
|
|
7930
|
+
* @returns True if the symbol appears to be a crypto pair
|
|
7931
|
+
*/
|
|
7932
|
+
function isCryptoSymbol(symbol) {
|
|
7933
|
+
// Pattern: ends with USD/USDT/USDC and has 3-4 letter base (e.g., BTCUSD, LINKUSD)
|
|
7934
|
+
if (/^[A-Z]{2,5}(USD[TC]?)$/i.test(symbol)) {
|
|
7935
|
+
return true;
|
|
7936
|
+
}
|
|
7937
|
+
// Pattern: contains hyphen or slash with USD (e.g., BTC-USD, BTC/USD)
|
|
7938
|
+
if (/^[A-Z]{2,5}[-/]USD[TC]?$/i.test(symbol)) {
|
|
7939
|
+
return true;
|
|
7940
|
+
}
|
|
7941
|
+
// Pattern: already has X: prefix (e.g., X:BTC-USD)
|
|
7942
|
+
if (symbol.startsWith("X:")) {
|
|
7943
|
+
return true;
|
|
7944
|
+
}
|
|
7945
|
+
return false;
|
|
7946
|
+
}
|
|
7947
|
+
/**
|
|
7948
|
+
* Normalize a symbol for the Massive.com API.
|
|
7949
|
+
* Crypto symbols must be prefixed with "X:" and use hyphen format (e.g., X:BTC-USD).
|
|
7950
|
+
* Stock symbols are passed through unchanged.
|
|
7951
|
+
*
|
|
7952
|
+
* @param symbol - The raw ticker symbol
|
|
7953
|
+
* @returns The symbol formatted for Massive.com API
|
|
7954
|
+
*/
|
|
7955
|
+
function normalizeMassiveSymbol(symbol) {
|
|
7956
|
+
// If already has X: prefix, ensure hyphen format
|
|
7957
|
+
if (symbol.startsWith("X:")) {
|
|
7958
|
+
return symbol;
|
|
7959
|
+
}
|
|
7960
|
+
// Check if it's a crypto symbol
|
|
7961
|
+
if (!isCryptoSymbol(symbol)) {
|
|
7962
|
+
return symbol; // Stock symbol - return unchanged
|
|
7963
|
+
}
|
|
7964
|
+
// Normalize crypto symbol to X:BASE-QUOTE format
|
|
7965
|
+
// Handle formats: BTCUSD, BTC-USD, BTC/USD -> X:BTC-USD
|
|
7966
|
+
let base;
|
|
7967
|
+
let quote;
|
|
7968
|
+
if (symbol.includes("-")) {
|
|
7969
|
+
// Format: BTC-USD
|
|
7970
|
+
const parts = symbol.split("-");
|
|
7971
|
+
base = parts[0];
|
|
7972
|
+
quote = parts.slice(1).join("-");
|
|
7973
|
+
}
|
|
7974
|
+
else if (symbol.includes("/")) {
|
|
7975
|
+
// Format: BTC/USD
|
|
7976
|
+
const parts = symbol.split("/");
|
|
7977
|
+
base = parts[0];
|
|
7978
|
+
quote = parts.slice(1).join("/");
|
|
7979
|
+
}
|
|
7980
|
+
else {
|
|
7981
|
+
// Format: BTCUSD - need to extract base and quote
|
|
7982
|
+
// Common quote currencies: USD, USDT, USDC
|
|
7983
|
+
if (symbol.endsWith("USDT")) {
|
|
7984
|
+
base = symbol.slice(0, -4);
|
|
7985
|
+
quote = "USDT";
|
|
7986
|
+
}
|
|
7987
|
+
else if (symbol.endsWith("USDC")) {
|
|
7988
|
+
base = symbol.slice(0, -4);
|
|
7989
|
+
quote = "USDC";
|
|
7990
|
+
}
|
|
7991
|
+
else if (symbol.endsWith("USD")) {
|
|
7992
|
+
base = symbol.slice(0, -3);
|
|
7993
|
+
quote = "USD";
|
|
7994
|
+
}
|
|
7995
|
+
else {
|
|
7996
|
+
// Unknown format, return as-is
|
|
7997
|
+
return symbol;
|
|
7998
|
+
}
|
|
7999
|
+
}
|
|
8000
|
+
return `X:${base.toUpperCase()}-${quote.toUpperCase()}`;
|
|
8001
|
+
}
|
|
7876
8002
|
// Use to update general information about stocks
|
|
7877
8003
|
/**
|
|
7878
8004
|
* Fetches general information about a stock ticker.
|
|
@@ -7994,7 +8120,9 @@ const fetchLastTradeImpl = async (symbol, options) => {
|
|
|
7994
8120
|
}
|
|
7995
8121
|
const apiKey = options?.apiKey || MASSIVE_API_KEY;
|
|
7996
8122
|
validateMassiveApiKey$1(apiKey);
|
|
7997
|
-
|
|
8123
|
+
// Normalize crypto symbols to Massive.com API format (e.g., LINK-USD -> X:LINK-USD)
|
|
8124
|
+
const normalizedSymbol = normalizeMassiveSymbol(symbol);
|
|
8125
|
+
const baseUrl = `https://api.massive.com/v3/trades/${encodeURIComponent(normalizedSymbol)}`;
|
|
7998
8126
|
const params = new URLSearchParams({
|
|
7999
8127
|
apiKey,
|
|
8000
8128
|
limit: "1",
|
|
@@ -8030,9 +8158,10 @@ const fetchLastTradeImpl = async (symbol, options) => {
|
|
|
8030
8158
|
}
|
|
8031
8159
|
catch (error) {
|
|
8032
8160
|
const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
|
|
8033
|
-
const contextualMessage = `Error fetching last trade for ${symbol}`;
|
|
8161
|
+
const contextualMessage = `Error fetching last trade for ${symbol}${normalizedSymbol !== symbol ? ` (normalized: ${normalizedSymbol})` : ""}`;
|
|
8034
8162
|
getLogger().error(`${contextualMessage}: ${errorMessage}`, {
|
|
8035
8163
|
symbol,
|
|
8164
|
+
normalizedSymbol,
|
|
8036
8165
|
errorType: error instanceof Error && error.message.includes("AUTH_ERROR")
|
|
8037
8166
|
? "AUTH_ERROR"
|
|
8038
8167
|
: error instanceof Error && error.message.includes("RATE_LIMIT")
|
|
@@ -8727,10 +8856,11 @@ const calculateFees = async (action, trade, alpacaAccount) => {
|
|
|
8727
8856
|
};
|
|
8728
8857
|
const computeTotalFees = async (trade) => {
|
|
8729
8858
|
let totalFees = 0;
|
|
8730
|
-
//
|
|
8859
|
+
// Use the shared singleton Apollo client to avoid creating orphaned connections
|
|
8860
|
+
const client = await getSharedApolloClient();
|
|
8731
8861
|
const alpacaAccount = (await adaptic$1.alpacaAccount.get({
|
|
8732
8862
|
id: trade.alpacaAccountId,
|
|
8733
|
-
}));
|
|
8863
|
+
}, client));
|
|
8734
8864
|
if (!alpacaAccount)
|
|
8735
8865
|
return totalFees;
|
|
8736
8866
|
const feePromises = trade?.actions?.map((action) => calculateFees(action, trade, alpacaAccount));
|
|
@@ -67785,6 +67915,7 @@ const adaptic = {
|
|
|
67785
67915
|
getApolloClient: getSharedApolloClient,
|
|
67786
67916
|
configureAuth: configureAuth,
|
|
67787
67917
|
isAuthConfigured: isAuthConfigured,
|
|
67918
|
+
disconnectClient: disconnectClient,
|
|
67788
67919
|
},
|
|
67789
67920
|
alpaca: {
|
|
67790
67921
|
// New SDK-based client factory (RECOMMENDED)
|