@finatic/client 0.0.136 → 0.0.138
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/README.md +68 -64
- package/dist/index.d.ts +294 -75
- package/dist/index.js +1424 -321
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1424 -321
- package/dist/index.mjs.map +1 -1
- package/dist/types/core/client/ApiClient.d.ts +21 -13
- package/dist/types/core/client/FinaticConnect.d.ts +44 -7
- package/dist/types/core/portal/PortalUI.d.ts +0 -3
- package/dist/types/index.d.ts +1 -1
- package/dist/types/mocks/MockApiClient.d.ts +6 -9
- package/dist/types/mocks/MockDataProvider.d.ts +6 -9
- package/dist/types/themes/portalPresets.d.ts +1 -0
- package/dist/types/types/api/broker.d.ts +47 -0
- package/dist/types/types/connect.d.ts +2 -0
- package/dist/types/types/portal.d.ts +178 -49
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -650,23 +650,6 @@ class ApiClient {
|
|
|
650
650
|
},
|
|
651
651
|
});
|
|
652
652
|
}
|
|
653
|
-
async validatePortalSession(sessionId, signature) {
|
|
654
|
-
return this.request('/portal/validate', {
|
|
655
|
-
method: 'GET',
|
|
656
|
-
headers: {
|
|
657
|
-
'Content-Type': 'application/json',
|
|
658
|
-
'X-Session-ID': sessionId,
|
|
659
|
-
'X-Device-Info': JSON.stringify({
|
|
660
|
-
ip_address: this.deviceInfo?.ip_address || '',
|
|
661
|
-
user_agent: this.deviceInfo?.user_agent || '',
|
|
662
|
-
fingerprint: this.deviceInfo?.fingerprint || '',
|
|
663
|
-
}),
|
|
664
|
-
},
|
|
665
|
-
params: {
|
|
666
|
-
signature,
|
|
667
|
-
},
|
|
668
|
-
});
|
|
669
|
-
}
|
|
670
653
|
async completePortalSession(sessionId) {
|
|
671
654
|
return this.request(`/portal/${sessionId}/complete`, {
|
|
672
655
|
method: 'POST',
|
|
@@ -676,34 +659,14 @@ class ApiClient {
|
|
|
676
659
|
});
|
|
677
660
|
}
|
|
678
661
|
// Portfolio Management
|
|
679
|
-
async getHoldings() {
|
|
680
|
-
const accessToken = await this.getValidAccessToken();
|
|
681
|
-
return this.request('/portfolio/holdings', {
|
|
682
|
-
method: 'GET',
|
|
683
|
-
headers: {
|
|
684
|
-
'Authorization': `Bearer ${accessToken}`,
|
|
685
|
-
},
|
|
686
|
-
});
|
|
687
|
-
}
|
|
688
662
|
async getOrders() {
|
|
689
663
|
const accessToken = await this.getValidAccessToken();
|
|
690
|
-
return this.request('/data/orders', {
|
|
691
|
-
method: 'GET',
|
|
692
|
-
headers: {
|
|
693
|
-
'Authorization': `Bearer ${accessToken}`,
|
|
694
|
-
},
|
|
695
|
-
});
|
|
696
|
-
}
|
|
697
|
-
async getPortfolio() {
|
|
698
|
-
const accessToken = await this.getValidAccessToken();
|
|
699
|
-
const response = await this.request('/portfolio/', {
|
|
664
|
+
return this.request('/brokers/data/orders', {
|
|
700
665
|
method: 'GET',
|
|
701
666
|
headers: {
|
|
702
|
-
|
|
703
|
-
'Content-Type': 'application/json',
|
|
667
|
+
Authorization: `Bearer ${accessToken}`,
|
|
704
668
|
},
|
|
705
669
|
});
|
|
706
|
-
return response;
|
|
707
670
|
}
|
|
708
671
|
// Enhanced Trading Methods with Session Management
|
|
709
672
|
async placeBrokerOrder(params, extras = {}, connection_id) {
|
|
@@ -766,10 +729,7 @@ class ApiClient {
|
|
|
766
729
|
}
|
|
767
730
|
const accountNumber = this.tradingContext.accountNumber;
|
|
768
731
|
// Build query parameters as required by API documentation
|
|
769
|
-
const queryParams = {
|
|
770
|
-
broker: selectedBroker,
|
|
771
|
-
order_id: orderId,
|
|
772
|
-
};
|
|
732
|
+
const queryParams = {};
|
|
773
733
|
// Add optional parameters if available
|
|
774
734
|
if (accountNumber) {
|
|
775
735
|
queryParams.account_number = accountNumber.toString();
|
|
@@ -785,11 +745,11 @@ class ApiClient {
|
|
|
785
745
|
order: {
|
|
786
746
|
order_id: orderId,
|
|
787
747
|
account_number: accountNumber,
|
|
788
|
-
...extras
|
|
789
|
-
}
|
|
748
|
+
...extras,
|
|
749
|
+
},
|
|
790
750
|
};
|
|
791
751
|
}
|
|
792
|
-
return this.request(
|
|
752
|
+
return this.request(`/brokers/orders/${orderId}`, {
|
|
793
753
|
method: 'DELETE',
|
|
794
754
|
headers: {
|
|
795
755
|
'Content-Type': 'application/json',
|
|
@@ -1059,22 +1019,12 @@ class ApiClient {
|
|
|
1059
1019
|
return extras;
|
|
1060
1020
|
}
|
|
1061
1021
|
}
|
|
1062
|
-
async
|
|
1063
|
-
const accessToken = await this.getValidAccessToken();
|
|
1064
|
-
await this.request('/auth/token/revoke', {
|
|
1065
|
-
method: 'POST',
|
|
1066
|
-
headers: {
|
|
1067
|
-
'Authorization': `Bearer ${accessToken}`,
|
|
1068
|
-
},
|
|
1069
|
-
});
|
|
1070
|
-
this.clearTokens();
|
|
1071
|
-
}
|
|
1072
|
-
async getUserToken(userId) {
|
|
1022
|
+
async getUserToken(sessionId) {
|
|
1073
1023
|
const accessToken = await this.getValidAccessToken();
|
|
1074
|
-
return this.request(`/auth/
|
|
1024
|
+
return this.request(`/auth/session/${sessionId}/user`, {
|
|
1075
1025
|
method: 'GET',
|
|
1076
1026
|
headers: {
|
|
1077
|
-
|
|
1027
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1078
1028
|
},
|
|
1079
1029
|
});
|
|
1080
1030
|
}
|
|
@@ -1101,12 +1051,9 @@ class ApiClient {
|
|
|
1101
1051
|
}
|
|
1102
1052
|
// Broker Data Management
|
|
1103
1053
|
async getBrokerList() {
|
|
1104
|
-
|
|
1105
|
-
return this.request('/brokers/
|
|
1054
|
+
// Public endpoint - no auth required
|
|
1055
|
+
return this.request('/brokers/', {
|
|
1106
1056
|
method: 'GET',
|
|
1107
|
-
headers: {
|
|
1108
|
-
'Authorization': `Bearer ${accessToken}`,
|
|
1109
|
-
},
|
|
1110
1057
|
});
|
|
1111
1058
|
}
|
|
1112
1059
|
async getBrokerAccounts(options) {
|
|
@@ -1124,7 +1071,7 @@ class ApiClient {
|
|
|
1124
1071
|
return this.request('/brokers/data/accounts', {
|
|
1125
1072
|
method: 'GET',
|
|
1126
1073
|
headers: {
|
|
1127
|
-
|
|
1074
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1128
1075
|
},
|
|
1129
1076
|
params,
|
|
1130
1077
|
});
|
|
@@ -1144,7 +1091,7 @@ class ApiClient {
|
|
|
1144
1091
|
return this.request('/brokers/data/orders', {
|
|
1145
1092
|
method: 'GET',
|
|
1146
1093
|
headers: {
|
|
1147
|
-
|
|
1094
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1148
1095
|
},
|
|
1149
1096
|
params,
|
|
1150
1097
|
});
|
|
@@ -1164,7 +1111,27 @@ class ApiClient {
|
|
|
1164
1111
|
return this.request('/brokers/data/positions', {
|
|
1165
1112
|
method: 'GET',
|
|
1166
1113
|
headers: {
|
|
1167
|
-
|
|
1114
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1115
|
+
},
|
|
1116
|
+
params,
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
async getBrokerBalances(options) {
|
|
1120
|
+
const accessToken = await this.getValidAccessToken();
|
|
1121
|
+
const params = {};
|
|
1122
|
+
if (options?.broker_name) {
|
|
1123
|
+
params.broker_id = options.broker_name;
|
|
1124
|
+
}
|
|
1125
|
+
if (options?.account_id) {
|
|
1126
|
+
params.account_id = options.account_id;
|
|
1127
|
+
}
|
|
1128
|
+
if (options?.symbol) {
|
|
1129
|
+
params.symbol = options.symbol;
|
|
1130
|
+
}
|
|
1131
|
+
return this.request('/brokers/data/balances', {
|
|
1132
|
+
method: 'GET',
|
|
1133
|
+
headers: {
|
|
1134
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1168
1135
|
},
|
|
1169
1136
|
params,
|
|
1170
1137
|
});
|
|
@@ -1174,7 +1141,26 @@ class ApiClient {
|
|
|
1174
1141
|
return this.request('/brokers/connections', {
|
|
1175
1142
|
method: 'GET',
|
|
1176
1143
|
headers: {
|
|
1177
|
-
|
|
1144
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1145
|
+
},
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1148
|
+
async getBalances(filters) {
|
|
1149
|
+
const accessToken = await this.getValidAccessToken();
|
|
1150
|
+
const params = new URLSearchParams();
|
|
1151
|
+
if (filters) {
|
|
1152
|
+
Object.entries(filters).forEach(([key, value]) => {
|
|
1153
|
+
if (value !== undefined && value !== null) {
|
|
1154
|
+
params.append(key, String(value));
|
|
1155
|
+
}
|
|
1156
|
+
});
|
|
1157
|
+
}
|
|
1158
|
+
const queryString = params.toString();
|
|
1159
|
+
const url = queryString ? `/brokers/data/balances?${queryString}` : '/brokers/data/balances';
|
|
1160
|
+
return this.request(url, {
|
|
1161
|
+
method: 'GET',
|
|
1162
|
+
headers: {
|
|
1163
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1178
1164
|
},
|
|
1179
1165
|
});
|
|
1180
1166
|
}
|
|
@@ -1396,6 +1382,81 @@ class ApiClient {
|
|
|
1396
1382
|
limit: perPage,
|
|
1397
1383
|
}, navigationCallback);
|
|
1398
1384
|
}
|
|
1385
|
+
async getBrokerBalancesPage(page = 1, perPage = 100, filters) {
|
|
1386
|
+
const accessToken = await this.getValidAccessToken();
|
|
1387
|
+
const offset = (page - 1) * perPage;
|
|
1388
|
+
const params = {
|
|
1389
|
+
limit: perPage.toString(),
|
|
1390
|
+
offset: offset.toString(),
|
|
1391
|
+
};
|
|
1392
|
+
// Add filter parameters
|
|
1393
|
+
if (filters) {
|
|
1394
|
+
if (filters.broker_id)
|
|
1395
|
+
params.broker_id = filters.broker_id;
|
|
1396
|
+
if (filters.connection_id)
|
|
1397
|
+
params.connection_id = filters.connection_id;
|
|
1398
|
+
if (filters.account_id)
|
|
1399
|
+
params.account_id = filters.account_id;
|
|
1400
|
+
if (filters.is_end_of_day_snapshot !== undefined)
|
|
1401
|
+
params.is_end_of_day_snapshot = filters.is_end_of_day_snapshot.toString();
|
|
1402
|
+
if (filters.balance_created_after)
|
|
1403
|
+
params.balance_created_after = filters.balance_created_after;
|
|
1404
|
+
if (filters.balance_created_before)
|
|
1405
|
+
params.balance_created_before = filters.balance_created_before;
|
|
1406
|
+
if (filters.with_metadata !== undefined)
|
|
1407
|
+
params.with_metadata = filters.with_metadata.toString();
|
|
1408
|
+
}
|
|
1409
|
+
const response = await this.request('/brokers/data/balances', {
|
|
1410
|
+
method: 'GET',
|
|
1411
|
+
headers: {
|
|
1412
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1413
|
+
},
|
|
1414
|
+
params,
|
|
1415
|
+
});
|
|
1416
|
+
// Create navigation callback for pagination
|
|
1417
|
+
const navigationCallback = async (newOffset, newLimit) => {
|
|
1418
|
+
const newParams = {
|
|
1419
|
+
limit: newLimit.toString(),
|
|
1420
|
+
offset: newOffset.toString(),
|
|
1421
|
+
};
|
|
1422
|
+
// Add filter parameters
|
|
1423
|
+
if (filters) {
|
|
1424
|
+
if (filters.broker_id)
|
|
1425
|
+
newParams.broker_id = filters.broker_id;
|
|
1426
|
+
if (filters.connection_id)
|
|
1427
|
+
newParams.connection_id = filters.connection_id;
|
|
1428
|
+
if (filters.account_id)
|
|
1429
|
+
newParams.account_id = filters.account_id;
|
|
1430
|
+
if (filters.is_end_of_day_snapshot !== undefined)
|
|
1431
|
+
newParams.is_end_of_day_snapshot = filters.is_end_of_day_snapshot.toString();
|
|
1432
|
+
if (filters.balance_created_after)
|
|
1433
|
+
newParams.balance_created_after = filters.balance_created_after;
|
|
1434
|
+
if (filters.balance_created_before)
|
|
1435
|
+
newParams.balance_created_before = filters.balance_created_before;
|
|
1436
|
+
if (filters.with_metadata !== undefined)
|
|
1437
|
+
newParams.with_metadata = filters.with_metadata.toString();
|
|
1438
|
+
}
|
|
1439
|
+
const newResponse = await this.request('/brokers/data/balances', {
|
|
1440
|
+
method: 'GET',
|
|
1441
|
+
headers: {
|
|
1442
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1443
|
+
},
|
|
1444
|
+
params: newParams,
|
|
1445
|
+
});
|
|
1446
|
+
return new PaginatedResult(newResponse.response_data, newResponse.pagination || {
|
|
1447
|
+
has_more: false,
|
|
1448
|
+
next_offset: newOffset,
|
|
1449
|
+
current_offset: newOffset,
|
|
1450
|
+
limit: newLimit,
|
|
1451
|
+
}, navigationCallback);
|
|
1452
|
+
};
|
|
1453
|
+
return new PaginatedResult(response.response_data, response.pagination || {
|
|
1454
|
+
has_more: false,
|
|
1455
|
+
next_offset: offset,
|
|
1456
|
+
current_offset: offset,
|
|
1457
|
+
limit: perPage,
|
|
1458
|
+
}, navigationCallback);
|
|
1459
|
+
}
|
|
1399
1460
|
// Navigation methods
|
|
1400
1461
|
async getNextPage(previousResult, fetchFunction) {
|
|
1401
1462
|
if (!previousResult.hasNext) {
|
|
@@ -1417,10 +1478,10 @@ class ApiClient {
|
|
|
1417
1478
|
*/
|
|
1418
1479
|
async disconnectCompany(connectionId) {
|
|
1419
1480
|
const accessToken = await this.getValidAccessToken();
|
|
1420
|
-
return this.request(`/brokers/disconnect
|
|
1481
|
+
return this.request(`/brokers/disconnect/${connectionId}`, {
|
|
1421
1482
|
method: 'DELETE',
|
|
1422
1483
|
headers: {
|
|
1423
|
-
|
|
1484
|
+
Authorization: `Bearer ${accessToken}`,
|
|
1424
1485
|
},
|
|
1425
1486
|
});
|
|
1426
1487
|
}
|
|
@@ -1483,7 +1544,6 @@ class PortalUI {
|
|
|
1483
1544
|
this.messageHandler = null;
|
|
1484
1545
|
this.sessionId = null;
|
|
1485
1546
|
this.portalOrigin = null;
|
|
1486
|
-
this.userToken = null;
|
|
1487
1547
|
this.originalBodyStyle = null;
|
|
1488
1548
|
this.createContainer();
|
|
1489
1549
|
}
|
|
@@ -1610,15 +1670,13 @@ class PortalUI {
|
|
|
1610
1670
|
console.warn('[PortalUI] Received message from unauthorized origin:', event.origin, 'Expected:', this.portalOrigin);
|
|
1611
1671
|
return;
|
|
1612
1672
|
}
|
|
1613
|
-
const { type, userId,
|
|
1673
|
+
const { type, userId, error, height, data } = event.data;
|
|
1614
1674
|
console.log('[PortalUI] Received message:', event.data);
|
|
1615
1675
|
switch (type) {
|
|
1616
1676
|
case 'portal-success': {
|
|
1617
1677
|
// Handle both direct userId and data.userId formats
|
|
1618
1678
|
const successUserId = userId || (data && data.userId);
|
|
1619
|
-
|
|
1620
|
-
const successRefreshToken = refresh_token || (data && data.refresh_token);
|
|
1621
|
-
this.handlePortalSuccess(successUserId, successAccessToken, successRefreshToken);
|
|
1679
|
+
this.handlePortalSuccess(successUserId);
|
|
1622
1680
|
break;
|
|
1623
1681
|
}
|
|
1624
1682
|
case 'portal-error': {
|
|
@@ -1638,7 +1696,7 @@ class PortalUI {
|
|
|
1638
1696
|
break;
|
|
1639
1697
|
// Legacy support for old message types
|
|
1640
1698
|
case 'success':
|
|
1641
|
-
this.handleSuccess(userId
|
|
1699
|
+
this.handleSuccess(userId);
|
|
1642
1700
|
break;
|
|
1643
1701
|
case 'error':
|
|
1644
1702
|
this.handleError(error);
|
|
@@ -1650,28 +1708,12 @@ class PortalUI {
|
|
|
1650
1708
|
console.warn('[PortalUI] Received unhandled message type:', type);
|
|
1651
1709
|
}
|
|
1652
1710
|
}
|
|
1653
|
-
handlePortalSuccess(userId
|
|
1711
|
+
handlePortalSuccess(userId) {
|
|
1654
1712
|
if (!userId) {
|
|
1655
1713
|
console.error('[PortalUI] Missing userId in portal-success message');
|
|
1656
1714
|
return;
|
|
1657
1715
|
}
|
|
1658
1716
|
console.log('[PortalUI] Portal success - User connected:', userId);
|
|
1659
|
-
// If tokens are provided, store them internally
|
|
1660
|
-
if (accessToken && refreshToken) {
|
|
1661
|
-
const userToken = {
|
|
1662
|
-
accessToken: accessToken,
|
|
1663
|
-
refreshToken: refreshToken,
|
|
1664
|
-
expiresIn: 3600, // Default to 1 hour
|
|
1665
|
-
user_id: userId,
|
|
1666
|
-
tokenType: 'Bearer',
|
|
1667
|
-
scope: 'api:access',
|
|
1668
|
-
};
|
|
1669
|
-
this.userToken = userToken;
|
|
1670
|
-
console.log('[PortalUI] Portal authentication successful');
|
|
1671
|
-
}
|
|
1672
|
-
else {
|
|
1673
|
-
console.warn('[PortalUI] No tokens received from portal');
|
|
1674
|
-
}
|
|
1675
1717
|
// Pass userId to parent (SDK will handle tokens internally)
|
|
1676
1718
|
this.options?.onSuccess?.(userId);
|
|
1677
1719
|
}
|
|
@@ -1696,22 +1738,11 @@ class PortalUI {
|
|
|
1696
1738
|
this.options.onEvent(data.type, data.data);
|
|
1697
1739
|
}
|
|
1698
1740
|
}
|
|
1699
|
-
handleSuccess(userId
|
|
1700
|
-
if (!userId
|
|
1741
|
+
handleSuccess(userId) {
|
|
1742
|
+
if (!userId) {
|
|
1701
1743
|
console.error('[PortalUI] Missing required fields in success message');
|
|
1702
1744
|
return;
|
|
1703
1745
|
}
|
|
1704
|
-
// Convert portal tokens to UserToken format
|
|
1705
|
-
const userToken = {
|
|
1706
|
-
accessToken: access_token,
|
|
1707
|
-
refreshToken: refresh_token,
|
|
1708
|
-
expiresIn: 3600, // Default to 1 hour
|
|
1709
|
-
user_id: userId,
|
|
1710
|
-
tokenType: 'Bearer',
|
|
1711
|
-
scope: 'api:access',
|
|
1712
|
-
};
|
|
1713
|
-
// Store tokens internally
|
|
1714
|
-
this.userToken = userToken;
|
|
1715
1746
|
// Pass userId to parent
|
|
1716
1747
|
this.options?.onSuccess?.(userId);
|
|
1717
1748
|
}
|
|
@@ -1730,9 +1761,6 @@ class PortalUI {
|
|
|
1730
1761
|
this.iframe.style.height = `${height}px`;
|
|
1731
1762
|
}
|
|
1732
1763
|
}
|
|
1733
|
-
getTokens() {
|
|
1734
|
-
return this.userToken;
|
|
1735
|
-
}
|
|
1736
1764
|
}
|
|
1737
1765
|
|
|
1738
1766
|
/**
|
|
@@ -2072,109 +2100,6 @@ class MockDataProvider {
|
|
|
2072
2100
|
};
|
|
2073
2101
|
}
|
|
2074
2102
|
// Portfolio & Trading Mocks
|
|
2075
|
-
async mockGetHoldings() {
|
|
2076
|
-
await this.simulateDelay();
|
|
2077
|
-
const holdings = [
|
|
2078
|
-
{
|
|
2079
|
-
symbol: 'AAPL',
|
|
2080
|
-
quantity: 100,
|
|
2081
|
-
averagePrice: 150.25,
|
|
2082
|
-
currentPrice: 175.5,
|
|
2083
|
-
marketValue: 17550.0,
|
|
2084
|
-
unrealizedPnL: 2525.0,
|
|
2085
|
-
realizedPnL: 0,
|
|
2086
|
-
costBasis: 15025.0,
|
|
2087
|
-
currency: 'USD',
|
|
2088
|
-
},
|
|
2089
|
-
{
|
|
2090
|
-
symbol: 'TSLA',
|
|
2091
|
-
quantity: 50,
|
|
2092
|
-
averagePrice: 200.0,
|
|
2093
|
-
currentPrice: 220.75,
|
|
2094
|
-
marketValue: 11037.5,
|
|
2095
|
-
unrealizedPnL: 1037.5,
|
|
2096
|
-
realizedPnL: 0,
|
|
2097
|
-
costBasis: 10000.0,
|
|
2098
|
-
currency: 'USD',
|
|
2099
|
-
},
|
|
2100
|
-
{
|
|
2101
|
-
symbol: 'MSFT',
|
|
2102
|
-
quantity: 75,
|
|
2103
|
-
averagePrice: 300.0,
|
|
2104
|
-
currentPrice: 325.25,
|
|
2105
|
-
marketValue: 24393.75,
|
|
2106
|
-
unrealizedPnL: 1893.75,
|
|
2107
|
-
realizedPnL: 0,
|
|
2108
|
-
costBasis: 22500.0,
|
|
2109
|
-
currency: 'USD',
|
|
2110
|
-
},
|
|
2111
|
-
];
|
|
2112
|
-
return { data: holdings };
|
|
2113
|
-
}
|
|
2114
|
-
async mockGetPortfolio() {
|
|
2115
|
-
await this.simulateDelay();
|
|
2116
|
-
const portfolio = {
|
|
2117
|
-
id: v4(),
|
|
2118
|
-
name: 'Main Portfolio',
|
|
2119
|
-
type: 'individual',
|
|
2120
|
-
status: 'active',
|
|
2121
|
-
cash: 15000.5,
|
|
2122
|
-
buyingPower: 45000.0,
|
|
2123
|
-
equity: 52981.25,
|
|
2124
|
-
longMarketValue: 37981.25,
|
|
2125
|
-
shortMarketValue: 0,
|
|
2126
|
-
initialMargin: 0,
|
|
2127
|
-
maintenanceMargin: 0,
|
|
2128
|
-
lastEquity: 52000.0,
|
|
2129
|
-
positions: [
|
|
2130
|
-
{
|
|
2131
|
-
symbol: 'AAPL',
|
|
2132
|
-
quantity: 100,
|
|
2133
|
-
averagePrice: 150.25,
|
|
2134
|
-
currentPrice: 175.5,
|
|
2135
|
-
marketValue: 17550.0,
|
|
2136
|
-
unrealizedPnL: 2525.0,
|
|
2137
|
-
realizedPnL: 0,
|
|
2138
|
-
costBasis: 15025.0,
|
|
2139
|
-
currency: 'USD',
|
|
2140
|
-
},
|
|
2141
|
-
{
|
|
2142
|
-
symbol: 'TSLA',
|
|
2143
|
-
quantity: 50,
|
|
2144
|
-
averagePrice: 200.0,
|
|
2145
|
-
currentPrice: 220.75,
|
|
2146
|
-
marketValue: 11037.5,
|
|
2147
|
-
unrealizedPnL: 1037.5,
|
|
2148
|
-
realizedPnL: 0,
|
|
2149
|
-
costBasis: 10000.0,
|
|
2150
|
-
currency: 'USD',
|
|
2151
|
-
},
|
|
2152
|
-
{
|
|
2153
|
-
symbol: 'MSFT',
|
|
2154
|
-
quantity: 75,
|
|
2155
|
-
averagePrice: 300.0,
|
|
2156
|
-
currentPrice: 325.25,
|
|
2157
|
-
marketValue: 24393.75,
|
|
2158
|
-
unrealizedPnL: 1893.75,
|
|
2159
|
-
realizedPnL: 0,
|
|
2160
|
-
costBasis: 22500.0,
|
|
2161
|
-
currency: 'USD',
|
|
2162
|
-
},
|
|
2163
|
-
],
|
|
2164
|
-
performance: {
|
|
2165
|
-
totalReturn: 0.089,
|
|
2166
|
-
dailyReturn: 0.002,
|
|
2167
|
-
weeklyReturn: 0.015,
|
|
2168
|
-
monthlyReturn: 0.045,
|
|
2169
|
-
yearlyReturn: 0.089,
|
|
2170
|
-
maxDrawdown: -0.05,
|
|
2171
|
-
sharpeRatio: 1.2,
|
|
2172
|
-
beta: 0.95,
|
|
2173
|
-
alpha: 0.02,
|
|
2174
|
-
},
|
|
2175
|
-
};
|
|
2176
|
-
return { data: portfolio };
|
|
2177
|
-
}
|
|
2178
2103
|
async mockGetOrders(filter) {
|
|
2179
2104
|
await this.simulateDelay();
|
|
2180
2105
|
const mockOrders = [
|
|
@@ -2235,6 +2160,52 @@ class MockDataProvider {
|
|
|
2235
2160
|
data: filteredPositions,
|
|
2236
2161
|
};
|
|
2237
2162
|
}
|
|
2163
|
+
async mockGetBrokerBalances(filter) {
|
|
2164
|
+
await this.simulateDelay();
|
|
2165
|
+
// Determine how many balances to generate based on limit parameter
|
|
2166
|
+
const limit = filter?.limit || 100;
|
|
2167
|
+
const maxLimit = Math.min(limit, 1000); // Cap at 1000
|
|
2168
|
+
const mockBalances = [];
|
|
2169
|
+
for (let i = 0; i < maxLimit; i++) {
|
|
2170
|
+
const totalCashValue = Math.random() * 100000 + 10000; // $10k - $110k
|
|
2171
|
+
const netLiquidationValue = totalCashValue * (0.8 + Math.random() * 0.4); // ±20% variation
|
|
2172
|
+
const initialMargin = netLiquidationValue * 0.1; // 10% of net liquidation
|
|
2173
|
+
const maintenanceMargin = initialMargin * 0.8; // 80% of initial margin
|
|
2174
|
+
const availableToWithdraw = totalCashValue * 0.9; // 90% of cash available
|
|
2175
|
+
const totalRealizedPnl = (Math.random() - 0.5) * 10000; // -$5k to +$5k
|
|
2176
|
+
const balance = {
|
|
2177
|
+
id: `balance_${i + 1}`,
|
|
2178
|
+
account_id: `account_${Math.floor(Math.random() * 3) + 1}`,
|
|
2179
|
+
total_cash_value: totalCashValue,
|
|
2180
|
+
net_liquidation_value: netLiquidationValue,
|
|
2181
|
+
initial_margin: initialMargin,
|
|
2182
|
+
maintenance_margin: maintenanceMargin,
|
|
2183
|
+
available_to_withdraw: availableToWithdraw,
|
|
2184
|
+
total_realized_pnl: totalRealizedPnl,
|
|
2185
|
+
balance_created_at: new Date(Date.now() - Math.random() * 7 * 24 * 60 * 60 * 1000).toISOString(),
|
|
2186
|
+
balance_updated_at: new Date().toISOString(),
|
|
2187
|
+
is_end_of_day_snapshot: Math.random() > 0.7, // 30% chance of being EOD snapshot
|
|
2188
|
+
raw_payload: {
|
|
2189
|
+
broker_specific_data: {
|
|
2190
|
+
margin_ratio: netLiquidationValue / initialMargin,
|
|
2191
|
+
day_trading_buying_power: availableToWithdraw * 4,
|
|
2192
|
+
overnight_buying_power: availableToWithdraw * 2,
|
|
2193
|
+
},
|
|
2194
|
+
},
|
|
2195
|
+
created_at: new Date(Date.now() - Math.random() * 30 * 24 * 60 * 60 * 1000).toISOString(),
|
|
2196
|
+
updated_at: new Date().toISOString(),
|
|
2197
|
+
};
|
|
2198
|
+
mockBalances.push(balance);
|
|
2199
|
+
}
|
|
2200
|
+
// Apply filters if provided
|
|
2201
|
+
let filteredBalances = mockBalances;
|
|
2202
|
+
if (filter) {
|
|
2203
|
+
filteredBalances = this.applyBrokerBalanceFilters(mockBalances, filter);
|
|
2204
|
+
}
|
|
2205
|
+
return {
|
|
2206
|
+
data: filteredBalances,
|
|
2207
|
+
};
|
|
2208
|
+
}
|
|
2238
2209
|
async mockGetBrokerDataAccounts(filter) {
|
|
2239
2210
|
await this.simulateDelay();
|
|
2240
2211
|
// Determine how many accounts to generate based on limit parameter
|
|
@@ -2287,8 +2258,8 @@ class MockDataProvider {
|
|
|
2287
2258
|
/**
|
|
2288
2259
|
* Get stored user token
|
|
2289
2260
|
*/
|
|
2290
|
-
getUserToken(
|
|
2291
|
-
return this.userTokens.get(
|
|
2261
|
+
getUserToken(sessionId) {
|
|
2262
|
+
return this.userTokens.get(sessionId);
|
|
2292
2263
|
}
|
|
2293
2264
|
/**
|
|
2294
2265
|
* Clear all stored data
|
|
@@ -2380,6 +2351,19 @@ class MockDataProvider {
|
|
|
2380
2351
|
return true;
|
|
2381
2352
|
});
|
|
2382
2353
|
}
|
|
2354
|
+
applyBrokerBalanceFilters(balances, filter) {
|
|
2355
|
+
return balances.filter(balance => {
|
|
2356
|
+
if (filter.account_id && balance.account_id !== filter.account_id)
|
|
2357
|
+
return false;
|
|
2358
|
+
if (filter.is_end_of_day_snapshot !== undefined && balance.is_end_of_day_snapshot !== filter.is_end_of_day_snapshot)
|
|
2359
|
+
return false;
|
|
2360
|
+
if (filter.balance_created_after && balance.balance_created_at && new Date(balance.balance_created_at) < new Date(filter.balance_created_after))
|
|
2361
|
+
return false;
|
|
2362
|
+
if (filter.balance_created_before && balance.balance_created_at && new Date(balance.balance_created_at) > new Date(filter.balance_created_before))
|
|
2363
|
+
return false;
|
|
2364
|
+
return true;
|
|
2365
|
+
});
|
|
2366
|
+
}
|
|
2383
2367
|
/**
|
|
2384
2368
|
* Generate mock orders with diverse data
|
|
2385
2369
|
*/
|
|
@@ -2791,18 +2775,10 @@ class MockApiClient {
|
|
|
2791
2775
|
return this.mockDataProvider.mockCompletePortalSession(sessionId);
|
|
2792
2776
|
}
|
|
2793
2777
|
// Portfolio Management
|
|
2794
|
-
async getHoldings(filter) {
|
|
2795
|
-
await this.getValidAccessToken();
|
|
2796
|
-
return this.mockDataProvider.mockGetHoldings();
|
|
2797
|
-
}
|
|
2798
2778
|
async getOrders(filter) {
|
|
2799
2779
|
await this.getValidAccessToken();
|
|
2800
2780
|
return this.mockDataProvider.mockGetOrders(filter);
|
|
2801
2781
|
}
|
|
2802
|
-
async getPortfolio() {
|
|
2803
|
-
await this.getValidAccessToken();
|
|
2804
|
-
return this.mockDataProvider.mockGetPortfolio();
|
|
2805
|
-
}
|
|
2806
2782
|
async placeOrder(order) {
|
|
2807
2783
|
await this.getValidAccessToken();
|
|
2808
2784
|
await this.mockDataProvider.mockPlaceOrder(order);
|
|
@@ -2817,7 +2793,7 @@ class MockApiClient {
|
|
|
2817
2793
|
paramsBroker: params.broker,
|
|
2818
2794
|
contextBroker: this.tradingContext.broker,
|
|
2819
2795
|
paramsAccountNumber: params.accountNumber,
|
|
2820
|
-
contextAccountNumber: this.tradingContext.accountNumber
|
|
2796
|
+
contextAccountNumber: this.tradingContext.accountNumber,
|
|
2821
2797
|
});
|
|
2822
2798
|
const fullParams = {
|
|
2823
2799
|
broker: (params.broker || this.tradingContext.broker) ||
|
|
@@ -2880,7 +2856,7 @@ class MockApiClient {
|
|
|
2880
2856
|
console.log('MockApiClient.setAccount Debug:', {
|
|
2881
2857
|
accountNumber,
|
|
2882
2858
|
accountId,
|
|
2883
|
-
previousContext: { ...this.tradingContext }
|
|
2859
|
+
previousContext: { ...this.tradingContext },
|
|
2884
2860
|
});
|
|
2885
2861
|
this.tradingContext.accountNumber = accountNumber;
|
|
2886
2862
|
this.tradingContext.accountId = accountId;
|
|
@@ -3013,12 +2989,8 @@ class MockApiClient {
|
|
|
3013
2989
|
price,
|
|
3014
2990
|
}, extras);
|
|
3015
2991
|
}
|
|
3016
|
-
async
|
|
3017
|
-
|
|
3018
|
-
this.clearTokens();
|
|
3019
|
-
}
|
|
3020
|
-
async getUserToken(userId) {
|
|
3021
|
-
const token = this.mockDataProvider.getUserToken(userId);
|
|
2992
|
+
async getUserToken(sessionId) {
|
|
2993
|
+
const token = this.mockDataProvider.getUserToken(sessionId);
|
|
3022
2994
|
if (!token) {
|
|
3023
2995
|
throw new AuthenticationError('User token not found');
|
|
3024
2996
|
}
|
|
@@ -3029,7 +3001,7 @@ class MockApiClient {
|
|
|
3029
3001
|
}
|
|
3030
3002
|
// Broker Data Management
|
|
3031
3003
|
async getBrokerList() {
|
|
3032
|
-
|
|
3004
|
+
// Public in mock mode as well - no auth required
|
|
3033
3005
|
return this.mockDataProvider.mockGetBrokerList();
|
|
3034
3006
|
}
|
|
3035
3007
|
async getBrokerAccounts(options) {
|
|
@@ -3067,6 +3039,9 @@ class MockApiClient {
|
|
|
3067
3039
|
async getBrokerPositionsWithFilter(filter) {
|
|
3068
3040
|
return this.mockDataProvider.mockGetBrokerPositions(filter);
|
|
3069
3041
|
}
|
|
3042
|
+
async getBrokerBalancesWithFilter(filter) {
|
|
3043
|
+
return this.mockDataProvider.mockGetBrokerBalances(filter);
|
|
3044
|
+
}
|
|
3070
3045
|
async getBrokerDataAccountsWithFilter(filter) {
|
|
3071
3046
|
return this.mockDataProvider.mockGetBrokerDataAccounts(filter);
|
|
3072
3047
|
}
|
|
@@ -3161,6 +3136,36 @@ class MockApiClient {
|
|
|
3161
3136
|
limit: perPage,
|
|
3162
3137
|
}, navigationCallback);
|
|
3163
3138
|
}
|
|
3139
|
+
async getBrokerBalancesPage(page = 1, perPage = 100, filters) {
|
|
3140
|
+
const mockBalances = await this.mockDataProvider.mockGetBrokerBalances(filters);
|
|
3141
|
+
const balances = mockBalances.data;
|
|
3142
|
+
// Simulate pagination
|
|
3143
|
+
const startIndex = (page - 1) * perPage;
|
|
3144
|
+
const endIndex = startIndex + perPage;
|
|
3145
|
+
const paginatedBalances = balances.slice(startIndex, endIndex);
|
|
3146
|
+
const hasMore = endIndex < balances.length;
|
|
3147
|
+
const nextOffset = hasMore ? endIndex : startIndex;
|
|
3148
|
+
// Create navigation callback for mock pagination
|
|
3149
|
+
const navigationCallback = async (newOffset, newLimit) => {
|
|
3150
|
+
const newStartIndex = newOffset;
|
|
3151
|
+
const newEndIndex = newStartIndex + newLimit;
|
|
3152
|
+
const newPaginatedBalances = balances.slice(newStartIndex, newEndIndex);
|
|
3153
|
+
const newHasMore = newEndIndex < balances.length;
|
|
3154
|
+
const newNextOffset = newHasMore ? newEndIndex : newStartIndex;
|
|
3155
|
+
return new PaginatedResult(newPaginatedBalances, {
|
|
3156
|
+
has_more: newHasMore,
|
|
3157
|
+
next_offset: newNextOffset,
|
|
3158
|
+
current_offset: newStartIndex,
|
|
3159
|
+
limit: newLimit,
|
|
3160
|
+
}, navigationCallback);
|
|
3161
|
+
};
|
|
3162
|
+
return new PaginatedResult(paginatedBalances, {
|
|
3163
|
+
has_more: hasMore,
|
|
3164
|
+
next_offset: nextOffset,
|
|
3165
|
+
current_offset: startIndex,
|
|
3166
|
+
limit: perPage,
|
|
3167
|
+
}, navigationCallback);
|
|
3168
|
+
}
|
|
3164
3169
|
async getBrokerConnections() {
|
|
3165
3170
|
await this.getValidAccessToken();
|
|
3166
3171
|
return this.mockDataProvider.mockGetBrokerConnections();
|
|
@@ -3399,9 +3404,135 @@ const darkTheme = {
|
|
|
3399
3404
|
},
|
|
3400
3405
|
},
|
|
3401
3406
|
},
|
|
3407
|
+
typography: {
|
|
3408
|
+
fontFamily: {
|
|
3409
|
+
primary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
|
|
3410
|
+
secondary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
|
|
3411
|
+
},
|
|
3412
|
+
fontSize: {
|
|
3413
|
+
xs: '0.75rem',
|
|
3414
|
+
sm: '0.875rem',
|
|
3415
|
+
base: '1rem',
|
|
3416
|
+
lg: '1.125rem',
|
|
3417
|
+
xl: '1.25rem',
|
|
3418
|
+
'2xl': '1.5rem',
|
|
3419
|
+
'3xl': '1.875rem',
|
|
3420
|
+
'4xl': '2.25rem',
|
|
3421
|
+
},
|
|
3422
|
+
fontWeight: {
|
|
3423
|
+
normal: 400,
|
|
3424
|
+
medium: 500,
|
|
3425
|
+
semibold: 600,
|
|
3426
|
+
bold: 700,
|
|
3427
|
+
extrabold: 800,
|
|
3428
|
+
},
|
|
3429
|
+
lineHeight: {
|
|
3430
|
+
tight: '1.25',
|
|
3431
|
+
normal: '1.5',
|
|
3432
|
+
relaxed: '1.75',
|
|
3433
|
+
},
|
|
3434
|
+
},
|
|
3435
|
+
spacing: {
|
|
3436
|
+
xs: '0.25rem',
|
|
3437
|
+
sm: '0.5rem',
|
|
3438
|
+
md: '1rem',
|
|
3439
|
+
lg: '1.5rem',
|
|
3440
|
+
xl: '2rem',
|
|
3441
|
+
'2xl': '3rem',
|
|
3442
|
+
'3xl': '4rem',
|
|
3443
|
+
},
|
|
3444
|
+
layout: {
|
|
3445
|
+
containerMaxWidth: '1440px',
|
|
3446
|
+
gridGap: '1rem',
|
|
3447
|
+
cardPadding: '1.5rem',
|
|
3448
|
+
borderRadius: {
|
|
3449
|
+
sm: '0.25rem',
|
|
3450
|
+
md: '0.5rem',
|
|
3451
|
+
lg: '0.75rem',
|
|
3452
|
+
xl: '1rem',
|
|
3453
|
+
'2xl': '1.5rem',
|
|
3454
|
+
full: '9999px',
|
|
3455
|
+
},
|
|
3456
|
+
},
|
|
3457
|
+
components: {
|
|
3458
|
+
brokerCard: {
|
|
3459
|
+
width: '100%',
|
|
3460
|
+
height: '180px',
|
|
3461
|
+
logoSize: '64px',
|
|
3462
|
+
padding: '1.5rem',
|
|
3463
|
+
},
|
|
3464
|
+
statusIndicator: {
|
|
3465
|
+
size: '22px',
|
|
3466
|
+
glowIntensity: 0.9,
|
|
3467
|
+
},
|
|
3468
|
+
modal: {
|
|
3469
|
+
background: 'rgba(0, 0, 0, 0.95)',
|
|
3470
|
+
backdrop: 'rgba(0, 0, 0, 0.8)',
|
|
3471
|
+
},
|
|
3472
|
+
brokerCardModern: {
|
|
3473
|
+
width: '150px',
|
|
3474
|
+
height: '150px',
|
|
3475
|
+
padding: '16px',
|
|
3476
|
+
logoSize: '48px',
|
|
3477
|
+
statusSize: '22px',
|
|
3478
|
+
},
|
|
3479
|
+
connectButton: {
|
|
3480
|
+
width: '120px',
|
|
3481
|
+
height: '120px',
|
|
3482
|
+
},
|
|
3483
|
+
themeSwitcher: {
|
|
3484
|
+
indicatorSize: '24px',
|
|
3485
|
+
},
|
|
3486
|
+
},
|
|
3487
|
+
effects: {
|
|
3488
|
+
glassmorphism: {
|
|
3489
|
+
enabled: true,
|
|
3490
|
+
blur: '12px',
|
|
3491
|
+
opacity: 0.15,
|
|
3492
|
+
border: 'rgba(0, 255, 255, 0.3)',
|
|
3493
|
+
},
|
|
3494
|
+
animations: {
|
|
3495
|
+
enabled: true,
|
|
3496
|
+
duration: {
|
|
3497
|
+
fast: '150ms',
|
|
3498
|
+
normal: '300ms',
|
|
3499
|
+
slow: '500ms',
|
|
3500
|
+
},
|
|
3501
|
+
easing: {
|
|
3502
|
+
default: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
|
3503
|
+
smooth: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
|
|
3504
|
+
bounce: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)',
|
|
3505
|
+
},
|
|
3506
|
+
},
|
|
3507
|
+
shadows: {
|
|
3508
|
+
sm: '0 1px 2px rgba(0, 0, 0, 0.5)',
|
|
3509
|
+
md: '0 4px 6px rgba(0, 0, 0, 0.6)',
|
|
3510
|
+
lg: '0 10px 15px rgba(0, 0, 0, 0.7)',
|
|
3511
|
+
xl: '0 20px 25px rgba(0, 0, 0, 0.8)',
|
|
3512
|
+
card: '0px 4px 12px rgba(0, 0, 0, 0.6), 0 0 20px rgba(0, 255, 255, 0.2)',
|
|
3513
|
+
cardHover: '0px 4px 24px rgba(0, 255, 255, 0.3), 0 0 30px rgba(0, 255, 255, 0.25)',
|
|
3514
|
+
glow: '0 0 20px rgba(0, 255, 255, 0.8)',
|
|
3515
|
+
focus: '0 0 0 2px #00FFFF, 0 0 8px 2px rgba(0, 255, 255, 0.8)',
|
|
3516
|
+
},
|
|
3517
|
+
},
|
|
3402
3518
|
branding: {
|
|
3403
3519
|
primaryColor: '#00FFFF',
|
|
3404
3520
|
},
|
|
3521
|
+
glow: {
|
|
3522
|
+
primary: 'rgba(0, 255, 255, 0.4)',
|
|
3523
|
+
secondary: 'rgba(0, 255, 255, 0.6)',
|
|
3524
|
+
card: 'rgba(0, 255, 255, 0.2)',
|
|
3525
|
+
cardHover: 'rgba(0, 255, 255, 0.3)',
|
|
3526
|
+
button: 'rgba(0, 255, 255, 0.6)',
|
|
3527
|
+
focus: 'rgba(0, 255, 255, 0.8)',
|
|
3528
|
+
scrollbar: 'rgba(0, 255, 255, 0.4)',
|
|
3529
|
+
},
|
|
3530
|
+
gradients: {
|
|
3531
|
+
start: 'rgba(0, 255, 255, 0.08)',
|
|
3532
|
+
end: 'rgba(0, 255, 255, 0.03)',
|
|
3533
|
+
hoverStart: 'rgba(0, 255, 255, 0.15)',
|
|
3534
|
+
hoverEnd: 'rgba(0, 255, 255, 0.08)',
|
|
3535
|
+
},
|
|
3405
3536
|
};
|
|
3406
3537
|
// Light theme with cyan accents
|
|
3407
3538
|
const lightTheme = {
|
|
@@ -3458,16 +3589,128 @@ const lightTheme = {
|
|
|
3458
3589
|
},
|
|
3459
3590
|
},
|
|
3460
3591
|
},
|
|
3461
|
-
|
|
3462
|
-
|
|
3592
|
+
typography: {
|
|
3593
|
+
fontFamily: {
|
|
3594
|
+
primary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
|
|
3595
|
+
secondary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
|
|
3596
|
+
},
|
|
3597
|
+
fontSize: {
|
|
3598
|
+
xs: '0.75rem',
|
|
3599
|
+
sm: '0.875rem',
|
|
3600
|
+
base: '1rem',
|
|
3601
|
+
lg: '1.125rem',
|
|
3602
|
+
xl: '1.25rem',
|
|
3603
|
+
'2xl': '1.5rem',
|
|
3604
|
+
'3xl': '1.875rem',
|
|
3605
|
+
'4xl': '2.25rem',
|
|
3606
|
+
},
|
|
3607
|
+
fontWeight: {
|
|
3608
|
+
normal: 400,
|
|
3609
|
+
medium: 500,
|
|
3610
|
+
semibold: 600,
|
|
3611
|
+
bold: 700,
|
|
3612
|
+
extrabold: 800,
|
|
3613
|
+
},
|
|
3614
|
+
lineHeight: {
|
|
3615
|
+
tight: '1.25',
|
|
3616
|
+
normal: '1.5',
|
|
3617
|
+
relaxed: '1.75',
|
|
3618
|
+
},
|
|
3463
3619
|
},
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3620
|
+
spacing: {
|
|
3621
|
+
xs: '0.25rem',
|
|
3622
|
+
sm: '0.5rem',
|
|
3623
|
+
md: '1rem',
|
|
3624
|
+
lg: '1.5rem',
|
|
3625
|
+
xl: '2rem',
|
|
3626
|
+
'2xl': '3rem',
|
|
3627
|
+
'3xl': '4rem',
|
|
3628
|
+
},
|
|
3629
|
+
layout: {
|
|
3630
|
+
containerMaxWidth: '1440px',
|
|
3631
|
+
gridGap: '1rem',
|
|
3632
|
+
cardPadding: '1.5rem',
|
|
3633
|
+
borderRadius: {
|
|
3634
|
+
sm: '0.25rem',
|
|
3635
|
+
md: '0.5rem',
|
|
3636
|
+
lg: '0.75rem',
|
|
3637
|
+
xl: '1rem',
|
|
3638
|
+
'2xl': '1.5rem',
|
|
3639
|
+
full: '9999px',
|
|
3640
|
+
},
|
|
3641
|
+
},
|
|
3642
|
+
components: {
|
|
3643
|
+
brokerCard: {
|
|
3644
|
+
width: '100%',
|
|
3645
|
+
height: '180px',
|
|
3646
|
+
logoSize: '64px',
|
|
3647
|
+
padding: '1.5rem',
|
|
3648
|
+
},
|
|
3649
|
+
statusIndicator: {
|
|
3650
|
+
size: '22px',
|
|
3651
|
+
glowIntensity: 0.9,
|
|
3652
|
+
},
|
|
3653
|
+
modal: {
|
|
3654
|
+
background: 'rgba(255, 255, 255, 0.95)',
|
|
3655
|
+
backdrop: 'rgba(0, 0, 0, 0.5)',
|
|
3656
|
+
},
|
|
3657
|
+
},
|
|
3658
|
+
effects: {
|
|
3659
|
+
glassmorphism: {
|
|
3660
|
+
enabled: true,
|
|
3661
|
+
blur: '12px',
|
|
3662
|
+
opacity: 0.15,
|
|
3663
|
+
border: 'rgba(0, 255, 255, 0.3)',
|
|
3664
|
+
},
|
|
3665
|
+
animations: {
|
|
3666
|
+
enabled: true,
|
|
3667
|
+
duration: {
|
|
3668
|
+
fast: '150ms',
|
|
3669
|
+
normal: '300ms',
|
|
3670
|
+
slow: '500ms',
|
|
3671
|
+
},
|
|
3672
|
+
easing: {
|
|
3673
|
+
default: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
|
3674
|
+
smooth: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
|
|
3675
|
+
bounce: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)',
|
|
3676
|
+
},
|
|
3677
|
+
},
|
|
3678
|
+
shadows: {
|
|
3679
|
+
sm: '0 1px 2px rgba(0, 0, 0, 0.1)',
|
|
3680
|
+
md: '0 4px 6px rgba(0, 0, 0, 0.1)',
|
|
3681
|
+
lg: '0 10px 15px rgba(0, 0, 0, 0.1)',
|
|
3682
|
+
xl: '0 20px 25px rgba(0, 0, 0, 0.1)',
|
|
3683
|
+
card: '0px 4px 12px rgba(0, 0, 0, 0.1), 0 0 20px rgba(0, 255, 255, 0.2)',
|
|
3684
|
+
cardHover: '0px 4px 24px rgba(0, 255, 255, 0.3), 0 0 30px rgba(0, 255, 255, 0.25)',
|
|
3685
|
+
glow: '0 0 20px rgba(0, 255, 255, 0.8)',
|
|
3686
|
+
focus: '0 0 0 2px #00FFFF, 0 0 8px 2px rgba(0, 255, 255, 0.8)',
|
|
3687
|
+
},
|
|
3688
|
+
},
|
|
3689
|
+
branding: {
|
|
3690
|
+
primaryColor: '#00FFFF',
|
|
3691
|
+
},
|
|
3692
|
+
glow: {
|
|
3693
|
+
primary: 'rgba(0, 255, 255, 0.4)',
|
|
3694
|
+
secondary: 'rgba(0, 255, 255, 0.6)',
|
|
3695
|
+
card: 'rgba(0, 255, 255, 0.2)',
|
|
3696
|
+
cardHover: 'rgba(0, 255, 255, 0.3)',
|
|
3697
|
+
button: 'rgba(0, 255, 255, 0.6)',
|
|
3698
|
+
focus: 'rgba(0, 255, 255, 0.8)',
|
|
3699
|
+
scrollbar: 'rgba(0, 255, 255, 0.4)',
|
|
3700
|
+
},
|
|
3701
|
+
gradients: {
|
|
3702
|
+
start: 'rgba(0, 255, 255, 0.08)',
|
|
3703
|
+
end: 'rgba(0, 255, 255, 0.03)',
|
|
3704
|
+
hoverStart: 'rgba(0, 255, 255, 0.15)',
|
|
3705
|
+
hoverEnd: 'rgba(0, 255, 255, 0.08)',
|
|
3706
|
+
},
|
|
3707
|
+
};
|
|
3708
|
+
// Corporate blue theme
|
|
3709
|
+
const corporateBlueTheme = {
|
|
3710
|
+
mode: 'dark',
|
|
3711
|
+
colors: {
|
|
3712
|
+
background: {
|
|
3713
|
+
primary: '#1E293B',
|
|
3471
3714
|
secondary: '#334155',
|
|
3472
3715
|
tertiary: '#475569',
|
|
3473
3716
|
accent: 'rgba(59, 130, 246, 0.1)',
|
|
@@ -3517,9 +3760,135 @@ const corporateBlueTheme = {
|
|
|
3517
3760
|
},
|
|
3518
3761
|
},
|
|
3519
3762
|
},
|
|
3763
|
+
typography: {
|
|
3764
|
+
fontFamily: {
|
|
3765
|
+
primary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
|
|
3766
|
+
secondary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
|
|
3767
|
+
},
|
|
3768
|
+
fontSize: {
|
|
3769
|
+
xs: '0.75rem',
|
|
3770
|
+
sm: '0.875rem',
|
|
3771
|
+
base: '1rem',
|
|
3772
|
+
lg: '1.125rem',
|
|
3773
|
+
xl: '1.25rem',
|
|
3774
|
+
'2xl': '1.5rem',
|
|
3775
|
+
'3xl': '1.875rem',
|
|
3776
|
+
'4xl': '2.25rem',
|
|
3777
|
+
},
|
|
3778
|
+
fontWeight: {
|
|
3779
|
+
normal: 400,
|
|
3780
|
+
medium: 500,
|
|
3781
|
+
semibold: 600,
|
|
3782
|
+
bold: 700,
|
|
3783
|
+
extrabold: 800,
|
|
3784
|
+
},
|
|
3785
|
+
lineHeight: {
|
|
3786
|
+
tight: '1.25',
|
|
3787
|
+
normal: '1.5',
|
|
3788
|
+
relaxed: '1.75',
|
|
3789
|
+
},
|
|
3790
|
+
},
|
|
3791
|
+
spacing: {
|
|
3792
|
+
xs: '0.25rem',
|
|
3793
|
+
sm: '0.5rem',
|
|
3794
|
+
md: '1rem',
|
|
3795
|
+
lg: '1.5rem',
|
|
3796
|
+
xl: '2rem',
|
|
3797
|
+
'2xl': '3rem',
|
|
3798
|
+
'3xl': '4rem',
|
|
3799
|
+
},
|
|
3800
|
+
layout: {
|
|
3801
|
+
containerMaxWidth: '1440px',
|
|
3802
|
+
gridGap: '1rem',
|
|
3803
|
+
cardPadding: '1.5rem',
|
|
3804
|
+
borderRadius: {
|
|
3805
|
+
sm: '0.25rem',
|
|
3806
|
+
md: '0.5rem',
|
|
3807
|
+
lg: '0.75rem',
|
|
3808
|
+
xl: '1rem',
|
|
3809
|
+
'2xl': '1.5rem',
|
|
3810
|
+
full: '9999px',
|
|
3811
|
+
},
|
|
3812
|
+
},
|
|
3813
|
+
components: {
|
|
3814
|
+
brokerCard: {
|
|
3815
|
+
width: '100%',
|
|
3816
|
+
height: '180px',
|
|
3817
|
+
logoSize: '64px',
|
|
3818
|
+
padding: '1.5rem',
|
|
3819
|
+
},
|
|
3820
|
+
statusIndicator: {
|
|
3821
|
+
size: '22px',
|
|
3822
|
+
glowIntensity: 0.9,
|
|
3823
|
+
},
|
|
3824
|
+
modal: {
|
|
3825
|
+
background: 'rgba(0, 0, 0, 0.95)',
|
|
3826
|
+
backdrop: 'rgba(0, 0, 0, 0.8)',
|
|
3827
|
+
},
|
|
3828
|
+
brokerCardModern: {
|
|
3829
|
+
width: '150px',
|
|
3830
|
+
height: '150px',
|
|
3831
|
+
padding: '16px',
|
|
3832
|
+
logoSize: '48px',
|
|
3833
|
+
statusSize: '22px',
|
|
3834
|
+
},
|
|
3835
|
+
connectButton: {
|
|
3836
|
+
width: '120px',
|
|
3837
|
+
height: '120px',
|
|
3838
|
+
},
|
|
3839
|
+
themeSwitcher: {
|
|
3840
|
+
indicatorSize: '24px',
|
|
3841
|
+
},
|
|
3842
|
+
},
|
|
3843
|
+
effects: {
|
|
3844
|
+
glassmorphism: {
|
|
3845
|
+
enabled: true,
|
|
3846
|
+
blur: '12px',
|
|
3847
|
+
opacity: 0.15,
|
|
3848
|
+
border: 'rgba(59, 130, 246, 0.3)',
|
|
3849
|
+
},
|
|
3850
|
+
animations: {
|
|
3851
|
+
enabled: true,
|
|
3852
|
+
duration: {
|
|
3853
|
+
fast: '150ms',
|
|
3854
|
+
normal: '300ms',
|
|
3855
|
+
slow: '500ms',
|
|
3856
|
+
},
|
|
3857
|
+
easing: {
|
|
3858
|
+
default: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
|
3859
|
+
smooth: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
|
|
3860
|
+
bounce: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)',
|
|
3861
|
+
},
|
|
3862
|
+
},
|
|
3863
|
+
shadows: {
|
|
3864
|
+
sm: '0 1px 2px rgba(0, 0, 0, 0.5)',
|
|
3865
|
+
md: '0 4px 6px rgba(0, 0, 0, 0.6)',
|
|
3866
|
+
lg: '0 10px 15px rgba(0, 0, 0, 0.7)',
|
|
3867
|
+
xl: '0 20px 25px rgba(0, 0, 0, 0.8)',
|
|
3868
|
+
card: '0px 4px 12px rgba(0, 0, 0, 0.6), 0 0 20px rgba(59, 130, 246, 0.2)',
|
|
3869
|
+
cardHover: '0px 4px 24px rgba(59, 130, 246, 0.3), 0 0 30px rgba(59, 130, 246, 0.25)',
|
|
3870
|
+
glow: '0 0 20px rgba(59, 130, 246, 0.8)',
|
|
3871
|
+
focus: '0 0 0 2px #3B82F6, 0 0 8px 2px rgba(59, 130, 246, 0.8)',
|
|
3872
|
+
},
|
|
3873
|
+
},
|
|
3520
3874
|
branding: {
|
|
3521
3875
|
primaryColor: '#3B82F6',
|
|
3522
3876
|
},
|
|
3877
|
+
glow: {
|
|
3878
|
+
primary: 'rgba(59, 130, 246, 0.4)',
|
|
3879
|
+
secondary: 'rgba(59, 130, 246, 0.6)',
|
|
3880
|
+
card: 'rgba(59, 130, 246, 0.2)',
|
|
3881
|
+
cardHover: 'rgba(59, 130, 246, 0.3)',
|
|
3882
|
+
button: 'rgba(59, 130, 246, 0.6)',
|
|
3883
|
+
focus: 'rgba(59, 130, 246, 0.8)',
|
|
3884
|
+
scrollbar: 'rgba(59, 130, 246, 0.4)',
|
|
3885
|
+
},
|
|
3886
|
+
gradients: {
|
|
3887
|
+
start: 'rgba(59, 130, 246, 0.08)',
|
|
3888
|
+
end: 'rgba(59, 130, 246, 0.03)',
|
|
3889
|
+
hoverStart: 'rgba(59, 130, 246, 0.15)',
|
|
3890
|
+
hoverEnd: 'rgba(59, 130, 246, 0.08)',
|
|
3891
|
+
},
|
|
3523
3892
|
};
|
|
3524
3893
|
// Purple theme
|
|
3525
3894
|
const purpleTheme = {
|
|
@@ -3576,9 +3945,135 @@ const purpleTheme = {
|
|
|
3576
3945
|
},
|
|
3577
3946
|
},
|
|
3578
3947
|
},
|
|
3948
|
+
typography: {
|
|
3949
|
+
fontFamily: {
|
|
3950
|
+
primary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
|
|
3951
|
+
secondary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
|
|
3952
|
+
},
|
|
3953
|
+
fontSize: {
|
|
3954
|
+
xs: '0.75rem',
|
|
3955
|
+
sm: '0.875rem',
|
|
3956
|
+
base: '1rem',
|
|
3957
|
+
lg: '1.125rem',
|
|
3958
|
+
xl: '1.25rem',
|
|
3959
|
+
'2xl': '1.5rem',
|
|
3960
|
+
'3xl': '1.875rem',
|
|
3961
|
+
'4xl': '2.25rem',
|
|
3962
|
+
},
|
|
3963
|
+
fontWeight: {
|
|
3964
|
+
normal: 400,
|
|
3965
|
+
medium: 500,
|
|
3966
|
+
semibold: 600,
|
|
3967
|
+
bold: 700,
|
|
3968
|
+
extrabold: 800,
|
|
3969
|
+
},
|
|
3970
|
+
lineHeight: {
|
|
3971
|
+
tight: '1.25',
|
|
3972
|
+
normal: '1.5',
|
|
3973
|
+
relaxed: '1.75',
|
|
3974
|
+
},
|
|
3975
|
+
},
|
|
3976
|
+
spacing: {
|
|
3977
|
+
xs: '0.25rem',
|
|
3978
|
+
sm: '0.5rem',
|
|
3979
|
+
md: '1rem',
|
|
3980
|
+
lg: '1.5rem',
|
|
3981
|
+
xl: '2rem',
|
|
3982
|
+
'2xl': '3rem',
|
|
3983
|
+
'3xl': '4rem',
|
|
3984
|
+
},
|
|
3985
|
+
layout: {
|
|
3986
|
+
containerMaxWidth: '1440px',
|
|
3987
|
+
gridGap: '1rem',
|
|
3988
|
+
cardPadding: '1.5rem',
|
|
3989
|
+
borderRadius: {
|
|
3990
|
+
sm: '0.25rem',
|
|
3991
|
+
md: '0.5rem',
|
|
3992
|
+
lg: '0.75rem',
|
|
3993
|
+
xl: '1rem',
|
|
3994
|
+
'2xl': '1.5rem',
|
|
3995
|
+
full: '9999px',
|
|
3996
|
+
},
|
|
3997
|
+
},
|
|
3998
|
+
components: {
|
|
3999
|
+
brokerCard: {
|
|
4000
|
+
width: '100%',
|
|
4001
|
+
height: '180px',
|
|
4002
|
+
logoSize: '64px',
|
|
4003
|
+
padding: '1.5rem',
|
|
4004
|
+
},
|
|
4005
|
+
statusIndicator: {
|
|
4006
|
+
size: '22px',
|
|
4007
|
+
glowIntensity: 0.9,
|
|
4008
|
+
},
|
|
4009
|
+
modal: {
|
|
4010
|
+
background: 'rgba(0, 0, 0, 0.95)',
|
|
4011
|
+
backdrop: 'rgba(0, 0, 0, 0.8)',
|
|
4012
|
+
},
|
|
4013
|
+
brokerCardModern: {
|
|
4014
|
+
width: '150px',
|
|
4015
|
+
height: '150px',
|
|
4016
|
+
padding: '16px',
|
|
4017
|
+
logoSize: '48px',
|
|
4018
|
+
statusSize: '22px',
|
|
4019
|
+
},
|
|
4020
|
+
connectButton: {
|
|
4021
|
+
width: '120px',
|
|
4022
|
+
height: '120px',
|
|
4023
|
+
},
|
|
4024
|
+
themeSwitcher: {
|
|
4025
|
+
indicatorSize: '24px',
|
|
4026
|
+
},
|
|
4027
|
+
},
|
|
4028
|
+
effects: {
|
|
4029
|
+
glassmorphism: {
|
|
4030
|
+
enabled: true,
|
|
4031
|
+
blur: '12px',
|
|
4032
|
+
opacity: 0.15,
|
|
4033
|
+
border: 'rgba(168, 85, 247, 0.3)',
|
|
4034
|
+
},
|
|
4035
|
+
animations: {
|
|
4036
|
+
enabled: true,
|
|
4037
|
+
duration: {
|
|
4038
|
+
fast: '150ms',
|
|
4039
|
+
normal: '300ms',
|
|
4040
|
+
slow: '500ms',
|
|
4041
|
+
},
|
|
4042
|
+
easing: {
|
|
4043
|
+
default: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
|
4044
|
+
smooth: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
|
|
4045
|
+
bounce: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)',
|
|
4046
|
+
},
|
|
4047
|
+
},
|
|
4048
|
+
shadows: {
|
|
4049
|
+
sm: '0 1px 2px rgba(0, 0, 0, 0.5)',
|
|
4050
|
+
md: '0 4px 6px rgba(0, 0, 0, 0.6)',
|
|
4051
|
+
lg: '0 10px 15px rgba(0, 0, 0, 0.7)',
|
|
4052
|
+
xl: '0 20px 25px rgba(0, 0, 0, 0.8)',
|
|
4053
|
+
card: '0px 4px 12px rgba(0, 0, 0, 0.6), 0 0 20px rgba(168, 85, 247, 0.2)',
|
|
4054
|
+
cardHover: '0px 4px 24px rgba(168, 85, 247, 0.3), 0 0 30px rgba(168, 85, 247, 0.25)',
|
|
4055
|
+
glow: '0 0 20px rgba(168, 85, 247, 0.8)',
|
|
4056
|
+
focus: '0 0 0 2px #A855F7, 0 0 8px 2px rgba(168, 85, 247, 0.8)',
|
|
4057
|
+
},
|
|
4058
|
+
},
|
|
3579
4059
|
branding: {
|
|
3580
4060
|
primaryColor: '#A855F7',
|
|
3581
4061
|
},
|
|
4062
|
+
glow: {
|
|
4063
|
+
primary: 'rgba(168, 85, 247, 0.4)',
|
|
4064
|
+
secondary: 'rgba(168, 85, 247, 0.6)',
|
|
4065
|
+
card: 'rgba(168, 85, 247, 0.2)',
|
|
4066
|
+
cardHover: 'rgba(168, 85, 247, 0.3)',
|
|
4067
|
+
button: 'rgba(168, 85, 247, 0.6)',
|
|
4068
|
+
focus: 'rgba(168, 85, 247, 0.8)',
|
|
4069
|
+
scrollbar: 'rgba(168, 85, 247, 0.4)',
|
|
4070
|
+
},
|
|
4071
|
+
gradients: {
|
|
4072
|
+
start: 'rgba(168, 85, 247, 0.08)',
|
|
4073
|
+
end: 'rgba(168, 85, 247, 0.03)',
|
|
4074
|
+
hoverStart: 'rgba(168, 85, 247, 0.15)',
|
|
4075
|
+
hoverEnd: 'rgba(168, 85, 247, 0.08)',
|
|
4076
|
+
},
|
|
3582
4077
|
};
|
|
3583
4078
|
// Green theme
|
|
3584
4079
|
const greenTheme = {
|
|
@@ -3635,9 +4130,135 @@ const greenTheme = {
|
|
|
3635
4130
|
},
|
|
3636
4131
|
},
|
|
3637
4132
|
},
|
|
4133
|
+
typography: {
|
|
4134
|
+
fontFamily: {
|
|
4135
|
+
primary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
|
|
4136
|
+
secondary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
|
|
4137
|
+
},
|
|
4138
|
+
fontSize: {
|
|
4139
|
+
xs: '0.75rem',
|
|
4140
|
+
sm: '0.875rem',
|
|
4141
|
+
base: '1rem',
|
|
4142
|
+
lg: '1.125rem',
|
|
4143
|
+
xl: '1.25rem',
|
|
4144
|
+
'2xl': '1.5rem',
|
|
4145
|
+
'3xl': '1.875rem',
|
|
4146
|
+
'4xl': '2.25rem',
|
|
4147
|
+
},
|
|
4148
|
+
fontWeight: {
|
|
4149
|
+
normal: 400,
|
|
4150
|
+
medium: 500,
|
|
4151
|
+
semibold: 600,
|
|
4152
|
+
bold: 700,
|
|
4153
|
+
extrabold: 800,
|
|
4154
|
+
},
|
|
4155
|
+
lineHeight: {
|
|
4156
|
+
tight: '1.25',
|
|
4157
|
+
normal: '1.5',
|
|
4158
|
+
relaxed: '1.75',
|
|
4159
|
+
},
|
|
4160
|
+
},
|
|
4161
|
+
spacing: {
|
|
4162
|
+
xs: '0.25rem',
|
|
4163
|
+
sm: '0.5rem',
|
|
4164
|
+
md: '1rem',
|
|
4165
|
+
lg: '1.5rem',
|
|
4166
|
+
xl: '2rem',
|
|
4167
|
+
'2xl': '3rem',
|
|
4168
|
+
'3xl': '4rem',
|
|
4169
|
+
},
|
|
4170
|
+
layout: {
|
|
4171
|
+
containerMaxWidth: '1440px',
|
|
4172
|
+
gridGap: '1rem',
|
|
4173
|
+
cardPadding: '1.5rem',
|
|
4174
|
+
borderRadius: {
|
|
4175
|
+
sm: '0.25rem',
|
|
4176
|
+
md: '0.5rem',
|
|
4177
|
+
lg: '0.75rem',
|
|
4178
|
+
xl: '1rem',
|
|
4179
|
+
'2xl': '1.5rem',
|
|
4180
|
+
full: '9999px',
|
|
4181
|
+
},
|
|
4182
|
+
},
|
|
4183
|
+
components: {
|
|
4184
|
+
brokerCard: {
|
|
4185
|
+
width: '100%',
|
|
4186
|
+
height: '180px',
|
|
4187
|
+
logoSize: '64px',
|
|
4188
|
+
padding: '1.5rem',
|
|
4189
|
+
},
|
|
4190
|
+
statusIndicator: {
|
|
4191
|
+
size: '22px',
|
|
4192
|
+
glowIntensity: 0.9,
|
|
4193
|
+
},
|
|
4194
|
+
modal: {
|
|
4195
|
+
background: 'rgba(0, 0, 0, 0.95)',
|
|
4196
|
+
backdrop: 'rgba(0, 0, 0, 0.8)',
|
|
4197
|
+
},
|
|
4198
|
+
brokerCardModern: {
|
|
4199
|
+
width: '150px',
|
|
4200
|
+
height: '150px',
|
|
4201
|
+
padding: '16px',
|
|
4202
|
+
logoSize: '48px',
|
|
4203
|
+
statusSize: '22px',
|
|
4204
|
+
},
|
|
4205
|
+
connectButton: {
|
|
4206
|
+
width: '120px',
|
|
4207
|
+
height: '120px',
|
|
4208
|
+
},
|
|
4209
|
+
themeSwitcher: {
|
|
4210
|
+
indicatorSize: '24px',
|
|
4211
|
+
},
|
|
4212
|
+
},
|
|
4213
|
+
effects: {
|
|
4214
|
+
glassmorphism: {
|
|
4215
|
+
enabled: true,
|
|
4216
|
+
blur: '12px',
|
|
4217
|
+
opacity: 0.15,
|
|
4218
|
+
border: 'rgba(34, 197, 94, 0.3)',
|
|
4219
|
+
},
|
|
4220
|
+
animations: {
|
|
4221
|
+
enabled: true,
|
|
4222
|
+
duration: {
|
|
4223
|
+
fast: '150ms',
|
|
4224
|
+
normal: '300ms',
|
|
4225
|
+
slow: '500ms',
|
|
4226
|
+
},
|
|
4227
|
+
easing: {
|
|
4228
|
+
default: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
|
4229
|
+
smooth: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
|
|
4230
|
+
bounce: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)',
|
|
4231
|
+
},
|
|
4232
|
+
},
|
|
4233
|
+
shadows: {
|
|
4234
|
+
sm: '0 1px 2px rgba(0, 0, 0, 0.5)',
|
|
4235
|
+
md: '0 4px 6px rgba(0, 0, 0, 0.6)',
|
|
4236
|
+
lg: '0 10px 15px rgba(0, 0, 0, 0.7)',
|
|
4237
|
+
xl: '0 20px 25px rgba(0, 0, 0, 0.8)',
|
|
4238
|
+
card: '0px 4px 12px rgba(0, 0, 0, 0.6), 0 0 20px rgba(34, 197, 94, 0.2)',
|
|
4239
|
+
cardHover: '0px 4px 24px rgba(34, 197, 94, 0.3), 0 0 30px rgba(34, 197, 94, 0.25)',
|
|
4240
|
+
glow: '0 0 20px rgba(34, 197, 94, 0.8)',
|
|
4241
|
+
focus: '0 0 0 2px #22C55E, 0 0 8px 2px rgba(34, 197, 94, 0.8)',
|
|
4242
|
+
},
|
|
4243
|
+
},
|
|
3638
4244
|
branding: {
|
|
3639
4245
|
primaryColor: '#22C55E',
|
|
3640
4246
|
},
|
|
4247
|
+
glow: {
|
|
4248
|
+
primary: 'rgba(34, 197, 94, 0.4)',
|
|
4249
|
+
secondary: 'rgba(34, 197, 94, 0.6)',
|
|
4250
|
+
card: 'rgba(34, 197, 94, 0.2)',
|
|
4251
|
+
cardHover: 'rgba(34, 197, 94, 0.3)',
|
|
4252
|
+
button: 'rgba(34, 197, 94, 0.6)',
|
|
4253
|
+
focus: 'rgba(34, 197, 94, 0.8)',
|
|
4254
|
+
scrollbar: 'rgba(34, 197, 94, 0.4)',
|
|
4255
|
+
},
|
|
4256
|
+
gradients: {
|
|
4257
|
+
start: 'rgba(34, 197, 94, 0.08)',
|
|
4258
|
+
end: 'rgba(34, 197, 94, 0.03)',
|
|
4259
|
+
hoverStart: 'rgba(34, 197, 94, 0.15)',
|
|
4260
|
+
hoverEnd: 'rgba(34, 197, 94, 0.08)',
|
|
4261
|
+
},
|
|
3641
4262
|
};
|
|
3642
4263
|
// Orange theme
|
|
3643
4264
|
const orangeTheme = {
|
|
@@ -3694,9 +4315,325 @@ const orangeTheme = {
|
|
|
3694
4315
|
},
|
|
3695
4316
|
},
|
|
3696
4317
|
},
|
|
4318
|
+
typography: {
|
|
4319
|
+
fontFamily: {
|
|
4320
|
+
primary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
|
|
4321
|
+
secondary: 'Orbitron, Futura, Inter, system-ui, sans-serif',
|
|
4322
|
+
},
|
|
4323
|
+
fontSize: {
|
|
4324
|
+
xs: '0.75rem',
|
|
4325
|
+
sm: '0.875rem',
|
|
4326
|
+
base: '1rem',
|
|
4327
|
+
lg: '1.125rem',
|
|
4328
|
+
xl: '1.25rem',
|
|
4329
|
+
'2xl': '1.5rem',
|
|
4330
|
+
'3xl': '1.875rem',
|
|
4331
|
+
'4xl': '2.25rem',
|
|
4332
|
+
},
|
|
4333
|
+
fontWeight: {
|
|
4334
|
+
normal: 400,
|
|
4335
|
+
medium: 500,
|
|
4336
|
+
semibold: 600,
|
|
4337
|
+
bold: 700,
|
|
4338
|
+
extrabold: 800,
|
|
4339
|
+
},
|
|
4340
|
+
lineHeight: {
|
|
4341
|
+
tight: '1.25',
|
|
4342
|
+
normal: '1.5',
|
|
4343
|
+
relaxed: '1.75',
|
|
4344
|
+
},
|
|
4345
|
+
},
|
|
4346
|
+
spacing: {
|
|
4347
|
+
xs: '0.25rem',
|
|
4348
|
+
sm: '0.5rem',
|
|
4349
|
+
md: '1rem',
|
|
4350
|
+
lg: '1.5rem',
|
|
4351
|
+
xl: '2rem',
|
|
4352
|
+
'2xl': '3rem',
|
|
4353
|
+
'3xl': '4rem',
|
|
4354
|
+
},
|
|
4355
|
+
layout: {
|
|
4356
|
+
containerMaxWidth: '1440px',
|
|
4357
|
+
gridGap: '1rem',
|
|
4358
|
+
cardPadding: '1.5rem',
|
|
4359
|
+
borderRadius: {
|
|
4360
|
+
sm: '0.25rem',
|
|
4361
|
+
md: '0.5rem',
|
|
4362
|
+
lg: '0.75rem',
|
|
4363
|
+
xl: '1rem',
|
|
4364
|
+
'2xl': '1.5rem',
|
|
4365
|
+
full: '9999px',
|
|
4366
|
+
},
|
|
4367
|
+
},
|
|
4368
|
+
components: {
|
|
4369
|
+
brokerCard: {
|
|
4370
|
+
width: '100%',
|
|
4371
|
+
height: '180px',
|
|
4372
|
+
logoSize: '64px',
|
|
4373
|
+
padding: '1.5rem',
|
|
4374
|
+
},
|
|
4375
|
+
statusIndicator: {
|
|
4376
|
+
size: '22px',
|
|
4377
|
+
glowIntensity: 0.9,
|
|
4378
|
+
},
|
|
4379
|
+
modal: {
|
|
4380
|
+
background: 'rgba(0, 0, 0, 0.95)',
|
|
4381
|
+
backdrop: 'rgba(0, 0, 0, 0.8)',
|
|
4382
|
+
},
|
|
4383
|
+
brokerCardModern: {
|
|
4384
|
+
width: '150px',
|
|
4385
|
+
height: '150px',
|
|
4386
|
+
padding: '16px',
|
|
4387
|
+
logoSize: '48px',
|
|
4388
|
+
statusSize: '22px',
|
|
4389
|
+
},
|
|
4390
|
+
connectButton: {
|
|
4391
|
+
width: '120px',
|
|
4392
|
+
height: '120px',
|
|
4393
|
+
},
|
|
4394
|
+
themeSwitcher: {
|
|
4395
|
+
indicatorSize: '24px',
|
|
4396
|
+
},
|
|
4397
|
+
},
|
|
4398
|
+
effects: {
|
|
4399
|
+
glassmorphism: {
|
|
4400
|
+
enabled: true,
|
|
4401
|
+
blur: '12px',
|
|
4402
|
+
opacity: 0.15,
|
|
4403
|
+
border: 'rgba(249, 115, 22, 0.3)',
|
|
4404
|
+
},
|
|
4405
|
+
animations: {
|
|
4406
|
+
enabled: true,
|
|
4407
|
+
duration: {
|
|
4408
|
+
fast: '150ms',
|
|
4409
|
+
normal: '300ms',
|
|
4410
|
+
slow: '500ms',
|
|
4411
|
+
},
|
|
4412
|
+
easing: {
|
|
4413
|
+
default: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
|
4414
|
+
smooth: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
|
|
4415
|
+
bounce: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)',
|
|
4416
|
+
},
|
|
4417
|
+
},
|
|
4418
|
+
shadows: {
|
|
4419
|
+
sm: '0 1px 2px rgba(0, 0, 0, 0.5)',
|
|
4420
|
+
md: '0 4px 6px rgba(0, 0, 0, 0.6)',
|
|
4421
|
+
lg: '0 10px 15px rgba(0, 0, 0, 0.7)',
|
|
4422
|
+
xl: '0 20px 25px rgba(0, 0, 0, 0.8)',
|
|
4423
|
+
card: '0px 4px 12px rgba(0, 0, 0, 0.6), 0 0 20px rgba(249, 115, 22, 0.2)',
|
|
4424
|
+
cardHover: '0px 4px 24px rgba(249, 115, 22, 0.3), 0 0 30px rgba(249, 115, 22, 0.25)',
|
|
4425
|
+
glow: '0 0 20px rgba(249, 115, 22, 0.8)',
|
|
4426
|
+
focus: '0 0 0 2px #F97316, 0 0 8px 2px rgba(249, 115, 22, 0.8)',
|
|
4427
|
+
},
|
|
4428
|
+
},
|
|
3697
4429
|
branding: {
|
|
3698
4430
|
primaryColor: '#F97316',
|
|
3699
4431
|
},
|
|
4432
|
+
glow: {
|
|
4433
|
+
primary: 'rgba(249, 115, 22, 0.4)',
|
|
4434
|
+
secondary: 'rgba(249, 115, 22, 0.6)',
|
|
4435
|
+
card: 'rgba(249, 115, 22, 0.2)',
|
|
4436
|
+
cardHover: 'rgba(249, 115, 22, 0.3)',
|
|
4437
|
+
button: 'rgba(249, 115, 22, 0.6)',
|
|
4438
|
+
focus: 'rgba(249, 115, 22, 0.8)',
|
|
4439
|
+
scrollbar: 'rgba(249, 115, 22, 0.4)',
|
|
4440
|
+
},
|
|
4441
|
+
gradients: {
|
|
4442
|
+
start: 'rgba(249, 115, 22, 0.08)',
|
|
4443
|
+
end: 'rgba(249, 115, 22, 0.03)',
|
|
4444
|
+
hoverStart: 'rgba(249, 115, 22, 0.15)',
|
|
4445
|
+
hoverEnd: 'rgba(249, 115, 22, 0.08)',
|
|
4446
|
+
},
|
|
4447
|
+
};
|
|
4448
|
+
// StockAlgos theme - Clean professional theme matching StockAlgos website
|
|
4449
|
+
const stockAlgosTheme = {
|
|
4450
|
+
mode: 'light', // Light mode like StockAlgos website
|
|
4451
|
+
colors: {
|
|
4452
|
+
background: {
|
|
4453
|
+
primary: '#FFFFFF', // Clean white background
|
|
4454
|
+
secondary: '#FFFFFF', // Also white for consistency
|
|
4455
|
+
tertiary: '#F8FAFC', // Very light gray for subtle elevation
|
|
4456
|
+
accent: 'rgba(79, 70, 229, 0.05)', // Very subtle blue accent
|
|
4457
|
+
glass: '#FFFFFF', // Pure white, no transparency
|
|
4458
|
+
},
|
|
4459
|
+
status: {
|
|
4460
|
+
connected: '#10B981', // Green for positive/connected
|
|
4461
|
+
disconnected: '#EF4444', // Red for negative/disconnected
|
|
4462
|
+
warning: '#F59E0B', // Amber for warnings
|
|
4463
|
+
pending: '#6366F1', // Indigo for pending states
|
|
4464
|
+
error: '#EF4444', // Red for errors
|
|
4465
|
+
success: '#10B981', // Green for success
|
|
4466
|
+
},
|
|
4467
|
+
text: {
|
|
4468
|
+
primary: '#111827', // Very dark text for maximum contrast
|
|
4469
|
+
secondary: '#374151', // Dark gray for secondary text
|
|
4470
|
+
muted: '#6B7280', // Medium gray for muted text
|
|
4471
|
+
inverse: '#FFFFFF', // White for text on dark backgrounds
|
|
4472
|
+
},
|
|
4473
|
+
border: {
|
|
4474
|
+
primary: '#E5E7EB', // Light gray border
|
|
4475
|
+
secondary: '#F3F4F6', // Very light gray border
|
|
4476
|
+
hover: '#D1D5DB', // Slightly darker on hover
|
|
4477
|
+
focus: '#4F46E5', // Blue focus border
|
|
4478
|
+
accent: '#4F46E5', // Blue accent border
|
|
4479
|
+
},
|
|
4480
|
+
input: {
|
|
4481
|
+
background: '#FFFFFF', // White input background
|
|
4482
|
+
border: '#D1D5DB', // Slightly more visible light gray border
|
|
4483
|
+
borderFocus: '#4F46E5', // Blue focus border
|
|
4484
|
+
text: '#111827', // Darker text for better contrast
|
|
4485
|
+
placeholder: '#6B7280', // Darker placeholder for visibility
|
|
4486
|
+
},
|
|
4487
|
+
button: {
|
|
4488
|
+
primary: {
|
|
4489
|
+
background: '#4F46E5', // Blue primary button
|
|
4490
|
+
text: '#FFFFFF', // White text
|
|
4491
|
+
hover: '#4338CA', // Darker blue on hover
|
|
4492
|
+
active: '#3730A3', // Even darker on active
|
|
4493
|
+
},
|
|
4494
|
+
secondary: {
|
|
4495
|
+
background: '#FFFFFF', // White background
|
|
4496
|
+
text: '#4F46E5', // Blue text
|
|
4497
|
+
border: '#E5E7EB', // Light gray border
|
|
4498
|
+
hover: '#F8FAFC', // Very light gray on hover
|
|
4499
|
+
active: '#F1F5F9', // Light gray on active
|
|
4500
|
+
},
|
|
4501
|
+
},
|
|
4502
|
+
},
|
|
4503
|
+
typography: {
|
|
4504
|
+
fontFamily: {
|
|
4505
|
+
primary: 'Inter, system-ui, -apple-system, sans-serif', // Clean, modern font like StockAlgos
|
|
4506
|
+
secondary: 'Inter, system-ui, -apple-system, sans-serif',
|
|
4507
|
+
},
|
|
4508
|
+
fontSize: {
|
|
4509
|
+
xs: '0.75rem', // 12px
|
|
4510
|
+
sm: '0.875rem', // 14px
|
|
4511
|
+
base: '1rem', // 16px
|
|
4512
|
+
lg: '1.125rem', // 18px
|
|
4513
|
+
xl: '1.25rem', // 20px
|
|
4514
|
+
'2xl': '1.5rem', // 24px
|
|
4515
|
+
'3xl': '1.875rem', // 30px
|
|
4516
|
+
'4xl': '2.25rem', // 36px
|
|
4517
|
+
},
|
|
4518
|
+
fontWeight: {
|
|
4519
|
+
normal: 400,
|
|
4520
|
+
medium: 500,
|
|
4521
|
+
semibold: 600,
|
|
4522
|
+
bold: 700,
|
|
4523
|
+
extrabold: 800,
|
|
4524
|
+
},
|
|
4525
|
+
lineHeight: {
|
|
4526
|
+
tight: '1.25',
|
|
4527
|
+
normal: '1.5',
|
|
4528
|
+
relaxed: '1.75',
|
|
4529
|
+
},
|
|
4530
|
+
},
|
|
4531
|
+
spacing: {
|
|
4532
|
+
xs: '0.25rem', // 4px
|
|
4533
|
+
sm: '0.5rem', // 8px
|
|
4534
|
+
md: '1rem', // 16px
|
|
4535
|
+
lg: '1.5rem', // 24px
|
|
4536
|
+
xl: '2rem', // 32px
|
|
4537
|
+
'2xl': '3rem', // 48px
|
|
4538
|
+
'3xl': '4rem', // 64px
|
|
4539
|
+
},
|
|
4540
|
+
layout: {
|
|
4541
|
+
containerMaxWidth: '1440px',
|
|
4542
|
+
gridGap: '1rem',
|
|
4543
|
+
cardPadding: '1.5rem',
|
|
4544
|
+
borderRadius: {
|
|
4545
|
+
sm: '0.25rem', // 4px
|
|
4546
|
+
md: '0.5rem', // 8px
|
|
4547
|
+
lg: '0.75rem', // 12px
|
|
4548
|
+
xl: '1rem', // 16px
|
|
4549
|
+
'2xl': '1.5rem', // 24px
|
|
4550
|
+
full: '9999px',
|
|
4551
|
+
},
|
|
4552
|
+
},
|
|
4553
|
+
components: {
|
|
4554
|
+
brokerCard: {
|
|
4555
|
+
width: '100%',
|
|
4556
|
+
height: '180px',
|
|
4557
|
+
logoSize: '64px',
|
|
4558
|
+
padding: '1.5rem',
|
|
4559
|
+
},
|
|
4560
|
+
statusIndicator: {
|
|
4561
|
+
size: '22px',
|
|
4562
|
+
glowIntensity: 0.1, // Minimal glow for clean look
|
|
4563
|
+
},
|
|
4564
|
+
modal: {
|
|
4565
|
+
background: '#FFFFFF', // Pure white modal background
|
|
4566
|
+
backdrop: 'rgba(0, 0, 0, 0.4)', // Lighter backdrop
|
|
4567
|
+
},
|
|
4568
|
+
brokerCardModern: {
|
|
4569
|
+
width: '150px',
|
|
4570
|
+
height: '150px',
|
|
4571
|
+
padding: '16px',
|
|
4572
|
+
logoSize: '48px',
|
|
4573
|
+
statusSize: '22px',
|
|
4574
|
+
},
|
|
4575
|
+
connectButton: {
|
|
4576
|
+
width: '120px',
|
|
4577
|
+
height: '120px',
|
|
4578
|
+
},
|
|
4579
|
+
themeSwitcher: {
|
|
4580
|
+
indicatorSize: '24px',
|
|
4581
|
+
},
|
|
4582
|
+
},
|
|
4583
|
+
effects: {
|
|
4584
|
+
glassmorphism: {
|
|
4585
|
+
enabled: false, // Disable glass effects for clean look
|
|
4586
|
+
blur: '0px',
|
|
4587
|
+
opacity: 0,
|
|
4588
|
+
border: 'rgba(0, 0, 0, 0.1)',
|
|
4589
|
+
},
|
|
4590
|
+
animations: {
|
|
4591
|
+
enabled: true,
|
|
4592
|
+
duration: {
|
|
4593
|
+
fast: '150ms',
|
|
4594
|
+
normal: '200ms', // Faster, more subtle animations
|
|
4595
|
+
slow: '300ms',
|
|
4596
|
+
},
|
|
4597
|
+
easing: {
|
|
4598
|
+
default: 'cubic-bezier(0.4, 0, 0.2, 1)',
|
|
4599
|
+
smooth: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',
|
|
4600
|
+
bounce: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)',
|
|
4601
|
+
},
|
|
4602
|
+
},
|
|
4603
|
+
shadows: {
|
|
4604
|
+
sm: '0 1px 2px rgba(0, 0, 0, 0.05)', // Very subtle shadows
|
|
4605
|
+
md: '0 4px 6px rgba(0, 0, 0, 0.07)',
|
|
4606
|
+
lg: '0 10px 15px rgba(0, 0, 0, 0.1)',
|
|
4607
|
+
xl: '0 20px 25px rgba(0, 0, 0, 0.1)',
|
|
4608
|
+
card: '0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06)', // Clean card shadow
|
|
4609
|
+
cardHover: '0 4px 6px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.06)', // Subtle hover shadow
|
|
4610
|
+
glow: '0 0 0px transparent', // No glow effects
|
|
4611
|
+
focus: '0 0 0 3px rgba(79, 70, 229, 0.1)', // Subtle focus ring
|
|
4612
|
+
},
|
|
4613
|
+
},
|
|
4614
|
+
branding: {
|
|
4615
|
+
logo: '/stockalgos-logo.png', // Custom logo path
|
|
4616
|
+
companyName: 'StockAlgos', // Company name
|
|
4617
|
+
favicon: '/stockalgos-favicon.ico', // Custom favicon
|
|
4618
|
+
primaryColor: '#4F46E5', // Indigo brand color
|
|
4619
|
+
},
|
|
4620
|
+
// Minimal glow effects
|
|
4621
|
+
glow: {
|
|
4622
|
+
primary: 'transparent',
|
|
4623
|
+
secondary: 'transparent',
|
|
4624
|
+
card: 'transparent',
|
|
4625
|
+
cardHover: 'rgba(79, 70, 229, 0.05)', // Very subtle
|
|
4626
|
+
button: 'transparent',
|
|
4627
|
+
focus: 'rgba(79, 70, 229, 0.1)',
|
|
4628
|
+
scrollbar: 'transparent',
|
|
4629
|
+
},
|
|
4630
|
+
// Minimal gradients
|
|
4631
|
+
gradients: {
|
|
4632
|
+
start: 'rgba(79, 70, 229, 0.02)',
|
|
4633
|
+
end: 'rgba(79, 70, 229, 0.01)',
|
|
4634
|
+
hoverStart: 'rgba(79, 70, 229, 0.05)',
|
|
4635
|
+
hoverEnd: 'rgba(79, 70, 229, 0.02)',
|
|
4636
|
+
},
|
|
3700
4637
|
};
|
|
3701
4638
|
// Theme preset mapping
|
|
3702
4639
|
const portalThemePresets = {
|
|
@@ -3706,6 +4643,7 @@ const portalThemePresets = {
|
|
|
3706
4643
|
purple: purpleTheme,
|
|
3707
4644
|
green: greenTheme,
|
|
3708
4645
|
orange: orangeTheme,
|
|
4646
|
+
stockAlgos: stockAlgosTheme,
|
|
3709
4647
|
};
|
|
3710
4648
|
|
|
3711
4649
|
/**
|
|
@@ -3781,17 +4719,36 @@ function getThemePreset(preset) {
|
|
|
3781
4719
|
*/
|
|
3782
4720
|
function validateCustomTheme(theme) {
|
|
3783
4721
|
try {
|
|
3784
|
-
//
|
|
3785
|
-
if (
|
|
4722
|
+
// Only validate what's provided - everything else gets defaults
|
|
4723
|
+
if (theme.mode && !['dark', 'light', 'auto'].includes(theme.mode)) {
|
|
3786
4724
|
return false;
|
|
3787
4725
|
}
|
|
3788
|
-
|
|
3789
|
-
|
|
4726
|
+
// If colors are provided, validate the structure
|
|
4727
|
+
if (theme.colors) {
|
|
4728
|
+
// Check that any provided color sections have valid structure
|
|
4729
|
+
const colorSections = ['background', 'status', 'text', 'border', 'input', 'button'];
|
|
4730
|
+
for (const section of colorSections) {
|
|
4731
|
+
const colorSection = theme.colors[section];
|
|
4732
|
+
if (colorSection && typeof colorSection !== 'object') {
|
|
4733
|
+
return false;
|
|
4734
|
+
}
|
|
4735
|
+
}
|
|
3790
4736
|
}
|
|
3791
|
-
//
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
4737
|
+
// If typography is provided, validate structure
|
|
4738
|
+
if (theme.typography) {
|
|
4739
|
+
if (theme.typography.fontSize && typeof theme.typography.fontSize !== 'object') {
|
|
4740
|
+
return false;
|
|
4741
|
+
}
|
|
4742
|
+
if (theme.typography.fontWeight && typeof theme.typography.fontWeight !== 'object') {
|
|
4743
|
+
return false;
|
|
4744
|
+
}
|
|
4745
|
+
}
|
|
4746
|
+
// If effects are provided, validate structure
|
|
4747
|
+
if (theme.effects) {
|
|
4748
|
+
if (theme.effects.animations && typeof theme.effects.animations !== 'object') {
|
|
4749
|
+
return false;
|
|
4750
|
+
}
|
|
4751
|
+
if (theme.effects.shadows && typeof theme.effects.shadows !== 'object') {
|
|
3795
4752
|
return false;
|
|
3796
4753
|
}
|
|
3797
4754
|
}
|
|
@@ -3823,12 +4780,14 @@ function createCustomThemeFromPreset(preset, modifications) {
|
|
|
3823
4780
|
/**
|
|
3824
4781
|
* Broker filtering utility functions
|
|
3825
4782
|
*/
|
|
3826
|
-
// Supported broker names and their corresponding IDs
|
|
4783
|
+
// Supported broker names and their corresponding IDs (including aliases)
|
|
3827
4784
|
const SUPPORTED_BROKERS = {
|
|
3828
4785
|
'alpaca': 'alpaca',
|
|
3829
4786
|
'robinhood': 'robinhood',
|
|
3830
4787
|
'tasty_trade': 'tasty_trade',
|
|
3831
|
-
'ninja_trader': 'ninja_trader'
|
|
4788
|
+
'ninja_trader': 'ninja_trader',
|
|
4789
|
+
'tradovate': 'tradovate', // Alias for ninja_trader
|
|
4790
|
+
'interactive_brokers': 'interactive_brokers',
|
|
3832
4791
|
};
|
|
3833
4792
|
/**
|
|
3834
4793
|
* Convert broker names to broker IDs, filtering out unsupported ones
|
|
@@ -3968,6 +4927,13 @@ class FinaticConnect extends EventEmitter {
|
|
|
3968
4927
|
this.userToken?.refreshToken &&
|
|
3969
4928
|
this.userToken?.user_id);
|
|
3970
4929
|
}
|
|
4930
|
+
/**
|
|
4931
|
+
* Check if the client is authenticated (alias for isAuthed for consistency)
|
|
4932
|
+
* @returns True if authenticated, false otherwise
|
|
4933
|
+
*/
|
|
4934
|
+
is_authenticated() {
|
|
4935
|
+
return this.isAuthed();
|
|
4936
|
+
}
|
|
3971
4937
|
/**
|
|
3972
4938
|
* Get user's orders with pagination and optional filtering
|
|
3973
4939
|
* @param params - Query parameters including page, perPage, and filters
|
|
@@ -4011,20 +4977,18 @@ class FinaticConnect extends EventEmitter {
|
|
|
4011
4977
|
return this.getAccountsPage(page, perPage, filter);
|
|
4012
4978
|
}
|
|
4013
4979
|
/**
|
|
4014
|
-
*
|
|
4980
|
+
* Get user's balances with pagination and optional filtering
|
|
4981
|
+
* @param params - Query parameters including page, perPage, and filters
|
|
4982
|
+
* @returns Promise with paginated result that supports navigation
|
|
4015
4983
|
*/
|
|
4016
|
-
async
|
|
4017
|
-
if (!this.
|
|
4018
|
-
|
|
4019
|
-
}
|
|
4020
|
-
try {
|
|
4021
|
-
await this.apiClient.revokeToken(this.userToken.accessToken);
|
|
4022
|
-
this.userToken = null;
|
|
4023
|
-
}
|
|
4024
|
-
catch (error) {
|
|
4025
|
-
this.emit('error', error);
|
|
4026
|
-
throw error;
|
|
4984
|
+
async getBalances(params) {
|
|
4985
|
+
if (!this.isAuthed()) {
|
|
4986
|
+
throw new AuthenticationError('User is not authenticated');
|
|
4027
4987
|
}
|
|
4988
|
+
const page = params?.page || 1;
|
|
4989
|
+
const perPage = params?.perPage || 100;
|
|
4990
|
+
const filter = params?.filter;
|
|
4991
|
+
return this.getBalancesPage(page, perPage, filter);
|
|
4028
4992
|
}
|
|
4029
4993
|
/**
|
|
4030
4994
|
* Initialize the Finatic Connect SDK
|
|
@@ -4113,9 +5077,33 @@ class FinaticConnect extends EventEmitter {
|
|
|
4113
5077
|
async setUserId(userId) {
|
|
4114
5078
|
await this.initializeWithUser(userId);
|
|
4115
5079
|
}
|
|
5080
|
+
/**
|
|
5081
|
+
* Get the user and tokens for a completed session
|
|
5082
|
+
* @returns Promise with user information and tokens
|
|
5083
|
+
*/
|
|
5084
|
+
async getSessionUser() {
|
|
5085
|
+
if (!this.isAuthed()) {
|
|
5086
|
+
throw new AuthenticationError('User is not authenticated');
|
|
5087
|
+
}
|
|
5088
|
+
if (!this.userToken) {
|
|
5089
|
+
throw new AuthenticationError('No user token available');
|
|
5090
|
+
}
|
|
5091
|
+
return {
|
|
5092
|
+
user_id: this.userToken.userId,
|
|
5093
|
+
access_token: this.userToken.accessToken,
|
|
5094
|
+
refresh_token: this.userToken.refreshToken,
|
|
5095
|
+
expires_in: this.userToken.expiresIn,
|
|
5096
|
+
token_type: this.userToken.tokenType,
|
|
5097
|
+
scope: this.userToken.scope,
|
|
5098
|
+
company_id: this.companyId,
|
|
5099
|
+
};
|
|
5100
|
+
}
|
|
4116
5101
|
async initializeWithUser(userId) {
|
|
4117
5102
|
try {
|
|
4118
|
-
|
|
5103
|
+
if (!this.sessionId) {
|
|
5104
|
+
throw new SessionError('Session not initialized');
|
|
5105
|
+
}
|
|
5106
|
+
this.userToken = await this.apiClient.getUserToken(this.sessionId);
|
|
4119
5107
|
// Set tokens in ApiClient for automatic token management
|
|
4120
5108
|
if (this.userToken) {
|
|
4121
5109
|
const expiresAt = new Date(Date.now() + 3600 * 1000).toISOString(); // 1 hour from now
|
|
@@ -4159,20 +5147,8 @@ class FinaticConnect extends EventEmitter {
|
|
|
4159
5147
|
this.apiClient.setSessionContext(this.sessionId, this.companyId, startResponse.data.csrf_token // If available in response
|
|
4160
5148
|
);
|
|
4161
5149
|
}
|
|
4162
|
-
//
|
|
4163
|
-
|
|
4164
|
-
let attempts = 0;
|
|
4165
|
-
while (attempts < maxAttempts) {
|
|
4166
|
-
const sessionResponse = await this.apiClient.validatePortalSession(this.sessionId, '');
|
|
4167
|
-
if (sessionResponse.status === 'active') {
|
|
4168
|
-
break;
|
|
4169
|
-
}
|
|
4170
|
-
await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1 second between attempts
|
|
4171
|
-
attempts++;
|
|
4172
|
-
}
|
|
4173
|
-
if (attempts === maxAttempts) {
|
|
4174
|
-
throw new SessionError('Session failed to become active');
|
|
4175
|
-
}
|
|
5150
|
+
// Session is now active
|
|
5151
|
+
this.currentSessionState = SessionState.ACTIVE;
|
|
4176
5152
|
}
|
|
4177
5153
|
// Get portal URL
|
|
4178
5154
|
const portalResponse = await this.apiClient.getPortalUrl(this.sessionId);
|
|
@@ -4183,6 +5159,12 @@ class FinaticConnect extends EventEmitter {
|
|
|
4183
5159
|
let themedPortalUrl = appendThemeToURL(portalResponse.data.portal_url, options?.theme);
|
|
4184
5160
|
// Apply broker filter to portal URL if provided
|
|
4185
5161
|
themedPortalUrl = appendBrokerFilterToURL(themedPortalUrl, options?.brokers);
|
|
5162
|
+
// Apply email parameter to portal URL if provided
|
|
5163
|
+
if (options?.email) {
|
|
5164
|
+
const url = new URL(themedPortalUrl);
|
|
5165
|
+
url.searchParams.set('email', options.email);
|
|
5166
|
+
themedPortalUrl = url.toString();
|
|
5167
|
+
}
|
|
4186
5168
|
// Create portal UI if not exists
|
|
4187
5169
|
if (!this.portalUI) {
|
|
4188
5170
|
this.portalUI = new PortalUI(this.baseUrl);
|
|
@@ -4194,16 +5176,6 @@ class FinaticConnect extends EventEmitter {
|
|
|
4194
5176
|
if (!this.sessionId) {
|
|
4195
5177
|
throw new SessionError('Session not initialized');
|
|
4196
5178
|
}
|
|
4197
|
-
// Get tokens from portal UI
|
|
4198
|
-
const userToken = this.portalUI.getTokens();
|
|
4199
|
-
if (!userToken) {
|
|
4200
|
-
throw new Error('No tokens received from portal');
|
|
4201
|
-
}
|
|
4202
|
-
// Set the tokens internally
|
|
4203
|
-
this.userToken = userToken;
|
|
4204
|
-
// Set tokens in ApiClient for automatic token management
|
|
4205
|
-
const expiresAt = new Date(Date.now() + 3600 * 1000).toISOString(); // 1 hour from now
|
|
4206
|
-
this.apiClient.setTokens(userToken.accessToken, userToken.refreshToken, expiresAt, userId);
|
|
4207
5179
|
// Emit portal success event
|
|
4208
5180
|
this.emit('portal:success', userId);
|
|
4209
5181
|
// Emit legacy success event
|
|
@@ -4278,21 +5250,8 @@ class FinaticConnect extends EventEmitter {
|
|
|
4278
5250
|
}
|
|
4279
5251
|
// For non-direct auth, we need to wait for the session to be ACTIVE
|
|
4280
5252
|
if (response.data.state === SessionState.PENDING) {
|
|
4281
|
-
//
|
|
4282
|
-
|
|
4283
|
-
let attempts = 0;
|
|
4284
|
-
while (attempts < maxAttempts) {
|
|
4285
|
-
const sessionResponse = await this.apiClient.validatePortalSession(this.sessionId, '');
|
|
4286
|
-
if (sessionResponse.status === 'active') {
|
|
4287
|
-
this.currentSessionState = SessionState.ACTIVE;
|
|
4288
|
-
break;
|
|
4289
|
-
}
|
|
4290
|
-
await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1 second between attempts
|
|
4291
|
-
attempts++;
|
|
4292
|
-
}
|
|
4293
|
-
if (attempts === maxAttempts) {
|
|
4294
|
-
throw new SessionError('Session failed to become active');
|
|
4295
|
-
}
|
|
5253
|
+
// Session is now active
|
|
5254
|
+
this.currentSessionState = SessionState.ACTIVE;
|
|
4296
5255
|
}
|
|
4297
5256
|
}
|
|
4298
5257
|
catch (error) {
|
|
@@ -4397,7 +5356,7 @@ class FinaticConnect extends EventEmitter {
|
|
|
4397
5356
|
* Set the broker context for trading
|
|
4398
5357
|
* @param broker - The broker to use for trading
|
|
4399
5358
|
*/
|
|
4400
|
-
|
|
5359
|
+
setTradingContextBroker(broker) {
|
|
4401
5360
|
this.apiClient.setBroker(broker);
|
|
4402
5361
|
}
|
|
4403
5362
|
/**
|
|
@@ -4405,7 +5364,7 @@ class FinaticConnect extends EventEmitter {
|
|
|
4405
5364
|
* @param accountNumber - The account number to use for trading
|
|
4406
5365
|
* @param accountId - Optional account ID
|
|
4407
5366
|
*/
|
|
4408
|
-
|
|
5367
|
+
setTradingContextAccount(accountNumber, accountId) {
|
|
4409
5368
|
this.apiClient.setAccount(accountNumber, accountId);
|
|
4410
5369
|
}
|
|
4411
5370
|
/**
|
|
@@ -4450,6 +5409,111 @@ class FinaticConnect extends EventEmitter {
|
|
|
4450
5409
|
throw error;
|
|
4451
5410
|
}
|
|
4452
5411
|
}
|
|
5412
|
+
/**
|
|
5413
|
+
* Place a stock stop order (convenience method)
|
|
5414
|
+
*/
|
|
5415
|
+
async placeStockStopOrder(symbol, quantity, side, stopPrice, timeInForce = 'gtc', broker, accountNumber) {
|
|
5416
|
+
if (!this.userToken) {
|
|
5417
|
+
throw new Error('Not initialized with user');
|
|
5418
|
+
}
|
|
5419
|
+
try {
|
|
5420
|
+
return await this.apiClient.placeStockStopOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', stopPrice, timeInForce, broker, accountNumber);
|
|
5421
|
+
}
|
|
5422
|
+
catch (error) {
|
|
5423
|
+
this.emit('error', error);
|
|
5424
|
+
throw error;
|
|
5425
|
+
}
|
|
5426
|
+
}
|
|
5427
|
+
/**
|
|
5428
|
+
* Place a crypto market order (convenience method)
|
|
5429
|
+
*/
|
|
5430
|
+
async placeCryptoMarketOrder(symbol, quantity, side, broker, accountNumber) {
|
|
5431
|
+
if (!this.userToken) {
|
|
5432
|
+
throw new Error('Not initialized with user');
|
|
5433
|
+
}
|
|
5434
|
+
try {
|
|
5435
|
+
return await this.apiClient.placeCryptoMarketOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', broker, accountNumber);
|
|
5436
|
+
}
|
|
5437
|
+
catch (error) {
|
|
5438
|
+
this.emit('error', error);
|
|
5439
|
+
throw error;
|
|
5440
|
+
}
|
|
5441
|
+
}
|
|
5442
|
+
/**
|
|
5443
|
+
* Place a crypto limit order (convenience method)
|
|
5444
|
+
*/
|
|
5445
|
+
async placeCryptoLimitOrder(symbol, quantity, side, price, timeInForce = 'gtc', broker, accountNumber) {
|
|
5446
|
+
if (!this.userToken) {
|
|
5447
|
+
throw new Error('Not initialized with user');
|
|
5448
|
+
}
|
|
5449
|
+
try {
|
|
5450
|
+
return await this.apiClient.placeCryptoLimitOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', price, timeInForce, broker, accountNumber);
|
|
5451
|
+
}
|
|
5452
|
+
catch (error) {
|
|
5453
|
+
this.emit('error', error);
|
|
5454
|
+
throw error;
|
|
5455
|
+
}
|
|
5456
|
+
}
|
|
5457
|
+
/**
|
|
5458
|
+
* Place an options market order (convenience method)
|
|
5459
|
+
*/
|
|
5460
|
+
async placeOptionsMarketOrder(symbol, quantity, side, broker, accountNumber) {
|
|
5461
|
+
if (!this.userToken) {
|
|
5462
|
+
throw new Error('Not initialized with user');
|
|
5463
|
+
}
|
|
5464
|
+
try {
|
|
5465
|
+
return await this.apiClient.placeOptionsMarketOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', broker, accountNumber);
|
|
5466
|
+
}
|
|
5467
|
+
catch (error) {
|
|
5468
|
+
this.emit('error', error);
|
|
5469
|
+
throw error;
|
|
5470
|
+
}
|
|
5471
|
+
}
|
|
5472
|
+
/**
|
|
5473
|
+
* Place an options limit order (convenience method)
|
|
5474
|
+
*/
|
|
5475
|
+
async placeOptionsLimitOrder(symbol, quantity, side, price, timeInForce = 'gtc', broker, accountNumber) {
|
|
5476
|
+
if (!this.userToken) {
|
|
5477
|
+
throw new Error('Not initialized with user');
|
|
5478
|
+
}
|
|
5479
|
+
try {
|
|
5480
|
+
return await this.apiClient.placeOptionsLimitOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', price, timeInForce, broker, accountNumber);
|
|
5481
|
+
}
|
|
5482
|
+
catch (error) {
|
|
5483
|
+
this.emit('error', error);
|
|
5484
|
+
throw error;
|
|
5485
|
+
}
|
|
5486
|
+
}
|
|
5487
|
+
/**
|
|
5488
|
+
* Place a futures market order (convenience method)
|
|
5489
|
+
*/
|
|
5490
|
+
async placeFuturesMarketOrder(symbol, quantity, side, broker, accountNumber) {
|
|
5491
|
+
if (!this.userToken) {
|
|
5492
|
+
throw new Error('Not initialized with user');
|
|
5493
|
+
}
|
|
5494
|
+
try {
|
|
5495
|
+
return await this.apiClient.placeFuturesMarketOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', broker, accountNumber);
|
|
5496
|
+
}
|
|
5497
|
+
catch (error) {
|
|
5498
|
+
this.emit('error', error);
|
|
5499
|
+
throw error;
|
|
5500
|
+
}
|
|
5501
|
+
}
|
|
5502
|
+
/**
|
|
5503
|
+
* Place a futures limit order (convenience method)
|
|
5504
|
+
*/
|
|
5505
|
+
async placeFuturesLimitOrder(symbol, quantity, side, price, timeInForce = 'gtc', broker, accountNumber) {
|
|
5506
|
+
if (!this.userToken) {
|
|
5507
|
+
throw new Error('Not initialized with user');
|
|
5508
|
+
}
|
|
5509
|
+
try {
|
|
5510
|
+
return await this.apiClient.placeFuturesLimitOrder(symbol, quantity, side === 'buy' ? 'Buy' : 'Sell', price, timeInForce, broker, accountNumber);
|
|
5511
|
+
}
|
|
5512
|
+
catch (error) {
|
|
5513
|
+
this.emit('error', error);
|
|
5514
|
+
throw error;
|
|
5515
|
+
}
|
|
5516
|
+
}
|
|
4453
5517
|
/**
|
|
4454
5518
|
* Get the current user ID
|
|
4455
5519
|
* @returns The current user ID or undefined if not authenticated
|
|
@@ -4469,9 +5533,9 @@ class FinaticConnect extends EventEmitter {
|
|
|
4469
5533
|
* @returns Promise with array of broker information
|
|
4470
5534
|
*/
|
|
4471
5535
|
async getBrokerList() {
|
|
4472
|
-
if (!this.isAuthed()) {
|
|
4473
|
-
|
|
4474
|
-
}
|
|
5536
|
+
// if (!this.isAuthed()) {
|
|
5537
|
+
// throw new AuthenticationError('Not authenticated');
|
|
5538
|
+
// }
|
|
4475
5539
|
const response = await this.apiClient.getBrokerList();
|
|
4476
5540
|
const baseUrl = this.baseUrl.replace('/api/v1', ''); // Remove /api/v1 to get the base URL
|
|
4477
5541
|
// Transform the broker list to include full logo URLs
|
|
@@ -4599,6 +5663,12 @@ class FinaticConnect extends EventEmitter {
|
|
|
4599
5663
|
}
|
|
4600
5664
|
return this.apiClient.getBrokerAccountsPage(page, perPage, filter);
|
|
4601
5665
|
}
|
|
5666
|
+
async getBalancesPage(page = 1, perPage = 100, filter) {
|
|
5667
|
+
if (!this.isAuthed()) {
|
|
5668
|
+
throw new AuthenticationError('User is not authenticated');
|
|
5669
|
+
}
|
|
5670
|
+
return this.apiClient.getBrokerBalancesPage(page, perPage, filter);
|
|
5671
|
+
}
|
|
4602
5672
|
/**
|
|
4603
5673
|
* Get the next page of orders
|
|
4604
5674
|
* @param previousResult - The previous paginated result
|
|
@@ -4641,6 +5711,15 @@ class FinaticConnect extends EventEmitter {
|
|
|
4641
5711
|
return this.apiClient.getBrokerAccountsPage(page, limit);
|
|
4642
5712
|
});
|
|
4643
5713
|
}
|
|
5714
|
+
async getNextBalancesPage(previousResult) {
|
|
5715
|
+
if (!this.isAuthed()) {
|
|
5716
|
+
throw new AuthenticationError('User is not authenticated');
|
|
5717
|
+
}
|
|
5718
|
+
return this.apiClient.getNextPage(previousResult, (offset, limit) => {
|
|
5719
|
+
const page = Math.floor(offset / limit) + 1;
|
|
5720
|
+
return this.apiClient.getBrokerBalancesPage(page, limit);
|
|
5721
|
+
});
|
|
5722
|
+
}
|
|
4644
5723
|
/**
|
|
4645
5724
|
* Get all orders across all pages (convenience method)
|
|
4646
5725
|
* @param filter - Optional filter parameters
|
|
@@ -4707,6 +5786,23 @@ class FinaticConnect extends EventEmitter {
|
|
|
4707
5786
|
}
|
|
4708
5787
|
return allData;
|
|
4709
5788
|
}
|
|
5789
|
+
async getAllBalances(filter) {
|
|
5790
|
+
if (!this.isAuthed()) {
|
|
5791
|
+
throw new AuthenticationError('User is not authenticated');
|
|
5792
|
+
}
|
|
5793
|
+
const allData = [];
|
|
5794
|
+
let currentResult = await this.getBalancesPage(1, 100, filter);
|
|
5795
|
+
while (currentResult) {
|
|
5796
|
+
allData.push(...currentResult.data);
|
|
5797
|
+
if (!currentResult.hasNext)
|
|
5798
|
+
break;
|
|
5799
|
+
const nextResult = await this.getNextBalancesPage(currentResult);
|
|
5800
|
+
if (!nextResult)
|
|
5801
|
+
break;
|
|
5802
|
+
currentResult = nextResult;
|
|
5803
|
+
}
|
|
5804
|
+
return allData;
|
|
5805
|
+
}
|
|
4710
5806
|
/**
|
|
4711
5807
|
* Register session management (but don't auto-cleanup for 24-hour sessions)
|
|
4712
5808
|
*/
|
|
@@ -4756,20 +5852,9 @@ class FinaticConnect extends EventEmitter {
|
|
|
4756
5852
|
await this.refreshSessionAutomatically();
|
|
4757
5853
|
return;
|
|
4758
5854
|
}
|
|
4759
|
-
//
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
});
|
|
4763
|
-
const validationPromise = this.apiClient.validatePortalSession(this.sessionId, '');
|
|
4764
|
-
const response = await Promise.race([validationPromise, timeoutPromise]);
|
|
4765
|
-
if (response && response.status === 'active') {
|
|
4766
|
-
console.log('[FinaticConnect] Session keep-alive successful');
|
|
4767
|
-
this.currentSessionState = 'active';
|
|
4768
|
-
}
|
|
4769
|
-
else {
|
|
4770
|
-
console.warn('[FinaticConnect] Session keep-alive failed - session not active');
|
|
4771
|
-
this.currentSessionState = response?.status || 'unknown';
|
|
4772
|
-
}
|
|
5855
|
+
// Session keep-alive - assume session is active if we have a session ID
|
|
5856
|
+
console.log('[FinaticConnect] Session keep-alive successful');
|
|
5857
|
+
this.currentSessionState = 'active';
|
|
4773
5858
|
}
|
|
4774
5859
|
catch (error) {
|
|
4775
5860
|
console.warn('[FinaticConnect] Session keep-alive error:', error);
|
|
@@ -4898,6 +5983,24 @@ class FinaticConnect extends EventEmitter {
|
|
|
4898
5983
|
}
|
|
4899
5984
|
return this.apiClient.disconnectCompany(connectionId);
|
|
4900
5985
|
}
|
|
5986
|
+
/**
|
|
5987
|
+
* Get account balances for the authenticated user
|
|
5988
|
+
* @param filters - Optional filters for balances
|
|
5989
|
+
* @returns Promise with balance data
|
|
5990
|
+
*/
|
|
5991
|
+
async getBalances(filters) {
|
|
5992
|
+
if (!this.isAuthed()) {
|
|
5993
|
+
throw new AuthenticationError('User is not authenticated');
|
|
5994
|
+
}
|
|
5995
|
+
try {
|
|
5996
|
+
const response = await this.apiClient.getBalances(filters);
|
|
5997
|
+
return response.response_data || [];
|
|
5998
|
+
}
|
|
5999
|
+
catch (error) {
|
|
6000
|
+
this.emit('error', error);
|
|
6001
|
+
throw error;
|
|
6002
|
+
}
|
|
6003
|
+
}
|
|
4901
6004
|
}
|
|
4902
6005
|
FinaticConnect.instance = null;
|
|
4903
6006
|
|