@adaptic/utils 0.1.2 → 0.1.4
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 +204 -180
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +204 -180
- package/dist/index.mjs.map +1 -1
- package/dist/test.js +33 -9
- package/dist/test.js.map +1 -1
- package/dist/types/alpaca/legacy/account.d.ts +4 -4
- package/dist/types/alpaca/legacy/account.d.ts.map +1 -1
- package/dist/types/alpaca/legacy/auth.d.ts +2 -2
- package/dist/types/alpaca-market-data-api.d.ts +2 -0
- package/dist/types/alpaca-market-data-api.d.ts.map +1 -1
- package/dist/types/crypto.d.ts +2 -2
- package/dist/types/crypto.d.ts.map +1 -1
- package/dist/types/performance-metrics.d.ts +2 -2
- package/dist/types/performance-metrics.d.ts.map +1 -1
- package/dist/types/types/alpaca-types.d.ts +6 -6
- package/dist/types/types/alpaca-types.d.ts.map +1 -1
- package/dist/types/types/metrics-types.d.ts +1 -1
- package/dist/types/types/metrics-types.d.ts.map +1 -1
- package/dist/types/utils/auth-validator.d.ts +9 -4
- package/dist/types/utils/auth-validator.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -320,23 +320,42 @@ const fetchAssetOverview = async (symbol) => {
|
|
|
320
320
|
/**
|
|
321
321
|
* Validates Alpaca API credentials
|
|
322
322
|
* @param auth - Authentication object containing API key and secret
|
|
323
|
-
* @
|
|
323
|
+
* @param options - Validation options
|
|
324
|
+
* @param options.throwOnMissing - If false, missing credentials will log a warning instead of throwing (default: true)
|
|
325
|
+
* @throws {Error} If credentials are invalid (when throwOnMissing is true)
|
|
326
|
+
* @returns {boolean} True if credentials are valid, false if missing (when throwOnMissing is false)
|
|
324
327
|
*/
|
|
325
|
-
function validateAlpacaCredentials(auth) {
|
|
328
|
+
function validateAlpacaCredentials(auth, options = { throwOnMissing: true }) {
|
|
329
|
+
const { throwOnMissing = true } = options;
|
|
330
|
+
// Check for missing or empty API key
|
|
326
331
|
if (!auth.apiKey ||
|
|
327
332
|
typeof auth.apiKey !== "string" ||
|
|
328
333
|
auth.apiKey.trim().length === 0) {
|
|
329
|
-
|
|
334
|
+
if (throwOnMissing) {
|
|
335
|
+
throw new Error("Invalid Alpaca API key: must be a non-empty string");
|
|
336
|
+
}
|
|
337
|
+
console.warn("[AlpacaAPI] API key not configured. Market data features will be unavailable.");
|
|
338
|
+
return false;
|
|
330
339
|
}
|
|
340
|
+
// Check for missing or empty API secret
|
|
331
341
|
if (!auth.apiSecret ||
|
|
332
342
|
typeof auth.apiSecret !== "string" ||
|
|
333
343
|
auth.apiSecret.trim().length === 0) {
|
|
334
|
-
|
|
344
|
+
if (throwOnMissing) {
|
|
345
|
+
throw new Error("Invalid Alpaca API secret: must be a non-empty string");
|
|
346
|
+
}
|
|
347
|
+
console.warn("[AlpacaAPI] API secret not configured. Market data features will be unavailable.");
|
|
348
|
+
return false;
|
|
335
349
|
}
|
|
336
350
|
// Alpaca keys are typically 20+ characters
|
|
337
351
|
if (auth.apiKey.length < 10) {
|
|
338
|
-
|
|
352
|
+
if (throwOnMissing) {
|
|
353
|
+
throw new Error("Alpaca API key appears to be too short");
|
|
354
|
+
}
|
|
355
|
+
console.warn("[AlpacaAPI] API key appears to be too short.");
|
|
356
|
+
return false;
|
|
339
357
|
}
|
|
358
|
+
return true;
|
|
340
359
|
}
|
|
341
360
|
/**
|
|
342
361
|
* Validates Polygon API key
|
|
@@ -369,21 +388,21 @@ function validateAlphaVantageApiKey(apiKey) {
|
|
|
369
388
|
async function validateAuth(auth) {
|
|
370
389
|
if (auth.adapticAccountId) {
|
|
371
390
|
const client = await getSharedApolloClient();
|
|
372
|
-
const
|
|
391
|
+
const brokerageAccount = (await adaptic$1.brokerageAccount.get({
|
|
373
392
|
id: auth.adapticAccountId,
|
|
374
393
|
}, client));
|
|
375
|
-
if (!
|
|
394
|
+
if (!brokerageAccount || !brokerageAccount.apiKey || !brokerageAccount.apiSecret) {
|
|
376
395
|
throw new Error("Alpaca account not found or incomplete");
|
|
377
396
|
}
|
|
378
397
|
validateAlpacaCredentials({
|
|
379
|
-
apiKey:
|
|
380
|
-
apiSecret:
|
|
381
|
-
isPaper:
|
|
398
|
+
apiKey: brokerageAccount.apiKey,
|
|
399
|
+
apiSecret: brokerageAccount.apiSecret,
|
|
400
|
+
isPaper: brokerageAccount.type === "PAPER",
|
|
382
401
|
});
|
|
383
402
|
return {
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
type:
|
|
403
|
+
apiKey: brokerageAccount.apiKey,
|
|
404
|
+
apiSecret: brokerageAccount.apiSecret,
|
|
405
|
+
type: brokerageAccount.type,
|
|
387
406
|
};
|
|
388
407
|
}
|
|
389
408
|
else if (auth.alpacaApiKey && auth.alpacaApiSecret) {
|
|
@@ -392,8 +411,8 @@ async function validateAuth(auth) {
|
|
|
392
411
|
apiKey: auth.alpacaApiKey,
|
|
393
412
|
apiSecret: auth.alpacaApiSecret});
|
|
394
413
|
return {
|
|
395
|
-
|
|
396
|
-
|
|
414
|
+
apiKey: auth.alpacaApiKey,
|
|
415
|
+
apiSecret: auth.alpacaApiSecret,
|
|
397
416
|
type: accountType,
|
|
398
417
|
};
|
|
399
418
|
}
|
|
@@ -564,11 +583,11 @@ const ORDER_CHUNK_SIZE = 500;
|
|
|
564
583
|
async function makeRequest(auth, params) {
|
|
565
584
|
const { endpoint, method, body, queryString, apiBaseUrl } = params;
|
|
566
585
|
try {
|
|
567
|
-
const {
|
|
586
|
+
const { apiKey, apiSecret, type } = await validateAuth(auth);
|
|
568
587
|
const apiBaseUrlInner = apiBaseUrl
|
|
569
588
|
? apiBaseUrl
|
|
570
589
|
: getTradingApiUrl(type);
|
|
571
|
-
if (!
|
|
590
|
+
if (!apiKey || !apiSecret) {
|
|
572
591
|
throw new Error("No valid Alpaca authentication found. Please provide either auth object or set ALPACA_API_KEY and ALPACA_API_SECRET environment variables.");
|
|
573
592
|
}
|
|
574
593
|
const url = `${apiBaseUrlInner}${endpoint}${queryString || ""}`;
|
|
@@ -579,8 +598,8 @@ async function makeRequest(auth, params) {
|
|
|
579
598
|
const fetchOptions = {
|
|
580
599
|
method,
|
|
581
600
|
headers: {
|
|
582
|
-
"APCA-API-KEY-ID":
|
|
583
|
-
"APCA-API-SECRET-KEY":
|
|
601
|
+
"APCA-API-KEY-ID": apiKey,
|
|
602
|
+
"APCA-API-SECRET-KEY": apiSecret,
|
|
584
603
|
},
|
|
585
604
|
};
|
|
586
605
|
// Only add Content-Type and body for non-GET/HEAD requests that have a body
|
|
@@ -624,13 +643,13 @@ async function makeRequest(auth, params) {
|
|
|
624
643
|
*/
|
|
625
644
|
async function createOrder$1(auth, params) {
|
|
626
645
|
try {
|
|
627
|
-
const {
|
|
646
|
+
const { apiKey, apiSecret, type } = await validateAuth(auth);
|
|
628
647
|
const apiBaseUrl = getTradingApiUrl(type);
|
|
629
648
|
const response = await fetch(`${apiBaseUrl}/v2/orders`, {
|
|
630
649
|
method: "POST",
|
|
631
650
|
headers: {
|
|
632
|
-
"APCA-API-KEY-ID":
|
|
633
|
-
"APCA-API-SECRET-KEY":
|
|
651
|
+
"APCA-API-KEY-ID": apiKey,
|
|
652
|
+
"APCA-API-SECRET-KEY": apiSecret,
|
|
634
653
|
"Content-Type": "application/json",
|
|
635
654
|
},
|
|
636
655
|
body: JSON.stringify(params),
|
|
@@ -655,7 +674,7 @@ async function createOrder$1(auth, params) {
|
|
|
655
674
|
*/
|
|
656
675
|
async function getOrders$1(auth, params = {}) {
|
|
657
676
|
try {
|
|
658
|
-
const {
|
|
677
|
+
const { apiKey, apiSecret, type } = await validateAuth(auth);
|
|
659
678
|
const apiBaseUrl = getTradingApiUrl(type);
|
|
660
679
|
const allOrders = [];
|
|
661
680
|
let currentUntil = params.until ? params.until : new Date().toISOString();
|
|
@@ -678,8 +697,8 @@ async function getOrders$1(auth, params = {}) {
|
|
|
678
697
|
const response = await fetch(`${apiBaseUrl}/v2/orders?${queryParams}`, {
|
|
679
698
|
method: "GET",
|
|
680
699
|
headers: {
|
|
681
|
-
"APCA-API-KEY-ID":
|
|
682
|
-
"APCA-API-SECRET-KEY":
|
|
700
|
+
"APCA-API-KEY-ID": apiKey,
|
|
701
|
+
"APCA-API-SECRET-KEY": apiSecret,
|
|
683
702
|
},
|
|
684
703
|
signal: createTimeoutSignal(DEFAULT_TIMEOUTS.ALPACA_API),
|
|
685
704
|
});
|
|
@@ -711,13 +730,13 @@ async function getOrders$1(auth, params = {}) {
|
|
|
711
730
|
*/
|
|
712
731
|
async function cancelAllOrders$1(auth) {
|
|
713
732
|
try {
|
|
714
|
-
const {
|
|
733
|
+
const { apiKey, apiSecret, type } = await validateAuth(auth);
|
|
715
734
|
const apiBaseUrl = getTradingApiUrl(type);
|
|
716
735
|
const response = await fetch(`${apiBaseUrl}/v2/orders`, {
|
|
717
736
|
method: "DELETE",
|
|
718
737
|
headers: {
|
|
719
|
-
"APCA-API-KEY-ID":
|
|
720
|
-
"APCA-API-SECRET-KEY":
|
|
738
|
+
"APCA-API-KEY-ID": apiKey,
|
|
739
|
+
"APCA-API-SECRET-KEY": apiSecret,
|
|
721
740
|
},
|
|
722
741
|
signal: createTimeoutSignal(DEFAULT_TIMEOUTS.ALPACA_API),
|
|
723
742
|
});
|
|
@@ -741,7 +760,7 @@ async function cancelAllOrders$1(auth) {
|
|
|
741
760
|
*/
|
|
742
761
|
async function getOrder$1(auth, orderId, nested) {
|
|
743
762
|
try {
|
|
744
|
-
const {
|
|
763
|
+
const { apiKey, apiSecret, type } = await validateAuth(auth);
|
|
745
764
|
const apiBaseUrl = getTradingApiUrl(type);
|
|
746
765
|
const queryParams = new URLSearchParams();
|
|
747
766
|
if (nested)
|
|
@@ -749,8 +768,8 @@ async function getOrder$1(auth, orderId, nested) {
|
|
|
749
768
|
const response = await fetch(`${apiBaseUrl}/v2/orders/${orderId}?${queryParams}`, {
|
|
750
769
|
method: "GET",
|
|
751
770
|
headers: {
|
|
752
|
-
"APCA-API-KEY-ID":
|
|
753
|
-
"APCA-API-SECRET-KEY":
|
|
771
|
+
"APCA-API-KEY-ID": apiKey,
|
|
772
|
+
"APCA-API-SECRET-KEY": apiSecret,
|
|
754
773
|
},
|
|
755
774
|
signal: createTimeoutSignal(DEFAULT_TIMEOUTS.ALPACA_API),
|
|
756
775
|
});
|
|
@@ -774,13 +793,13 @@ async function getOrder$1(auth, orderId, nested) {
|
|
|
774
793
|
*/
|
|
775
794
|
async function replaceOrder$1(auth, orderId, params) {
|
|
776
795
|
try {
|
|
777
|
-
const {
|
|
796
|
+
const { apiKey, apiSecret, type } = await validateAuth(auth);
|
|
778
797
|
const apiBaseUrl = getTradingApiUrl(type);
|
|
779
798
|
const response = await fetch(`${apiBaseUrl}/v2/orders/${orderId}`, {
|
|
780
799
|
method: "PATCH",
|
|
781
800
|
headers: {
|
|
782
|
-
"APCA-API-KEY-ID":
|
|
783
|
-
"APCA-API-SECRET-KEY":
|
|
801
|
+
"APCA-API-KEY-ID": apiKey,
|
|
802
|
+
"APCA-API-SECRET-KEY": apiSecret,
|
|
784
803
|
"Content-Type": "application/json",
|
|
785
804
|
accept: "application/json",
|
|
786
805
|
},
|
|
@@ -806,13 +825,13 @@ async function replaceOrder$1(auth, orderId, params) {
|
|
|
806
825
|
*/
|
|
807
826
|
async function cancelOrder$1(auth, orderId) {
|
|
808
827
|
try {
|
|
809
|
-
const {
|
|
828
|
+
const { apiKey, apiSecret, type } = await validateAuth(auth);
|
|
810
829
|
const apiBaseUrl = getTradingApiUrl(type);
|
|
811
830
|
const response = await fetch(`${apiBaseUrl}/v2/orders/${orderId}`, {
|
|
812
831
|
method: "DELETE",
|
|
813
832
|
headers: {
|
|
814
|
-
"APCA-API-KEY-ID":
|
|
815
|
-
"APCA-API-SECRET-KEY":
|
|
833
|
+
"APCA-API-KEY-ID": apiKey,
|
|
834
|
+
"APCA-API-SECRET-KEY": apiSecret,
|
|
816
835
|
},
|
|
817
836
|
signal: createTimeoutSignal(DEFAULT_TIMEOUTS.ALPACA_API),
|
|
818
837
|
});
|
|
@@ -1394,14 +1413,14 @@ async function fetchNews$1(symbols, params) {
|
|
|
1394
1413
|
}
|
|
1395
1414
|
else if (mergedParams.auth.adapticAccountId) {
|
|
1396
1415
|
const client = await getSharedApolloClient();
|
|
1397
|
-
const
|
|
1416
|
+
const brokerageAccount = (await adaptic$1.brokerageAccount.get({
|
|
1398
1417
|
id: mergedParams.auth.adapticAccountId,
|
|
1399
1418
|
}, client));
|
|
1400
|
-
if (!
|
|
1419
|
+
if (!brokerageAccount || !brokerageAccount.apiKey || !brokerageAccount.apiSecret) {
|
|
1401
1420
|
throw new Error("Alpaca account not found or incomplete");
|
|
1402
1421
|
}
|
|
1403
|
-
APIKey =
|
|
1404
|
-
APISecret =
|
|
1422
|
+
APIKey = brokerageAccount.apiKey;
|
|
1423
|
+
APISecret = brokerageAccount.apiSecret;
|
|
1405
1424
|
}
|
|
1406
1425
|
}
|
|
1407
1426
|
else {
|
|
@@ -1494,14 +1513,14 @@ async function fetchNews$1(symbols, params) {
|
|
|
1494
1513
|
*/
|
|
1495
1514
|
async function fetchAllPositions(auth) {
|
|
1496
1515
|
try {
|
|
1497
|
-
const {
|
|
1516
|
+
const { apiKey, apiSecret, type } = await validateAuth(auth);
|
|
1498
1517
|
const apiBaseUrl = getTradingApiUrl(type);
|
|
1499
1518
|
const apiUrl = `${apiBaseUrl}/v2/positions`;
|
|
1500
1519
|
const response = await fetch(apiUrl, {
|
|
1501
1520
|
method: "GET",
|
|
1502
1521
|
headers: {
|
|
1503
|
-
"APCA-API-KEY-ID":
|
|
1504
|
-
"APCA-API-SECRET-KEY":
|
|
1522
|
+
"APCA-API-KEY-ID": apiKey,
|
|
1523
|
+
"APCA-API-SECRET-KEY": apiSecret,
|
|
1505
1524
|
"Content-Type": "application/json",
|
|
1506
1525
|
},
|
|
1507
1526
|
signal: createTimeoutSignal(DEFAULT_TIMEOUTS.ALPACA_API),
|
|
@@ -1525,13 +1544,13 @@ async function fetchAllPositions(auth) {
|
|
|
1525
1544
|
*/
|
|
1526
1545
|
async function fetchPosition(auth, symbolOrAssetId) {
|
|
1527
1546
|
try {
|
|
1528
|
-
const {
|
|
1547
|
+
const { apiKey, apiSecret, type } = await validateAuth(auth);
|
|
1529
1548
|
const apiBaseUrl = getTradingApiUrl(type);
|
|
1530
1549
|
const response = await fetch(`${apiBaseUrl}/v2/positions/${symbolOrAssetId}`, {
|
|
1531
1550
|
method: "GET",
|
|
1532
1551
|
headers: {
|
|
1533
|
-
"APCA-API-KEY-ID":
|
|
1534
|
-
"APCA-API-SECRET-KEY":
|
|
1552
|
+
"APCA-API-KEY-ID": apiKey,
|
|
1553
|
+
"APCA-API-SECRET-KEY": apiSecret,
|
|
1535
1554
|
"Content-Type": "application/json",
|
|
1536
1555
|
},
|
|
1537
1556
|
signal: createTimeoutSignal(DEFAULT_TIMEOUTS.ALPACA_API),
|
|
@@ -1565,7 +1584,7 @@ async function fetchPosition(auth, symbolOrAssetId) {
|
|
|
1565
1584
|
*/
|
|
1566
1585
|
async function closePosition$1(auth, symbolOrAssetId, params) {
|
|
1567
1586
|
try {
|
|
1568
|
-
const {
|
|
1587
|
+
const { apiKey, apiSecret, type } = await validateAuth(auth);
|
|
1569
1588
|
const apiBaseUrl = getTradingApiUrl(type);
|
|
1570
1589
|
const useLimitOrder = params?.useLimitOrder ?? false;
|
|
1571
1590
|
const cancelOrdersFlag = params?.cancelOrders ?? true;
|
|
@@ -1648,8 +1667,8 @@ async function closePosition$1(auth, symbolOrAssetId, params) {
|
|
|
1648
1667
|
const response = await fetch(url, {
|
|
1649
1668
|
method: "DELETE",
|
|
1650
1669
|
headers: {
|
|
1651
|
-
"APCA-API-KEY-ID":
|
|
1652
|
-
"APCA-API-SECRET-KEY":
|
|
1670
|
+
"APCA-API-KEY-ID": apiKey,
|
|
1671
|
+
"APCA-API-SECRET-KEY": apiSecret,
|
|
1653
1672
|
},
|
|
1654
1673
|
});
|
|
1655
1674
|
if (!response.ok) {
|
|
@@ -1840,20 +1859,20 @@ async function closeAllPositionsAfterHours$1(auth, params = { cancel_orders: tru
|
|
|
1840
1859
|
* @param props - The properties for fetching account details
|
|
1841
1860
|
* @returns The account details
|
|
1842
1861
|
*/
|
|
1843
|
-
async function fetchAccountDetails({ accountId, client,
|
|
1844
|
-
let
|
|
1845
|
-
if (!
|
|
1862
|
+
async function fetchAccountDetails({ accountId, client, brokerageAccount, auth, }) {
|
|
1863
|
+
let brokerageAccountObj = brokerageAccount ? brokerageAccount : null;
|
|
1864
|
+
if (!brokerageAccountObj && auth) {
|
|
1846
1865
|
const validatedAuth = await validateAuth(auth);
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1866
|
+
brokerageAccountObj = {
|
|
1867
|
+
apiKey: validatedAuth.apiKey,
|
|
1868
|
+
apiSecret: validatedAuth.apiSecret,
|
|
1850
1869
|
type: validatedAuth.type,
|
|
1851
1870
|
};
|
|
1852
1871
|
}
|
|
1853
|
-
if (!
|
|
1872
|
+
if (!brokerageAccountObj) {
|
|
1854
1873
|
try {
|
|
1855
1874
|
const apolloClient = client || (await getSharedApolloClient());
|
|
1856
|
-
|
|
1875
|
+
brokerageAccountObj = (await adaptic$1.brokerageAccount.get({
|
|
1857
1876
|
id: accountId,
|
|
1858
1877
|
}, apolloClient));
|
|
1859
1878
|
}
|
|
@@ -1862,19 +1881,19 @@ async function fetchAccountDetails({ accountId, client, alpacaAccount, auth, })
|
|
|
1862
1881
|
throw error;
|
|
1863
1882
|
}
|
|
1864
1883
|
}
|
|
1865
|
-
if (!
|
|
1866
|
-
!
|
|
1867
|
-
!
|
|
1884
|
+
if (!brokerageAccountObj ||
|
|
1885
|
+
!brokerageAccountObj.apiKey ||
|
|
1886
|
+
!brokerageAccountObj.apiSecret) {
|
|
1868
1887
|
throw new Error("[fetchAccountDetails] Alpaca account not found or incomplete");
|
|
1869
1888
|
}
|
|
1870
|
-
const {
|
|
1889
|
+
const { apiKey, apiSecret, type } = brokerageAccountObj;
|
|
1871
1890
|
const apiUrl = `${getTradingApiUrl(type)}/account`;
|
|
1872
1891
|
try {
|
|
1873
1892
|
const response = await fetch(apiUrl, {
|
|
1874
1893
|
method: "GET",
|
|
1875
1894
|
headers: {
|
|
1876
|
-
"APCA-API-KEY-ID":
|
|
1877
|
-
"APCA-API-SECRET-KEY":
|
|
1895
|
+
"APCA-API-KEY-ID": apiKey,
|
|
1896
|
+
"APCA-API-SECRET-KEY": apiSecret,
|
|
1878
1897
|
"Content-Type": "application/json",
|
|
1879
1898
|
},
|
|
1880
1899
|
signal: createTimeoutSignal(DEFAULT_TIMEOUTS.ALPACA_API),
|
|
@@ -1895,12 +1914,12 @@ async function fetchAccountDetails({ accountId, client, alpacaAccount, auth, })
|
|
|
1895
1914
|
* @param props - The properties for fetching portfolio history
|
|
1896
1915
|
* @returns The portfolio history
|
|
1897
1916
|
*/
|
|
1898
|
-
async function fetchPortfolioHistory({ params, accountId, client,
|
|
1899
|
-
let
|
|
1900
|
-
if (!
|
|
1917
|
+
async function fetchPortfolioHistory({ params, accountId, client, brokerageAccount, }) {
|
|
1918
|
+
let brokerageAccountObj = brokerageAccount ? brokerageAccount : null;
|
|
1919
|
+
if (!brokerageAccountObj) {
|
|
1901
1920
|
try {
|
|
1902
1921
|
const apolloClient = client || (await getSharedApolloClient());
|
|
1903
|
-
|
|
1922
|
+
brokerageAccountObj = (await adaptic$1.brokerageAccount.get({
|
|
1904
1923
|
id: accountId,
|
|
1905
1924
|
}, apolloClient));
|
|
1906
1925
|
}
|
|
@@ -1909,12 +1928,12 @@ async function fetchPortfolioHistory({ params, accountId, client, alpacaAccount,
|
|
|
1909
1928
|
throw error;
|
|
1910
1929
|
}
|
|
1911
1930
|
}
|
|
1912
|
-
if (!
|
|
1913
|
-
!
|
|
1914
|
-
!
|
|
1931
|
+
if (!brokerageAccountObj ||
|
|
1932
|
+
!brokerageAccountObj.apiKey ||
|
|
1933
|
+
!brokerageAccountObj.apiSecret) {
|
|
1915
1934
|
throw new Error("[fetchPortfolioHistory] Alpaca account not found or incomplete");
|
|
1916
1935
|
}
|
|
1917
|
-
const {
|
|
1936
|
+
const { apiKey, apiSecret, type } = brokerageAccountObj;
|
|
1918
1937
|
const apiBaseUrl = getTradingApiUrl(type);
|
|
1919
1938
|
const apiUrl = `${apiBaseUrl}/v2/account/portfolio/history`;
|
|
1920
1939
|
const { start, end, period } = params;
|
|
@@ -1940,8 +1959,8 @@ async function fetchPortfolioHistory({ params, accountId, client, alpacaAccount,
|
|
|
1940
1959
|
const response = await fetch(fullUrl, {
|
|
1941
1960
|
method: "GET",
|
|
1942
1961
|
headers: {
|
|
1943
|
-
"APCA-API-KEY-ID":
|
|
1944
|
-
"APCA-API-SECRET-KEY":
|
|
1962
|
+
"APCA-API-KEY-ID": apiKey,
|
|
1963
|
+
"APCA-API-SECRET-KEY": apiSecret,
|
|
1945
1964
|
"Content-Type": "application/json",
|
|
1946
1965
|
},
|
|
1947
1966
|
signal: createTimeoutSignal(DEFAULT_TIMEOUTS.ALPACA_API),
|
|
@@ -1968,31 +1987,31 @@ async function getConfiguration(account) {
|
|
|
1968
1987
|
if (!account) {
|
|
1969
1988
|
throw new Error(`Account is missing.`);
|
|
1970
1989
|
}
|
|
1971
|
-
const {
|
|
1972
|
-
if (!
|
|
1973
|
-
throw new Error("
|
|
1990
|
+
const { apiKey, apiSecret } = account;
|
|
1991
|
+
if (!apiKey || !apiSecret) {
|
|
1992
|
+
throw new Error("Account apiKey or apiSecret is missing.");
|
|
1974
1993
|
}
|
|
1975
1994
|
const apiUrl = getTradingApiUrl(account.type);
|
|
1976
1995
|
const client = await getSharedApolloClient();
|
|
1977
|
-
const [alpacaResponse,
|
|
1996
|
+
const [alpacaResponse, freshBrokerageAccount] = await Promise.all([
|
|
1978
1997
|
fetch(`${apiUrl}/account/configurations`, {
|
|
1979
1998
|
method: "GET",
|
|
1980
1999
|
headers: {
|
|
1981
|
-
"APCA-API-KEY-ID":
|
|
1982
|
-
"APCA-API-SECRET-KEY":
|
|
2000
|
+
"APCA-API-KEY-ID": apiKey,
|
|
2001
|
+
"APCA-API-SECRET-KEY": apiSecret,
|
|
1983
2002
|
accept: "application/json",
|
|
1984
2003
|
},
|
|
1985
2004
|
}),
|
|
1986
|
-
adaptic$1.
|
|
2005
|
+
adaptic$1.brokerageAccount.get({ id: account.id }, client),
|
|
1987
2006
|
]);
|
|
1988
2007
|
if (!alpacaResponse.ok) {
|
|
1989
2008
|
throw new Error(`Failed to fetch account configuration: ${alpacaResponse.statusText}`);
|
|
1990
2009
|
}
|
|
1991
|
-
if (!
|
|
2010
|
+
if (!freshBrokerageAccount) {
|
|
1992
2011
|
throw new Error("Failed to get Alpaca Account from @adaptic/backend-legacy.");
|
|
1993
2012
|
}
|
|
1994
2013
|
const dataFromAlpaca = (await alpacaResponse.json());
|
|
1995
|
-
const accountWithAllocation =
|
|
2014
|
+
const accountWithAllocation = freshBrokerageAccount;
|
|
1996
2015
|
const allocationData = accountWithAllocation.allocation || {
|
|
1997
2016
|
stocks: 70,
|
|
1998
2017
|
options: 0,
|
|
@@ -2003,26 +2022,26 @@ async function getConfiguration(account) {
|
|
|
2003
2022
|
};
|
|
2004
2023
|
const combinedConfig = {
|
|
2005
2024
|
...dataFromAlpaca,
|
|
2006
|
-
marketOpen:
|
|
2007
|
-
realTime:
|
|
2008
|
-
tradeAllocationPct:
|
|
2009
|
-
minPercentageChange:
|
|
2010
|
-
volumeThreshold:
|
|
2011
|
-
cryptoTradingEnabled:
|
|
2012
|
-
cryptoTradingPairs:
|
|
2013
|
-
cryptoTradeAllocationPct:
|
|
2025
|
+
marketOpen: freshBrokerageAccount.marketOpen,
|
|
2026
|
+
realTime: freshBrokerageAccount.realTime,
|
|
2027
|
+
tradeAllocationPct: freshBrokerageAccount.tradeAllocationPct,
|
|
2028
|
+
minPercentageChange: freshBrokerageAccount.minPercentageChange,
|
|
2029
|
+
volumeThreshold: freshBrokerageAccount.volumeThreshold,
|
|
2030
|
+
cryptoTradingEnabled: freshBrokerageAccount.cryptoTradingEnabled ?? false,
|
|
2031
|
+
cryptoTradingPairs: freshBrokerageAccount.cryptoTradingPairs ?? [],
|
|
2032
|
+
cryptoTradeAllocationPct: freshBrokerageAccount.cryptoTradeAllocationPct ?? 5.0,
|
|
2014
2033
|
autoAllocation: accountWithAllocation.autoAllocation ?? false,
|
|
2015
2034
|
allocation: allocationData,
|
|
2016
|
-
enablePortfolioTrailingStop:
|
|
2017
|
-
portfolioTrailPercent:
|
|
2018
|
-
portfolioProfitThresholdPercent:
|
|
2019
|
-
reducedPortfolioTrailPercent:
|
|
2020
|
-
defaultTrailingStopPercentage100:
|
|
2021
|
-
firstTrailReductionThreshold100:
|
|
2022
|
-
secondTrailReductionThreshold100:
|
|
2023
|
-
firstReducedTrailPercentage100:
|
|
2024
|
-
secondReducedTrailPercentage100:
|
|
2025
|
-
minimumPriceChangePercent100:
|
|
2035
|
+
enablePortfolioTrailingStop: freshBrokerageAccount.enablePortfolioTrailingStop,
|
|
2036
|
+
portfolioTrailPercent: freshBrokerageAccount.portfolioTrailPercent,
|
|
2037
|
+
portfolioProfitThresholdPercent: freshBrokerageAccount.portfolioProfitThresholdPercent,
|
|
2038
|
+
reducedPortfolioTrailPercent: freshBrokerageAccount.reducedPortfolioTrailPercent,
|
|
2039
|
+
defaultTrailingStopPercentage100: freshBrokerageAccount.defaultTrailingStopPercentage100 ?? 4.0,
|
|
2040
|
+
firstTrailReductionThreshold100: freshBrokerageAccount.firstTrailReductionThreshold100 ?? 2.0,
|
|
2041
|
+
secondTrailReductionThreshold100: freshBrokerageAccount.secondTrailReductionThreshold100 ?? 5.0,
|
|
2042
|
+
firstReducedTrailPercentage100: freshBrokerageAccount.firstReducedTrailPercentage100 ?? 1.0,
|
|
2043
|
+
secondReducedTrailPercentage100: freshBrokerageAccount.secondReducedTrailPercentage100 ?? 0.5,
|
|
2044
|
+
minimumPriceChangePercent100: freshBrokerageAccount.minimumPriceChangePercent100 ?? 0.5,
|
|
2026
2045
|
};
|
|
2027
2046
|
return combinedConfig;
|
|
2028
2047
|
}
|
|
@@ -2043,9 +2062,9 @@ async function updateConfiguration(user, account, updatedConfig) {
|
|
|
2043
2062
|
if (!account) {
|
|
2044
2063
|
throw new Error(`Account is missing.`);
|
|
2045
2064
|
}
|
|
2046
|
-
const {
|
|
2047
|
-
if (!
|
|
2048
|
-
throw new Error("
|
|
2065
|
+
const { apiKey, apiSecret } = account;
|
|
2066
|
+
if (!apiKey || !apiSecret) {
|
|
2067
|
+
throw new Error("Account apiKey or apiSecret is missing.");
|
|
2049
2068
|
}
|
|
2050
2069
|
const apiUrl = getTradingApiUrl(account.type);
|
|
2051
2070
|
// Prepare the config object for Alpaca by removing DB-only fields
|
|
@@ -2073,8 +2092,8 @@ async function updateConfiguration(user, account, updatedConfig) {
|
|
|
2073
2092
|
const alpacaUpdatePromise = fetch(`${apiUrl}/account/configurations`, {
|
|
2074
2093
|
method: "PATCH",
|
|
2075
2094
|
headers: {
|
|
2076
|
-
"APCA-API-KEY-ID":
|
|
2077
|
-
"APCA-API-SECRET-KEY":
|
|
2095
|
+
"APCA-API-KEY-ID": apiKey,
|
|
2096
|
+
"APCA-API-SECRET-KEY": apiSecret,
|
|
2078
2097
|
"Content-Type": "application/json",
|
|
2079
2098
|
accept: "application/json",
|
|
2080
2099
|
},
|
|
@@ -2095,10 +2114,10 @@ async function updateConfiguration(user, account, updatedConfig) {
|
|
|
2095
2114
|
if (account.allocation) {
|
|
2096
2115
|
allocUpdatePromise = adaptic$1.allocation.update({
|
|
2097
2116
|
id: account.allocation.id,
|
|
2098
|
-
|
|
2117
|
+
brokerageAccount: {
|
|
2099
2118
|
id: account.id,
|
|
2100
2119
|
},
|
|
2101
|
-
|
|
2120
|
+
brokerageAccountId: account.id,
|
|
2102
2121
|
stocks: updatedConfig.allocation.stocks ?? 0,
|
|
2103
2122
|
options: updatedConfig.allocation.options ?? 0,
|
|
2104
2123
|
futures: updatedConfig.allocation.futures ?? 0,
|
|
@@ -2115,14 +2134,14 @@ async function updateConfiguration(user, account, updatedConfig) {
|
|
|
2115
2134
|
etfs: updatedConfig.allocation.etfs ?? 0,
|
|
2116
2135
|
forex: updatedConfig.allocation.forex ?? 0,
|
|
2117
2136
|
crypto: updatedConfig.allocation.crypto ?? 0,
|
|
2118
|
-
|
|
2137
|
+
brokerageAccount: {
|
|
2119
2138
|
id: account.id,
|
|
2120
2139
|
},
|
|
2121
|
-
|
|
2140
|
+
brokerageAccountId: account.id,
|
|
2122
2141
|
}, client);
|
|
2123
2142
|
}
|
|
2124
2143
|
}
|
|
2125
|
-
const adapticUpdatePromise = adaptic$1.
|
|
2144
|
+
const adapticUpdatePromise = adaptic$1.brokerageAccount.update({
|
|
2126
2145
|
id: account.id,
|
|
2127
2146
|
user: {
|
|
2128
2147
|
id: user.id,
|
|
@@ -2149,7 +2168,7 @@ async function updateConfiguration(user, account, updatedConfig) {
|
|
|
2149
2168
|
secondReducedTrailPercentage100: updatedConfig.secondReducedTrailPercentage100 ?? 0,
|
|
2150
2169
|
minimumPriceChangePercent100: updatedConfig.minimumPriceChangePercent100 ?? 0,
|
|
2151
2170
|
}, client);
|
|
2152
|
-
const [alpacaResponse,
|
|
2171
|
+
const [alpacaResponse, updatedBrokerageAccount, updatedAllocation] = await Promise.all([
|
|
2153
2172
|
alpacaUpdatePromise,
|
|
2154
2173
|
adapticUpdatePromise,
|
|
2155
2174
|
allocUpdatePromise,
|
|
@@ -2169,10 +2188,10 @@ async function updateConfiguration(user, account, updatedConfig) {
|
|
|
2169
2188
|
throw new Error(`Failed to update account config at Alpaca: ${alpacaResponse.statusText}`);
|
|
2170
2189
|
}
|
|
2171
2190
|
const alpacaData = (await alpacaResponse.json());
|
|
2172
|
-
if (!
|
|
2191
|
+
if (!updatedBrokerageAccount) {
|
|
2173
2192
|
throw new Error("Failed to update Alpaca Account in @adaptic/backend-legacy.");
|
|
2174
2193
|
}
|
|
2175
|
-
const updatedAccountWithAllocation =
|
|
2194
|
+
const updatedAccountWithAllocation = updatedBrokerageAccount;
|
|
2176
2195
|
const selectedAllocation = (updatedConfig.allocation ||
|
|
2177
2196
|
updatedAllocation ||
|
|
2178
2197
|
updatedAccountWithAllocation.allocation);
|
|
@@ -2182,26 +2201,26 @@ async function updateConfiguration(user, account, updatedConfig) {
|
|
|
2182
2201
|
getLogger().info("Final allocation:", selectedAllocation);
|
|
2183
2202
|
const finalConfig = {
|
|
2184
2203
|
...alpacaData,
|
|
2185
|
-
marketOpen:
|
|
2186
|
-
realTime:
|
|
2187
|
-
tradeAllocationPct:
|
|
2188
|
-
minPercentageChange:
|
|
2189
|
-
volumeThreshold:
|
|
2190
|
-
cryptoTradingEnabled:
|
|
2191
|
-
cryptoTradingPairs:
|
|
2192
|
-
cryptoTradeAllocationPct:
|
|
2204
|
+
marketOpen: updatedBrokerageAccount.marketOpen,
|
|
2205
|
+
realTime: updatedBrokerageAccount.realTime,
|
|
2206
|
+
tradeAllocationPct: updatedBrokerageAccount.tradeAllocationPct,
|
|
2207
|
+
minPercentageChange: updatedBrokerageAccount.minPercentageChange,
|
|
2208
|
+
volumeThreshold: updatedBrokerageAccount.volumeThreshold,
|
|
2209
|
+
cryptoTradingEnabled: updatedBrokerageAccount.cryptoTradingEnabled,
|
|
2210
|
+
cryptoTradingPairs: updatedBrokerageAccount.cryptoTradingPairs,
|
|
2211
|
+
cryptoTradeAllocationPct: updatedBrokerageAccount.cryptoTradeAllocationPct,
|
|
2193
2212
|
autoAllocation: updatedAccountWithAllocation.autoAllocation,
|
|
2194
2213
|
allocation: selectedAllocation,
|
|
2195
|
-
enablePortfolioTrailingStop:
|
|
2196
|
-
portfolioTrailPercent:
|
|
2197
|
-
portfolioProfitThresholdPercent:
|
|
2198
|
-
reducedPortfolioTrailPercent:
|
|
2199
|
-
defaultTrailingStopPercentage100:
|
|
2200
|
-
firstTrailReductionThreshold100:
|
|
2201
|
-
secondTrailReductionThreshold100:
|
|
2202
|
-
firstReducedTrailPercentage100:
|
|
2203
|
-
secondReducedTrailPercentage100:
|
|
2204
|
-
minimumPriceChangePercent100:
|
|
2214
|
+
enablePortfolioTrailingStop: updatedBrokerageAccount.enablePortfolioTrailingStop,
|
|
2215
|
+
portfolioTrailPercent: updatedBrokerageAccount.portfolioTrailPercent,
|
|
2216
|
+
portfolioProfitThresholdPercent: updatedBrokerageAccount.portfolioProfitThresholdPercent,
|
|
2217
|
+
reducedPortfolioTrailPercent: updatedBrokerageAccount.reducedPortfolioTrailPercent,
|
|
2218
|
+
defaultTrailingStopPercentage100: updatedBrokerageAccount.defaultTrailingStopPercentage100,
|
|
2219
|
+
firstTrailReductionThreshold100: updatedBrokerageAccount.firstTrailReductionThreshold100,
|
|
2220
|
+
secondTrailReductionThreshold100: updatedBrokerageAccount.secondTrailReductionThreshold100,
|
|
2221
|
+
firstReducedTrailPercentage100: updatedBrokerageAccount.firstReducedTrailPercentage100,
|
|
2222
|
+
secondReducedTrailPercentage100: updatedBrokerageAccount.secondReducedTrailPercentage100,
|
|
2223
|
+
minimumPriceChangePercent100: updatedBrokerageAccount.minimumPriceChangePercent100,
|
|
2205
2224
|
};
|
|
2206
2225
|
return finalConfig;
|
|
2207
2226
|
}
|
|
@@ -2219,15 +2238,15 @@ async function updateConfiguration(user, account, updatedConfig) {
|
|
|
2219
2238
|
*/
|
|
2220
2239
|
async function getAsset(auth, symbolOrAssetId) {
|
|
2221
2240
|
try {
|
|
2222
|
-
const {
|
|
2241
|
+
const { apiKey, apiSecret, type } = await validateAuth(auth);
|
|
2223
2242
|
const apiBaseUrl = getTradingApiUrl(type);
|
|
2224
2243
|
// Use encodeURIComponent to handle special characters in symbols (e.g., BTC/USDT)
|
|
2225
2244
|
const encodedSymbolOrAssetId = encodeURIComponent(symbolOrAssetId);
|
|
2226
2245
|
const response = await fetch(`${apiBaseUrl}/v2/assets/${encodedSymbolOrAssetId}`, {
|
|
2227
2246
|
method: "GET",
|
|
2228
2247
|
headers: {
|
|
2229
|
-
"APCA-API-KEY-ID":
|
|
2230
|
-
"APCA-API-SECRET-KEY":
|
|
2248
|
+
"APCA-API-KEY-ID": apiKey,
|
|
2249
|
+
"APCA-API-SECRET-KEY": apiSecret,
|
|
2231
2250
|
"Content-Type": "application/json",
|
|
2232
2251
|
},
|
|
2233
2252
|
signal: createTimeoutSignal(DEFAULT_TIMEOUTS.ALPACA_API),
|
|
@@ -3284,24 +3303,24 @@ async function calculateTotalReturnYTD(portfolioHistory) {
|
|
|
3284
3303
|
* Calculates the expense ratio for a given Alpaca account.
|
|
3285
3304
|
* @param accountId - The ID of the Alpaca account.
|
|
3286
3305
|
* @param client - The Apollo client instance.
|
|
3287
|
-
* @param
|
|
3306
|
+
* @param brokerageAccount - The Alpaca account object.
|
|
3288
3307
|
* @returns A promise that resolves to a string representing the expense ratio in percentage format.
|
|
3289
3308
|
*/
|
|
3290
|
-
async function calculateExpenseRatio$1({ accountId, client,
|
|
3291
|
-
if (!accountId && !
|
|
3309
|
+
async function calculateExpenseRatio$1({ accountId, client, brokerageAccount, }) {
|
|
3310
|
+
if (!accountId && !brokerageAccount && !client) {
|
|
3292
3311
|
getLogger().warn("Missing account ID or client to calculate expense ratio.");
|
|
3293
3312
|
return "N/A";
|
|
3294
3313
|
}
|
|
3295
|
-
let
|
|
3314
|
+
let brokerageAccountId = accountId || (brokerageAccount && brokerageAccount.id) || "";
|
|
3296
3315
|
let accountDetails;
|
|
3297
|
-
if (!
|
|
3316
|
+
if (!brokerageAccountId) {
|
|
3298
3317
|
getLogger().warn("Invalid account ID.");
|
|
3299
3318
|
return "N/A";
|
|
3300
3319
|
}
|
|
3301
|
-
if (
|
|
3320
|
+
if (brokerageAccount) {
|
|
3302
3321
|
// Use Alpaca account object to get accountDetails
|
|
3303
3322
|
accountDetails = (await fetchAccountDetails({
|
|
3304
|
-
|
|
3323
|
+
brokerageAccount: brokerageAccount,
|
|
3305
3324
|
}));
|
|
3306
3325
|
if (!accountDetails) {
|
|
3307
3326
|
getLogger().warn("Failed to fetch account details inside calculateExpenseRatio.");
|
|
@@ -3340,24 +3359,24 @@ async function getPortfolioExpensesFromYourSystem(accountId) {
|
|
|
3340
3359
|
* Calculates the liquidity ratio for a given Alpaca account.
|
|
3341
3360
|
* @param accountId - The ID of the Alpaca account.
|
|
3342
3361
|
* @param client - The Apollo client instance.
|
|
3343
|
-
* @param
|
|
3362
|
+
* @param brokerageAccount - The Alpaca account object.
|
|
3344
3363
|
* @returns A promise that resolves to a string representing the liquidity ratio in the format "1:ratio".
|
|
3345
3364
|
*/
|
|
3346
|
-
async function calculateLiquidityRatio({ accountId, client,
|
|
3347
|
-
if (!accountId && !
|
|
3365
|
+
async function calculateLiquidityRatio({ accountId, client, brokerageAccount, }) {
|
|
3366
|
+
if (!accountId && !brokerageAccount && !client) {
|
|
3348
3367
|
getLogger().warn("Missing account ID or client to calculateLiquidityRatio.");
|
|
3349
3368
|
return "N/A";
|
|
3350
3369
|
}
|
|
3351
|
-
let
|
|
3370
|
+
let brokerageAccountId = accountId || (brokerageAccount && brokerageAccount.id) || "";
|
|
3352
3371
|
let accountDetails;
|
|
3353
|
-
if (!
|
|
3372
|
+
if (!brokerageAccountId) {
|
|
3354
3373
|
getLogger().warn("Invalid account ID.");
|
|
3355
3374
|
return "N/A";
|
|
3356
3375
|
}
|
|
3357
|
-
if (
|
|
3376
|
+
if (brokerageAccount) {
|
|
3358
3377
|
// Use Alpaca account object to get accountDetails
|
|
3359
3378
|
accountDetails = (await fetchAccountDetails({
|
|
3360
|
-
|
|
3379
|
+
brokerageAccount: brokerageAccount,
|
|
3361
3380
|
}));
|
|
3362
3381
|
if (!accountDetails) {
|
|
3363
3382
|
getLogger().warn("Failed to fetch account details inside calculateLiquidityRatio.");
|
|
@@ -3985,11 +4004,11 @@ async function calculateInformationRatio$1(portfolioHistory, benchmarkBars) {
|
|
|
3985
4004
|
* @param params - The parameters for fetching performance metrics.
|
|
3986
4005
|
* @param client - The Apollo client instance.
|
|
3987
4006
|
* @param accountId - The ID of the Alpaca account.
|
|
3988
|
-
* @param
|
|
4007
|
+
* @param brokerageAccount - The Alpaca account object.
|
|
3989
4008
|
* @returns A promise that resolves to an object containing various performance metrics.
|
|
3990
4009
|
* @throws Will throw an error if required parameters are missing or if fetching fails.
|
|
3991
4010
|
*/
|
|
3992
|
-
async function fetchPerformanceMetrics({ params, client, accountId,
|
|
4011
|
+
async function fetchPerformanceMetrics({ params, client, accountId, brokerageAccount, }) {
|
|
3993
4012
|
// Default response for error cases
|
|
3994
4013
|
const defaultMetrics = {
|
|
3995
4014
|
totalReturnYTD: "N/A",
|
|
@@ -4012,12 +4031,12 @@ async function fetchPerformanceMetrics({ params, client, accountId, alpacaAccoun
|
|
|
4012
4031
|
throw new Error("Missing required timeframe or period parameters");
|
|
4013
4032
|
}
|
|
4014
4033
|
// Obtain Alpaca account
|
|
4015
|
-
let
|
|
4016
|
-
if (!
|
|
4034
|
+
let brokerageAccountObj = brokerageAccount ? brokerageAccount : null;
|
|
4035
|
+
if (!brokerageAccountObj && accountId) {
|
|
4017
4036
|
try {
|
|
4018
4037
|
// Use provided client or get the shared client
|
|
4019
4038
|
const apolloClient = client || (await getSharedApolloClient());
|
|
4020
|
-
|
|
4039
|
+
brokerageAccountObj = (await adaptic$1.brokerageAccount.get({
|
|
4021
4040
|
id: accountId,
|
|
4022
4041
|
}, apolloClient));
|
|
4023
4042
|
}
|
|
@@ -4027,9 +4046,9 @@ async function fetchPerformanceMetrics({ params, client, accountId, alpacaAccoun
|
|
|
4027
4046
|
}
|
|
4028
4047
|
}
|
|
4029
4048
|
// Validate Alpaca account
|
|
4030
|
-
if (!
|
|
4031
|
-
!
|
|
4032
|
-
!
|
|
4049
|
+
if (!brokerageAccountObj ||
|
|
4050
|
+
!brokerageAccountObj.apiKey ||
|
|
4051
|
+
!brokerageAccountObj.apiSecret) {
|
|
4033
4052
|
throw new Error("Alpaca account not found or credentials missing");
|
|
4034
4053
|
}
|
|
4035
4054
|
// Fetch portfolio history with structured error handling
|
|
@@ -4037,7 +4056,7 @@ async function fetchPerformanceMetrics({ params, client, accountId, alpacaAccoun
|
|
|
4037
4056
|
try {
|
|
4038
4057
|
portfolioHistory = await fetchPortfolioHistory({
|
|
4039
4058
|
params: params,
|
|
4040
|
-
|
|
4059
|
+
brokerageAccount: brokerageAccountObj,
|
|
4041
4060
|
});
|
|
4042
4061
|
}
|
|
4043
4062
|
catch (error) {
|
|
@@ -4087,10 +4106,10 @@ async function fetchPerformanceMetrics({ params, client, accountId, alpacaAccoun
|
|
|
4087
4106
|
calculateInformationRatio$1(portfolioHistory, benchmarkBars),
|
|
4088
4107
|
calculateRiskAdjustedReturn$1(portfolioHistory),
|
|
4089
4108
|
calculateLiquidityRatio({
|
|
4090
|
-
|
|
4109
|
+
brokerageAccount: brokerageAccountObj,
|
|
4091
4110
|
}),
|
|
4092
4111
|
calculateExpenseRatio$1({
|
|
4093
|
-
|
|
4112
|
+
brokerageAccount: brokerageAccountObj,
|
|
4094
4113
|
}),
|
|
4095
4114
|
getDividendYield(),
|
|
4096
4115
|
calculateMaxDrawdown$1(portfolioHistory.equity),
|
|
@@ -4310,15 +4329,15 @@ const timeDiffString = (milliseconds) => {
|
|
|
4310
4329
|
};
|
|
4311
4330
|
|
|
4312
4331
|
// price-utils.ts
|
|
4313
|
-
const calculateFees = async (action, trade,
|
|
4332
|
+
const calculateFees = async (action, trade, brokerageAccount) => {
|
|
4314
4333
|
let fee = 0;
|
|
4315
4334
|
const alpacaOrderId = action.alpacaOrderId;
|
|
4316
4335
|
if (!alpacaOrderId)
|
|
4317
4336
|
return fee;
|
|
4318
4337
|
const order = await getOrder$1({
|
|
4319
|
-
adapticAccountId: trade.
|
|
4320
|
-
alpacaApiKey:
|
|
4321
|
-
alpacaApiSecret:
|
|
4338
|
+
adapticAccountId: trade.brokerageAccountId,
|
|
4339
|
+
alpacaApiKey: brokerageAccount.apiKey,
|
|
4340
|
+
alpacaApiSecret: brokerageAccount.apiSecret,
|
|
4322
4341
|
}, alpacaOrderId);
|
|
4323
4342
|
if (!order)
|
|
4324
4343
|
return fee;
|
|
@@ -4356,13 +4375,13 @@ const calculateFees = async (action, trade, alpacaAccount) => {
|
|
|
4356
4375
|
};
|
|
4357
4376
|
const computeTotalFees = async (trade) => {
|
|
4358
4377
|
let totalFees = 0;
|
|
4359
|
-
// fetch alpaca account details using adaptic.
|
|
4360
|
-
const
|
|
4361
|
-
id: trade.
|
|
4378
|
+
// fetch alpaca account details using adaptic.brokerageAccount.get({id: trade.brokerageAccountId})
|
|
4379
|
+
const brokerageAccount = (await adaptic$1.brokerageAccount.get({
|
|
4380
|
+
id: trade.brokerageAccountId,
|
|
4362
4381
|
}));
|
|
4363
|
-
if (!
|
|
4382
|
+
if (!brokerageAccount)
|
|
4364
4383
|
return totalFees;
|
|
4365
|
-
const feePromises = trade?.actions?.map((action) => calculateFees(action, trade,
|
|
4384
|
+
const feePromises = trade?.actions?.map((action) => calculateFees(action, trade, brokerageAccount));
|
|
4366
4385
|
const fees = await Promise.all(feePromises || []);
|
|
4367
4386
|
totalFees = fees.reduce((acc, fee) => acc + fee, 0);
|
|
4368
4387
|
return totalFees;
|
|
@@ -6109,7 +6128,7 @@ async function fetchBars(params) {
|
|
|
6109
6128
|
*/
|
|
6110
6129
|
async function fetchNews(params, auth) {
|
|
6111
6130
|
const { symbol, start = new Date(Date.now() - 24 * 60 * 60 * 1000), sort = "desc", includeContent = false, limit = 1000, } = params;
|
|
6112
|
-
if (!auth.
|
|
6131
|
+
if (!auth.alpacaApiKey || !auth.alpacaApiSecret) {
|
|
6113
6132
|
throw new Error("Alpaca API key and secret are required");
|
|
6114
6133
|
}
|
|
6115
6134
|
if (!symbol) {
|
|
@@ -6177,7 +6196,7 @@ async function fetchNews(params, auth) {
|
|
|
6177
6196
|
*/
|
|
6178
6197
|
async function fetchLatestTrades(params, auth) {
|
|
6179
6198
|
const { symbols, loc = "us" } = params;
|
|
6180
|
-
if (!auth.
|
|
6199
|
+
if (!auth.alpacaApiKey || !auth.alpacaApiSecret) {
|
|
6181
6200
|
throw new Error("Alpaca API key and secret are required");
|
|
6182
6201
|
}
|
|
6183
6202
|
if (!symbols || symbols.length === 0) {
|
|
@@ -6193,8 +6212,8 @@ async function fetchLatestTrades(params, auth) {
|
|
|
6193
6212
|
return withRetry(async () => {
|
|
6194
6213
|
const response = await fetch(url, {
|
|
6195
6214
|
headers: {
|
|
6196
|
-
"APCA-API-KEY-ID": auth.
|
|
6197
|
-
"APCA-API-SECRET-KEY": auth.
|
|
6215
|
+
"APCA-API-KEY-ID": auth.alpacaApiKey,
|
|
6216
|
+
"APCA-API-SECRET-KEY": auth.alpacaApiSecret,
|
|
6198
6217
|
},
|
|
6199
6218
|
signal: createTimeoutSignal(DEFAULT_TIMEOUTS.ALPACA_API),
|
|
6200
6219
|
});
|
|
@@ -6220,7 +6239,7 @@ async function fetchLatestTrades(params, auth) {
|
|
|
6220
6239
|
*/
|
|
6221
6240
|
async function fetchLatestQuotes(params, auth) {
|
|
6222
6241
|
const { symbols, loc = "us" } = params;
|
|
6223
|
-
if (!auth.
|
|
6242
|
+
if (!auth.alpacaApiKey || !auth.alpacaApiSecret) {
|
|
6224
6243
|
throw new Error("Alpaca API key and secret are required");
|
|
6225
6244
|
}
|
|
6226
6245
|
if (!symbols || symbols.length === 0) {
|
|
@@ -6236,8 +6255,8 @@ async function fetchLatestQuotes(params, auth) {
|
|
|
6236
6255
|
return withRetry(async () => {
|
|
6237
6256
|
const response = await fetch(url, {
|
|
6238
6257
|
headers: {
|
|
6239
|
-
"APCA-API-KEY-ID": auth.
|
|
6240
|
-
"APCA-API-SECRET-KEY": auth.
|
|
6258
|
+
"APCA-API-KEY-ID": auth.alpacaApiKey,
|
|
6259
|
+
"APCA-API-SECRET-KEY": auth.alpacaApiSecret,
|
|
6241
6260
|
},
|
|
6242
6261
|
signal: createTimeoutSignal(DEFAULT_TIMEOUTS.ALPACA_API),
|
|
6243
6262
|
});
|
|
@@ -12283,6 +12302,8 @@ class AlpacaMarketDataAPI extends require$$0$4.EventEmitter {
|
|
|
12283
12302
|
dataURL;
|
|
12284
12303
|
apiURL;
|
|
12285
12304
|
v1beta1url;
|
|
12305
|
+
/** Whether API credentials are valid and available. False during build time when env vars are missing. */
|
|
12306
|
+
credentialsValid = false;
|
|
12286
12307
|
stockStreamUrl = getStockStreamUrl("PRODUCTION"); // production values
|
|
12287
12308
|
optionStreamUrl = getOptionsStreamUrl("PRODUCTION"); // production values
|
|
12288
12309
|
cryptoStreamUrl = getCryptoStreamUrl("PRODUCTION"); // production values
|
|
@@ -12338,13 +12359,16 @@ class AlpacaMarketDataAPI extends require$$0$4.EventEmitter {
|
|
|
12338
12359
|
constructor() {
|
|
12339
12360
|
super();
|
|
12340
12361
|
// Validate credentials from environment variables before initializing
|
|
12341
|
-
|
|
12342
|
-
|
|
12343
|
-
|
|
12362
|
+
// Use throwOnMissing: false to allow initialization during build time
|
|
12363
|
+
// when env vars are not available. Features will be unavailable until
|
|
12364
|
+
// credentials are provided at runtime.
|
|
12365
|
+
const apiKey = process.env.ALPACA_API_KEY || "";
|
|
12366
|
+
const apiSecret = process.env.ALPACA_SECRET_KEY || "";
|
|
12367
|
+
this.credentialsValid = validateAlpacaCredentials({
|
|
12344
12368
|
apiKey,
|
|
12345
12369
|
apiSecret,
|
|
12346
12370
|
isPaper: process.env.ALPACA_ACCOUNT_TYPE === "PAPER",
|
|
12347
|
-
});
|
|
12371
|
+
}, { throwOnMissing: false });
|
|
12348
12372
|
this.dataURL = MARKET_DATA_API.STOCKS;
|
|
12349
12373
|
this.apiURL =
|
|
12350
12374
|
process.env.ALPACA_ACCOUNT_TYPE === "PAPER"
|