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