@one_deploy/sdk 1.0.7 → 1.2.0
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 +339 -0
- package/dist/ForexPoolDataGenerator--__twRwl.d.mts +76 -0
- package/dist/ForexPoolDataGenerator-eUgwsU_B.d.ts +76 -0
- package/dist/OneForexTradeHistory-TlKxjbFF.d.ts +250 -0
- package/dist/OneForexTradeHistory-iDySMcw0.d.mts +250 -0
- package/dist/components/index.d.mts +539 -0
- package/dist/components/index.d.ts +539 -0
- package/dist/components/index.js +7295 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/index.mjs +7243 -0
- package/dist/components/index.mjs.map +1 -0
- package/dist/config/index.d.mts +1 -0
- package/dist/config/index.d.ts +1 -0
- package/dist/console-BfTMA7ah.d.mts +504 -0
- package/dist/console-BfTMA7ah.d.ts +504 -0
- package/dist/hooks/index.d.mts +323 -1
- package/dist/hooks/index.d.ts +323 -1
- package/dist/hooks/index.js +3223 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +3204 -1
- package/dist/hooks/index.mjs.map +1 -1
- package/dist/index.d.mts +18 -352
- package/dist/index.d.ts +18 -352
- package/dist/index.js +8646 -574
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +8449 -432
- package/dist/index.mjs.map +1 -1
- package/dist/providers/index.d.mts +31 -31
- package/dist/providers/index.d.ts +31 -31
- package/dist/providers/index.js +140 -153
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/index.mjs +100 -109
- package/dist/providers/index.mjs.map +1 -1
- package/dist/react-native.d.mts +8 -144
- package/dist/react-native.d.ts +8 -144
- package/dist/react-native.js +2640 -689
- package/dist/react-native.js.map +1 -1
- package/dist/react-native.mjs +2610 -691
- package/dist/react-native.mjs.map +1 -1
- package/dist/services/index.d.mts +85 -4
- package/dist/services/index.d.ts +85 -4
- package/dist/services/index.js +1621 -0
- package/dist/services/index.js.map +1 -1
- package/dist/services/index.mjs +1619 -1
- package/dist/services/index.mjs.map +1 -1
- package/dist/types/index.d.mts +203 -1
- package/dist/types/index.d.ts +203 -1
- package/dist/types/index.js +275 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/index.mjs +251 -0
- package/dist/types/index.mjs.map +1 -1
- package/dist/useForexTrading-BleeSor8.d.mts +80 -0
- package/dist/useForexTrading-ZgW_G40Q.d.ts +80 -0
- package/package.json +9 -2
- package/src/components/OneConnectButton.tsx +24 -1
- package/src/components/OneNFTGallery.tsx +13 -7
- package/src/components/OneOfframpWidget.tsx +4 -3
- package/src/components/OnePayWidget.tsx +10 -1
- package/src/components/OneSendWidget.tsx +3 -3
- package/src/components/OneSwapWidget.tsx +4 -4
- package/src/components/OneTransactionButton.tsx +28 -3
- package/src/components/OneWalletBalance.tsx +1 -1
- package/src/components/ai/OneChainSelector.tsx +63 -336
- package/src/components/ai/OneForexCapitalSplit.tsx +112 -0
- package/src/components/ai/OneForexConsoleView.tsx +90 -0
- package/src/components/ai/OneForexPairSelector.tsx +101 -0
- package/src/components/ai/OneForexPoolCard.tsx +105 -0
- package/src/components/ai/OneForexTradeHistory.tsx +107 -0
- package/src/components/ai/OnePairSelector.tsx +77 -434
- package/src/components/ai/console/OneAIQuantConsole.tsx +423 -0
- package/src/components/ai/console/OneAgentCard.tsx +383 -0
- package/src/components/ai/console/OneAgentConsole.tsx +469 -0
- package/src/components/ai/console/OneDecisionTimeline.tsx +433 -0
- package/src/components/ai/console/OneMetricsDashboard.tsx +493 -0
- package/src/components/ai/console/OnePositionCard.tsx +406 -0
- package/src/components/ai/console/OnePositionDetail.tsx +600 -0
- package/src/components/ai/console/OneRiskIndicator.tsx +464 -0
- package/src/components/ai/console/OneTradingConsole.tsx +660 -0
- package/src/components/ai/console/index.ts +17 -0
- package/src/components/ai/index.ts +10 -0
- package/src/hooks/index.ts +46 -0
- package/src/hooks/useAIDecisions.ts +280 -0
- package/src/hooks/useAIPositions.ts +349 -0
- package/src/hooks/useAIQuantConsole.ts +283 -0
- package/src/hooks/useAIRiskStatus.ts +276 -0
- package/src/hooks/useAITrading.ts +190 -0
- package/src/hooks/useBotSimulation.ts +201 -0
- package/src/hooks/useForexTrading.ts +430 -0
- package/src/hooks/useTradingConsole.ts +243 -0
- package/src/index.ts +123 -5
- package/src/providers/OneProvider.tsx +181 -5
- package/src/providers/index.ts +22 -8
- package/src/react-native.ts +41 -0
- package/src/services/forex/BotSimulationEngine.ts +968 -0
- package/src/services/forex/ForexPoolDataGenerator.ts +542 -0
- package/src/services/forex/ForexSimulationEngine.ts +482 -0
- package/src/services/forex/index.ts +21 -0
- package/src/services/index.ts +16 -0
- package/src/types/aiTrading.ts +151 -0
- package/src/types/console.ts +380 -0
- package/src/types/forex.ts +282 -0
- package/src/types/index.ts +106 -0
- package/dist/price-CgqXPnT3.d.ts +0 -13
- package/dist/price-ClbLHHjv.d.mts +0 -13
- package/dist/supabase-BT0c7q9e.d.mts +0 -82
- package/dist/supabase-BT0c7q9e.d.ts +0 -82
package/dist/react-native.mjs
CHANGED
|
@@ -1,6 +1,930 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { StyleSheet, View, Text, TouchableOpacity, Modal, Pressable, ScrollView, Dimensions, Platform } from 'react-native';
|
|
1
|
+
import { StyleSheet, Platform, View, Text, TouchableOpacity, ScrollView } from 'react-native';
|
|
3
2
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
+
import { useRef, useEffect, useState, useCallback, useMemo } from 'react';
|
|
4
|
+
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __esm = (fn, res) => function __init() {
|
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
+
};
|
|
12
|
+
var __export = (target, all) => {
|
|
13
|
+
for (var name in all)
|
|
14
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
|
+
};
|
|
16
|
+
var __copyProps = (to, from, except, desc) => {
|
|
17
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
18
|
+
for (let key of __getOwnPropNames(from))
|
|
19
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
20
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
21
|
+
}
|
|
22
|
+
return to;
|
|
23
|
+
};
|
|
24
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
25
|
+
|
|
26
|
+
// src/types/forex.ts
|
|
27
|
+
var forex_exports = {};
|
|
28
|
+
__export(forex_exports, {
|
|
29
|
+
FOREX_AGENT: () => FOREX_AGENT,
|
|
30
|
+
FOREX_CAPITAL_SPLIT: () => FOREX_CAPITAL_SPLIT,
|
|
31
|
+
FOREX_CURRENCY_PAIRS: () => FOREX_CURRENCY_PAIRS,
|
|
32
|
+
FOREX_CYCLE_OPTIONS: () => FOREX_CYCLE_OPTIONS,
|
|
33
|
+
FOREX_POOL_DEFAULTS: () => FOREX_POOL_DEFAULTS,
|
|
34
|
+
calculateForexNetProfit: () => calculateForexNetProfit,
|
|
35
|
+
computePoolAllocations: () => computePoolAllocations,
|
|
36
|
+
estimateForexProfit: () => estimateForexProfit
|
|
37
|
+
});
|
|
38
|
+
function computePoolAllocations(amount) {
|
|
39
|
+
const totalPoolReserves = amount * FOREX_CAPITAL_SPLIT.poolReserves;
|
|
40
|
+
const tradingCapital = amount * FOREX_CAPITAL_SPLIT.tradingCapital;
|
|
41
|
+
return {
|
|
42
|
+
tradingCapital,
|
|
43
|
+
totalPoolReserves,
|
|
44
|
+
clearing: totalPoolReserves * 0.5,
|
|
45
|
+
hedging: totalPoolReserves * 0.3,
|
|
46
|
+
insurance: totalPoolReserves * 0.2
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function calculateForexNetProfit(grossProfit, cycleOption) {
|
|
50
|
+
const feeAmount = grossProfit * cycleOption.feeRate;
|
|
51
|
+
const postFeeProfit = grossProfit - feeAmount;
|
|
52
|
+
const netProfit = postFeeProfit * cycleOption.commissionRate;
|
|
53
|
+
return { feeAmount, postFeeProfit, netProfit };
|
|
54
|
+
}
|
|
55
|
+
function estimateForexProfit(amount, cycleDays, agent = FOREX_AGENT) {
|
|
56
|
+
const cycleOption = FOREX_CYCLE_OPTIONS.find((c) => c.days === cycleDays) || FOREX_CYCLE_OPTIONS[0];
|
|
57
|
+
const estimatedApy = (agent.dailyRoiMin + agent.dailyRoiMax) / 2 * 365 * 100;
|
|
58
|
+
const dailyRate = estimatedApy / 100 / 365;
|
|
59
|
+
const grossProfit = amount * dailyRate * cycleDays;
|
|
60
|
+
const { feeAmount, netProfit } = calculateForexNetProfit(grossProfit, cycleOption);
|
|
61
|
+
return { grossProfit, feeAmount, netProfit, dailyRate };
|
|
62
|
+
}
|
|
63
|
+
var FOREX_CAPITAL_SPLIT, FOREX_CYCLE_OPTIONS, FOREX_CURRENCY_PAIRS, FOREX_POOL_DEFAULTS, FOREX_AGENT;
|
|
64
|
+
var init_forex = __esm({
|
|
65
|
+
"src/types/forex.ts"() {
|
|
66
|
+
FOREX_CAPITAL_SPLIT = {
|
|
67
|
+
poolReserves: 0.5,
|
|
68
|
+
tradingCapital: 0.5
|
|
69
|
+
};
|
|
70
|
+
FOREX_CYCLE_OPTIONS = [
|
|
71
|
+
{ days: 30, feeRate: 0.1, commissionRate: 0.6, label: "30D" },
|
|
72
|
+
{ days: 60, feeRate: 0.08, commissionRate: 0.7, label: "60D" },
|
|
73
|
+
{ days: 90, feeRate: 0.07, commissionRate: 0.75, label: "90D" },
|
|
74
|
+
{ days: 180, feeRate: 0.05, commissionRate: 0.85, label: "180D" },
|
|
75
|
+
{ days: 360, feeRate: 0.03, commissionRate: 0.9, label: "360D" }
|
|
76
|
+
];
|
|
77
|
+
FOREX_CURRENCY_PAIRS = [
|
|
78
|
+
{ id: "USDC_EURC", base: "USDC", quote: "EURC", symbol: "USDC/EURC", flag: "\u{1F1EA}\u{1F1FA}", name: "Euro", basePrice: 0.923, pipSize: 1e-4, spreadPips: 1.2 },
|
|
79
|
+
{ id: "USDC_GBPC", base: "USDC", quote: "GBPC", symbol: "USDC/GBPC", flag: "\u{1F1EC}\u{1F1E7}", name: "British Pound", basePrice: 0.789, pipSize: 1e-4, spreadPips: 1.5 },
|
|
80
|
+
{ id: "USDC_JPYC", base: "USDC", quote: "JPYC", symbol: "USDC/JPYC", flag: "\u{1F1EF}\u{1F1F5}", name: "Japanese Yen", basePrice: 154.5, pipSize: 0.01, spreadPips: 1 },
|
|
81
|
+
{ id: "USDC_AUDC", base: "USDC", quote: "AUDC", symbol: "USDC/AUDC", flag: "\u{1F1E6}\u{1F1FA}", name: "Australian Dollar", basePrice: 1.538, pipSize: 1e-4, spreadPips: 1.8 },
|
|
82
|
+
{ id: "USDC_CADC", base: "USDC", quote: "CADC", symbol: "USDC/CADC", flag: "\u{1F1E8}\u{1F1E6}", name: "Canadian Dollar", basePrice: 1.364, pipSize: 1e-4, spreadPips: 1.5 },
|
|
83
|
+
{ id: "USDC_CHFC", base: "USDC", quote: "CHFC", symbol: "USDC/CHFC", flag: "\u{1F1E8}\u{1F1ED}", name: "Swiss Franc", basePrice: 0.875, pipSize: 1e-4, spreadPips: 1.3 }
|
|
84
|
+
];
|
|
85
|
+
FOREX_POOL_DEFAULTS = [
|
|
86
|
+
{ id: "clearing", nameKey: "forex.pool_clearing", descriptionKey: "forex.pool_clearing_desc", allocation: 0.5, totalSize: 125e5, utilization: 0.78, color: "#3B82F6", apy7d: 12.8, apy30d: 11.5, netFlow24h: 185e3, txCount24h: 42, txCountTotal: 12840, totalDeposits: 452e5, totalWithdrawals: 327e5, profitDistributed: 185e4, lastUpdated: Date.now() },
|
|
87
|
+
{ id: "hedging", nameKey: "forex.pool_hedging", descriptionKey: "forex.pool_hedging_desc", allocation: 0.3, totalSize: 75e5, utilization: 0.65, color: "#F59E0B", apy7d: 8.1, apy30d: 7.6, netFlow24h: 72e3, txCount24h: 24, txCountTotal: 7620, totalDeposits: 285e5, totalWithdrawals: 21e6, profitDistributed: 98e4, lastUpdated: Date.now() },
|
|
88
|
+
{ id: "insurance", nameKey: "forex.pool_insurance", descriptionKey: "forex.pool_insurance_desc", allocation: 0.2, totalSize: 5e6, utilization: 0.42, color: "#10B981", apy7d: 4.8, apy30d: 4.5, netFlow24h: 35e3, txCount24h: 14, txCountTotal: 4280, totalDeposits: 158e5, totalWithdrawals: 108e5, profitDistributed: 52e4, lastUpdated: Date.now() }
|
|
89
|
+
];
|
|
90
|
+
FOREX_AGENT = {
|
|
91
|
+
id: "stablefx-01",
|
|
92
|
+
nameKey: "forex.agent_name",
|
|
93
|
+
descriptionKey: "forex.agent_description",
|
|
94
|
+
icon: "\u{1F4B1}",
|
|
95
|
+
color: "#0EA5E9",
|
|
96
|
+
supportedPairs: FOREX_CURRENCY_PAIRS.map((p) => p.id),
|
|
97
|
+
dailyRoiMin: 2e-3,
|
|
98
|
+
dailyRoiMax: 5e-3,
|
|
99
|
+
totalManaged: 25e6,
|
|
100
|
+
totalUsers: 3847,
|
|
101
|
+
winRate: 72.5
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// src/services/forex/ForexPoolDataGenerator.ts
|
|
107
|
+
var ForexPoolDataGenerator_exports = {};
|
|
108
|
+
__export(ForexPoolDataGenerator_exports, {
|
|
109
|
+
ForexPoolDataGenerator: () => ForexPoolDataGenerator
|
|
110
|
+
});
|
|
111
|
+
function rand(min, max) {
|
|
112
|
+
return min + Math.random() * (max - min);
|
|
113
|
+
}
|
|
114
|
+
function randInt(min, max) {
|
|
115
|
+
return Math.floor(rand(min, max + 1));
|
|
116
|
+
}
|
|
117
|
+
function pick2(arr) {
|
|
118
|
+
return arr[Math.floor(Math.random() * arr.length)];
|
|
119
|
+
}
|
|
120
|
+
function genTxHash() {
|
|
121
|
+
const chars = "0123456789abcdef";
|
|
122
|
+
let hash = "0x";
|
|
123
|
+
for (let i = 0; i < 64; i++) hash += chars[Math.floor(Math.random() * 16)];
|
|
124
|
+
return hash;
|
|
125
|
+
}
|
|
126
|
+
function formatDate2(d) {
|
|
127
|
+
return d.toISOString().split("T")[0];
|
|
128
|
+
}
|
|
129
|
+
function genId(prefix) {
|
|
130
|
+
return `${prefix}_${Date.now().toString(36)}_${(++_idCounter).toString(36)}`;
|
|
131
|
+
}
|
|
132
|
+
var _idCounter, POOL_PARAMS, ForexPoolDataGeneratorClass, _instance, ForexPoolDataGenerator;
|
|
133
|
+
var init_ForexPoolDataGenerator = __esm({
|
|
134
|
+
"src/services/forex/ForexPoolDataGenerator.ts"() {
|
|
135
|
+
init_forex();
|
|
136
|
+
_idCounter = 0;
|
|
137
|
+
POOL_PARAMS = {
|
|
138
|
+
clearing: {
|
|
139
|
+
meanDailyPnlPct: 35e-5,
|
|
140
|
+
stddevPnlPct: 15e-5,
|
|
141
|
+
utilizationMin: 0.7,
|
|
142
|
+
utilizationMax: 0.85,
|
|
143
|
+
depositsPerDay: [15, 25],
|
|
144
|
+
withdrawalsPerDay: [8, 12],
|
|
145
|
+
profitDistPerDay: 5,
|
|
146
|
+
avgDepositSize: 25e3,
|
|
147
|
+
avgWithdrawalSize: 18e3
|
|
148
|
+
},
|
|
149
|
+
hedging: {
|
|
150
|
+
meanDailyPnlPct: 22e-5,
|
|
151
|
+
stddevPnlPct: 2e-4,
|
|
152
|
+
utilizationMin: 0.55,
|
|
153
|
+
utilizationMax: 0.75,
|
|
154
|
+
depositsPerDay: [8, 15],
|
|
155
|
+
withdrawalsPerDay: [5, 8],
|
|
156
|
+
profitDistPerDay: 3,
|
|
157
|
+
avgDepositSize: 18e3,
|
|
158
|
+
avgWithdrawalSize: 12e3
|
|
159
|
+
},
|
|
160
|
+
insurance: {
|
|
161
|
+
meanDailyPnlPct: 13e-5,
|
|
162
|
+
stddevPnlPct: 8e-5,
|
|
163
|
+
utilizationMin: 0.3,
|
|
164
|
+
utilizationMax: 0.5,
|
|
165
|
+
depositsPerDay: [5, 10],
|
|
166
|
+
withdrawalsPerDay: [3, 5],
|
|
167
|
+
profitDistPerDay: 2,
|
|
168
|
+
avgDepositSize: 12e3,
|
|
169
|
+
avgWithdrawalSize: 8e3
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
ForexPoolDataGeneratorClass = class {
|
|
173
|
+
constructor() {
|
|
174
|
+
this.snapshotCache = null;
|
|
175
|
+
this.transactionCache = null;
|
|
176
|
+
this.baseBlockNumber = 195e5;
|
|
177
|
+
}
|
|
178
|
+
// ── Public API ─────────────────────────────────────────────────────────
|
|
179
|
+
generateAllSnapshots() {
|
|
180
|
+
if (this.snapshotCache) return this.snapshotCache;
|
|
181
|
+
const result = {
|
|
182
|
+
clearing: [],
|
|
183
|
+
hedging: [],
|
|
184
|
+
insurance: []
|
|
185
|
+
};
|
|
186
|
+
for (const pool of FOREX_POOL_DEFAULTS) {
|
|
187
|
+
result[pool.id] = this.generatePoolSnapshots(pool.id, pool.totalSize);
|
|
188
|
+
}
|
|
189
|
+
this.snapshotCache = result;
|
|
190
|
+
return result;
|
|
191
|
+
}
|
|
192
|
+
generateAllTransactions() {
|
|
193
|
+
if (this.transactionCache) return this.transactionCache;
|
|
194
|
+
const allTx = [];
|
|
195
|
+
for (const pool of FOREX_POOL_DEFAULTS) {
|
|
196
|
+
const snapshots = this.snapshotCache?.[pool.id] || this.generatePoolSnapshots(pool.id, pool.totalSize);
|
|
197
|
+
const txs = this.generatePoolTransactions(pool.id, snapshots);
|
|
198
|
+
allTx.push(...txs);
|
|
199
|
+
}
|
|
200
|
+
const now = /* @__PURE__ */ new Date();
|
|
201
|
+
for (let i = 0; i < 60; i++) {
|
|
202
|
+
const day = new Date(now);
|
|
203
|
+
day.setDate(day.getDate() - (60 - i));
|
|
204
|
+
const dayOfWeek = day.getDay();
|
|
205
|
+
if (dayOfWeek === 2 || dayOfWeek === 4 || dayOfWeek === 5 && Math.random() < 0.4) {
|
|
206
|
+
const fromPool = pick2(["clearing", "hedging", "insurance"]);
|
|
207
|
+
const toOptions = ["clearing", "hedging", "insurance"].filter((p) => p !== fromPool);
|
|
208
|
+
const toPool = pick2(toOptions);
|
|
209
|
+
const amount = rand(5e4, 2e5);
|
|
210
|
+
const ts = day.getTime() + randInt(10, 18) * 36e5;
|
|
211
|
+
allTx.push({
|
|
212
|
+
id: genId("ipt"),
|
|
213
|
+
poolId: fromPool,
|
|
214
|
+
type: "inter_pool_transfer",
|
|
215
|
+
amount: -amount,
|
|
216
|
+
balanceBefore: 0,
|
|
217
|
+
balanceAfter: 0,
|
|
218
|
+
txHash: genTxHash(),
|
|
219
|
+
blockNumber: this.baseBlockNumber + i * 7200 + randInt(0, 100),
|
|
220
|
+
timestamp: ts,
|
|
221
|
+
description: `Transfer to ${toPool} pool`
|
|
222
|
+
});
|
|
223
|
+
allTx.push({
|
|
224
|
+
id: genId("ipt"),
|
|
225
|
+
poolId: toPool,
|
|
226
|
+
type: "inter_pool_transfer",
|
|
227
|
+
amount,
|
|
228
|
+
balanceBefore: 0,
|
|
229
|
+
balanceAfter: 0,
|
|
230
|
+
txHash: genTxHash(),
|
|
231
|
+
blockNumber: this.baseBlockNumber + i * 7200 + randInt(100, 200),
|
|
232
|
+
timestamp: ts + 5e3,
|
|
233
|
+
description: `Transfer from ${fromPool} pool`
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
if (dayOfWeek === 3 && Math.random() < 0.85) {
|
|
237
|
+
const pool = pick2(FOREX_POOL_DEFAULTS);
|
|
238
|
+
const rebalanceAmt = rand(2e4, 1e5);
|
|
239
|
+
const ts = day.getTime() + randInt(2, 6) * 36e5;
|
|
240
|
+
allTx.push({
|
|
241
|
+
id: genId("rrb"),
|
|
242
|
+
poolId: pool.id,
|
|
243
|
+
type: "reserve_rebalance",
|
|
244
|
+
amount: Math.random() < 0.5 ? rebalanceAmt : -rebalanceAmt,
|
|
245
|
+
balanceBefore: 0,
|
|
246
|
+
balanceAfter: 0,
|
|
247
|
+
txHash: genTxHash(),
|
|
248
|
+
blockNumber: this.baseBlockNumber + i * 7200 + randInt(200, 300),
|
|
249
|
+
timestamp: ts,
|
|
250
|
+
description: "Automated reserve rebalance"
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
allTx.sort((a, b) => a.timestamp - b.timestamp);
|
|
255
|
+
const runningBalance = {
|
|
256
|
+
clearing: FOREX_POOL_DEFAULTS[0].totalSize * 0.85,
|
|
257
|
+
hedging: FOREX_POOL_DEFAULTS[1].totalSize * 0.82,
|
|
258
|
+
insurance: FOREX_POOL_DEFAULTS[2].totalSize * 0.88
|
|
259
|
+
};
|
|
260
|
+
for (const tx of allTx) {
|
|
261
|
+
tx.balanceBefore = runningBalance[tx.poolId];
|
|
262
|
+
runningBalance[tx.poolId] += tx.amount;
|
|
263
|
+
tx.balanceAfter = runningBalance[tx.poolId];
|
|
264
|
+
}
|
|
265
|
+
this.transactionCache = allTx;
|
|
266
|
+
return allTx;
|
|
267
|
+
}
|
|
268
|
+
generateTradeHistory(investmentAmount, startDate, selectedPairs) {
|
|
269
|
+
const trades = [];
|
|
270
|
+
const start = new Date(startDate);
|
|
271
|
+
const now = /* @__PURE__ */ new Date();
|
|
272
|
+
const dayCount = Math.min(60, Math.ceil((now.getTime() - start.getTime()) / 864e5));
|
|
273
|
+
let cumulativePnl = 0;
|
|
274
|
+
let blockNum = this.baseBlockNumber + randInt(0, 5e3);
|
|
275
|
+
for (let d = 0; d < dayCount; d++) {
|
|
276
|
+
const day = new Date(start);
|
|
277
|
+
day.setDate(day.getDate() + d);
|
|
278
|
+
const dayOfWeek = day.getDay();
|
|
279
|
+
const baseCount = dayOfWeek === 0 || dayOfWeek === 6 ? randInt(1, 2) : randInt(3, 8);
|
|
280
|
+
for (let t = 0; t < baseCount; t++) {
|
|
281
|
+
const pair = FOREX_CURRENCY_PAIRS.find((p) => p.id === pick2(selectedPairs)) || pick2(FOREX_CURRENCY_PAIRS);
|
|
282
|
+
const side = Math.random() > 0.5 ? "BUY" : "SELL";
|
|
283
|
+
const lots = parseFloat(rand(0.1, 2.5).toFixed(2));
|
|
284
|
+
const rfqPrice = pair.basePrice * (1 + rand(-3e-3, 3e-3));
|
|
285
|
+
const quoteSpread = rand(0.5, 2) * pair.pipSize;
|
|
286
|
+
const quotePrice = side === "BUY" ? rfqPrice + quoteSpread : rfqPrice - quoteSpread;
|
|
287
|
+
const matched = Math.random() < 0.85;
|
|
288
|
+
if (!matched) continue;
|
|
289
|
+
const matchPrice = quotePrice * (1 + rand(-5e-5, 5e-5));
|
|
290
|
+
const settlePrice = matchPrice * (1 + rand(-2e-5, 2e-5));
|
|
291
|
+
const pips = (settlePrice - rfqPrice) / pair.pipSize * (side === "BUY" ? 1 : -1);
|
|
292
|
+
const pnl = pips * pair.pipSize * lots * 1e5;
|
|
293
|
+
const isWin = Math.random() < FOREX_AGENT.winRate / 100;
|
|
294
|
+
const finalPnl = isWin ? Math.abs(pnl) : -Math.abs(pnl) * rand(0.3, 0.8);
|
|
295
|
+
cumulativePnl += finalPnl;
|
|
296
|
+
const clearingFee = Math.abs(finalPnl) * rand(1e-3, 3e-3);
|
|
297
|
+
const hedgingCost = Math.abs(finalPnl) * rand(5e-4, 2e-3);
|
|
298
|
+
const insuranceReserve = Math.abs(finalPnl) * rand(3e-4, 1e-3);
|
|
299
|
+
blockNum += randInt(1, 20);
|
|
300
|
+
const timestamp = day.getTime() + randInt(0, 23) * 36e5 + randInt(0, 36e5);
|
|
301
|
+
trades.push({
|
|
302
|
+
id: genId("FXT"),
|
|
303
|
+
timestamp,
|
|
304
|
+
pairId: pair.id,
|
|
305
|
+
pairSymbol: pair.symbol,
|
|
306
|
+
side,
|
|
307
|
+
rfqPrice,
|
|
308
|
+
quotePrice,
|
|
309
|
+
matchPrice,
|
|
310
|
+
settlePrice,
|
|
311
|
+
lots,
|
|
312
|
+
pips: isWin ? Math.abs(pips) : -Math.abs(pips) * rand(0.3, 0.8),
|
|
313
|
+
pnl: finalPnl,
|
|
314
|
+
status: "SETTLED",
|
|
315
|
+
pvpSettled: true,
|
|
316
|
+
clearingFee,
|
|
317
|
+
hedgingCost,
|
|
318
|
+
insuranceReserve,
|
|
319
|
+
txHash: genTxHash(),
|
|
320
|
+
blockNumber: blockNum,
|
|
321
|
+
cycleDay: d + 1,
|
|
322
|
+
cumulativePnl
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
trades.sort((a, b) => a.timestamp - b.timestamp);
|
|
327
|
+
return trades;
|
|
328
|
+
}
|
|
329
|
+
generateLiveTransaction(poolId, type, baseAmount) {
|
|
330
|
+
const params = POOL_PARAMS[poolId];
|
|
331
|
+
let amount;
|
|
332
|
+
switch (type) {
|
|
333
|
+
case "deposit":
|
|
334
|
+
amount = baseAmount ?? rand(params.avgDepositSize * 0.5, params.avgDepositSize * 1.5);
|
|
335
|
+
break;
|
|
336
|
+
case "withdrawal":
|
|
337
|
+
amount = -(baseAmount ?? rand(params.avgWithdrawalSize * 0.5, params.avgWithdrawalSize * 1.5));
|
|
338
|
+
break;
|
|
339
|
+
case "profit_distribution":
|
|
340
|
+
amount = baseAmount ?? rand(500, 5e3);
|
|
341
|
+
break;
|
|
342
|
+
case "fee_collection":
|
|
343
|
+
amount = baseAmount ?? rand(100, 2e3);
|
|
344
|
+
break;
|
|
345
|
+
case "loss_absorption":
|
|
346
|
+
amount = -(baseAmount ?? rand(200, 3e3));
|
|
347
|
+
break;
|
|
348
|
+
default:
|
|
349
|
+
amount = baseAmount ?? rand(-5e3, 5e3);
|
|
350
|
+
}
|
|
351
|
+
const pool = FOREX_POOL_DEFAULTS.find((p) => p.id === poolId);
|
|
352
|
+
const balanceBefore = pool.totalSize;
|
|
353
|
+
return {
|
|
354
|
+
id: genId("ptx"),
|
|
355
|
+
poolId,
|
|
356
|
+
type,
|
|
357
|
+
amount,
|
|
358
|
+
balanceBefore,
|
|
359
|
+
balanceAfter: balanceBefore + amount,
|
|
360
|
+
txHash: genTxHash(),
|
|
361
|
+
blockNumber: this.baseBlockNumber + Math.floor(Date.now() / 12e3),
|
|
362
|
+
timestamp: Date.now(),
|
|
363
|
+
description: this.getTxDescription(type, poolId, Math.abs(amount))
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
// ── Private Methods ────────────────────────────────────────────────────
|
|
367
|
+
generatePoolSnapshots(poolId, currentSize) {
|
|
368
|
+
const params = POOL_PARAMS[poolId];
|
|
369
|
+
const snapshots = [];
|
|
370
|
+
const now = /* @__PURE__ */ new Date();
|
|
371
|
+
let balance = currentSize * rand(0.82, 0.88);
|
|
372
|
+
let cumulativePnl = 0;
|
|
373
|
+
for (let i = 59; i >= 0; i--) {
|
|
374
|
+
const day = new Date(now);
|
|
375
|
+
day.setDate(day.getDate() - i);
|
|
376
|
+
const dayOfWeek = day.getDay();
|
|
377
|
+
const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;
|
|
378
|
+
const openBalance = balance;
|
|
379
|
+
const activityMultiplier = isWeekend ? 0.2 : 1;
|
|
380
|
+
const isDrawdown = !isWeekend && Math.random() < 0.2;
|
|
381
|
+
let dailyPnlPct;
|
|
382
|
+
if (isDrawdown) {
|
|
383
|
+
dailyPnlPct = -rand(1e-4, params.stddevPnlPct * 2);
|
|
384
|
+
} else {
|
|
385
|
+
dailyPnlPct = this.gaussianRandom(params.meanDailyPnlPct, params.stddevPnlPct);
|
|
386
|
+
}
|
|
387
|
+
dailyPnlPct *= activityMultiplier;
|
|
388
|
+
const dailyPnl = balance * dailyPnlPct;
|
|
389
|
+
cumulativePnl += dailyPnl;
|
|
390
|
+
const depositCount = isWeekend ? randInt(1, Math.ceil(params.depositsPerDay[0] * 0.2)) : randInt(params.depositsPerDay[0], params.depositsPerDay[1]);
|
|
391
|
+
const withdrawalCount = isWeekend ? randInt(0, Math.ceil(params.withdrawalsPerDay[0] * 0.2)) : randInt(params.withdrawalsPerDay[0], params.withdrawalsPerDay[1]);
|
|
392
|
+
const deposits = depositCount * params.avgDepositSize * rand(0.7, 1.3) * activityMultiplier;
|
|
393
|
+
const withdrawals = withdrawalCount * params.avgWithdrawalSize * rand(0.7, 1.3) * activityMultiplier;
|
|
394
|
+
const netFlow = deposits - withdrawals;
|
|
395
|
+
balance += dailyPnl + netFlow;
|
|
396
|
+
const txCount = depositCount + withdrawalCount + Math.round(params.profitDistPerDay * activityMultiplier);
|
|
397
|
+
const utilization = rand(params.utilizationMin, params.utilizationMax);
|
|
398
|
+
const activeUsers = Math.round(rand(80, 400) * activityMultiplier);
|
|
399
|
+
snapshots.push({
|
|
400
|
+
poolId,
|
|
401
|
+
date: formatDate2(day),
|
|
402
|
+
openBalance,
|
|
403
|
+
closeBalance: balance,
|
|
404
|
+
deposits,
|
|
405
|
+
withdrawals,
|
|
406
|
+
netFlow,
|
|
407
|
+
dailyPnl,
|
|
408
|
+
dailyPnlPct,
|
|
409
|
+
cumulativePnl,
|
|
410
|
+
utilization,
|
|
411
|
+
txCount,
|
|
412
|
+
activeUsers
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
return snapshots;
|
|
416
|
+
}
|
|
417
|
+
generatePoolTransactions(poolId, snapshots) {
|
|
418
|
+
const params = POOL_PARAMS[poolId];
|
|
419
|
+
const transactions = [];
|
|
420
|
+
for (const snap of snapshots) {
|
|
421
|
+
const day = new Date(snap.date);
|
|
422
|
+
const dayOfWeek = day.getDay();
|
|
423
|
+
const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;
|
|
424
|
+
const mult = isWeekend ? 0.2 : 1;
|
|
425
|
+
const depositCount = Math.round(randInt(params.depositsPerDay[0], params.depositsPerDay[1]) * mult);
|
|
426
|
+
const withdrawalCount = Math.round(randInt(params.withdrawalsPerDay[0], params.withdrawalsPerDay[1]) * mult);
|
|
427
|
+
const profitCount = Math.round(params.profitDistPerDay * mult);
|
|
428
|
+
for (let i = 0; i < depositCount; i++) {
|
|
429
|
+
const amount = rand(params.avgDepositSize * 0.3, params.avgDepositSize * 2);
|
|
430
|
+
const ts = day.getTime() + randInt(0, 23) * 36e5 + randInt(0, 36e5);
|
|
431
|
+
transactions.push({
|
|
432
|
+
id: genId("dep"),
|
|
433
|
+
poolId,
|
|
434
|
+
type: "deposit",
|
|
435
|
+
amount,
|
|
436
|
+
balanceBefore: 0,
|
|
437
|
+
balanceAfter: 0,
|
|
438
|
+
txHash: genTxHash(),
|
|
439
|
+
blockNumber: this.baseBlockNumber + Math.floor(ts / 12e3) + randInt(0, 50),
|
|
440
|
+
timestamp: ts,
|
|
441
|
+
description: `Deposit to ${poolId} pool`
|
|
442
|
+
});
|
|
443
|
+
}
|
|
444
|
+
for (let i = 0; i < withdrawalCount; i++) {
|
|
445
|
+
const amount = rand(params.avgWithdrawalSize * 0.3, params.avgWithdrawalSize * 2);
|
|
446
|
+
const ts = day.getTime() + randInt(0, 23) * 36e5 + randInt(0, 36e5);
|
|
447
|
+
transactions.push({
|
|
448
|
+
id: genId("wdr"),
|
|
449
|
+
poolId,
|
|
450
|
+
type: "withdrawal",
|
|
451
|
+
amount: -amount,
|
|
452
|
+
balanceBefore: 0,
|
|
453
|
+
balanceAfter: 0,
|
|
454
|
+
txHash: genTxHash(),
|
|
455
|
+
blockNumber: this.baseBlockNumber + Math.floor(ts / 12e3) + randInt(0, 50),
|
|
456
|
+
timestamp: ts,
|
|
457
|
+
description: `Withdrawal from ${poolId} pool`
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
for (let i = 0; i < profitCount; i++) {
|
|
461
|
+
const amount = rand(500, 8e3);
|
|
462
|
+
const ts = day.getTime() + randInt(6, 22) * 36e5 + randInt(0, 36e5);
|
|
463
|
+
transactions.push({
|
|
464
|
+
id: genId("prd"),
|
|
465
|
+
poolId,
|
|
466
|
+
type: "profit_distribution",
|
|
467
|
+
amount,
|
|
468
|
+
balanceBefore: 0,
|
|
469
|
+
balanceAfter: 0,
|
|
470
|
+
txHash: genTxHash(),
|
|
471
|
+
blockNumber: this.baseBlockNumber + Math.floor(ts / 12e3) + randInt(0, 50),
|
|
472
|
+
timestamp: ts,
|
|
473
|
+
description: `Profit distribution from ${poolId} pool`
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
if (!isWeekend) {
|
|
477
|
+
const feeCount = randInt(1, 2);
|
|
478
|
+
for (let i = 0; i < feeCount; i++) {
|
|
479
|
+
const amount = rand(100, 3e3);
|
|
480
|
+
const ts = day.getTime() + randInt(8, 20) * 36e5;
|
|
481
|
+
transactions.push({
|
|
482
|
+
id: genId("fee"),
|
|
483
|
+
poolId,
|
|
484
|
+
type: "fee_collection",
|
|
485
|
+
amount,
|
|
486
|
+
balanceBefore: 0,
|
|
487
|
+
balanceAfter: 0,
|
|
488
|
+
txHash: genTxHash(),
|
|
489
|
+
blockNumber: this.baseBlockNumber + Math.floor(ts / 12e3) + randInt(0, 50),
|
|
490
|
+
timestamp: ts,
|
|
491
|
+
description: `Fee collection for ${poolId} pool`
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
return transactions;
|
|
497
|
+
}
|
|
498
|
+
gaussianRandom(mean, stddev) {
|
|
499
|
+
let u = 0, v = 0;
|
|
500
|
+
while (u === 0) u = Math.random();
|
|
501
|
+
while (v === 0) v = Math.random();
|
|
502
|
+
const z = Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v);
|
|
503
|
+
return mean + z * stddev;
|
|
504
|
+
}
|
|
505
|
+
getTxDescription(type, poolId, amount) {
|
|
506
|
+
const fmt = `$${amount.toLocaleString(void 0, { maximumFractionDigits: 0 })}`;
|
|
507
|
+
switch (type) {
|
|
508
|
+
case "deposit":
|
|
509
|
+
return `Deposit ${fmt} to ${poolId} pool`;
|
|
510
|
+
case "withdrawal":
|
|
511
|
+
return `Withdrawal ${fmt} from ${poolId} pool`;
|
|
512
|
+
case "profit_distribution":
|
|
513
|
+
return `Profit distribution ${fmt} from ${poolId}`;
|
|
514
|
+
case "loss_absorption":
|
|
515
|
+
return `Loss absorbed ${fmt} by ${poolId} pool`;
|
|
516
|
+
case "inter_pool_transfer":
|
|
517
|
+
return `Inter-pool transfer ${fmt}`;
|
|
518
|
+
case "fee_collection":
|
|
519
|
+
return `Fee collected ${fmt} in ${poolId}`;
|
|
520
|
+
case "reserve_rebalance":
|
|
521
|
+
return `Reserve rebalance ${fmt} in ${poolId}`;
|
|
522
|
+
default:
|
|
523
|
+
return `${type} ${fmt}`;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
};
|
|
527
|
+
_instance = null;
|
|
528
|
+
ForexPoolDataGenerator = {
|
|
529
|
+
getInstance() {
|
|
530
|
+
if (!_instance) {
|
|
531
|
+
_instance = new ForexPoolDataGeneratorClass();
|
|
532
|
+
}
|
|
533
|
+
return _instance;
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
// src/services/forex/ForexSimulationEngine.ts
|
|
540
|
+
var ForexSimulationEngine_exports = {};
|
|
541
|
+
__export(ForexSimulationEngine_exports, {
|
|
542
|
+
forexSimulationEngine: () => forexSimulationEngine
|
|
543
|
+
});
|
|
544
|
+
function genId2() {
|
|
545
|
+
return `fxlog_${Date.now()}_${++idCounter}`;
|
|
546
|
+
}
|
|
547
|
+
function tradeId() {
|
|
548
|
+
return `FXT_${Date.now().toString(36).toUpperCase()}_${(++idCounter).toString(36).toUpperCase()}`;
|
|
549
|
+
}
|
|
550
|
+
function rand2(min, max) {
|
|
551
|
+
return min + Math.random() * (max - min);
|
|
552
|
+
}
|
|
553
|
+
function randInt2(min, max) {
|
|
554
|
+
return Math.floor(rand2(min, max + 1));
|
|
555
|
+
}
|
|
556
|
+
function pick3(arr) {
|
|
557
|
+
return arr[Math.floor(Math.random() * arr.length)];
|
|
558
|
+
}
|
|
559
|
+
function formatRate(price, pair) {
|
|
560
|
+
if (pair.pipSize >= 0.01) return price.toFixed(3);
|
|
561
|
+
return price.toFixed(5);
|
|
562
|
+
}
|
|
563
|
+
var idCounter, FX_NEWS, ForexSimulationEngine, forexSimulationEngine;
|
|
564
|
+
var init_ForexSimulationEngine = __esm({
|
|
565
|
+
"src/services/forex/ForexSimulationEngine.ts"() {
|
|
566
|
+
init_forex();
|
|
567
|
+
idCounter = 0;
|
|
568
|
+
FX_NEWS = [
|
|
569
|
+
"ECB signals potential rate adjustment, EUR pairs volatile",
|
|
570
|
+
"BOJ maintains yield curve control, JPY weakens further",
|
|
571
|
+
"Fed minutes reveal hawkish sentiment, USD strengthens",
|
|
572
|
+
"UK CPI data beats expectations, GBP rallies",
|
|
573
|
+
"RBA holds rates steady, AUD consolidates",
|
|
574
|
+
"SNB intervenes in currency markets, CHF stabilizes",
|
|
575
|
+
"Bank of Canada rate decision pending, CAD in focus",
|
|
576
|
+
"Cross-border stablecoin settlement volume hits $2.1B daily",
|
|
577
|
+
"Circle USDC reserves fully backed, attestation report released",
|
|
578
|
+
"DeFi forex protocol TVL reaches new high at $890M",
|
|
579
|
+
"On-chain FX liquidity deepens across major pairs",
|
|
580
|
+
"Institutional adoption of on-chain forex accelerates"
|
|
581
|
+
];
|
|
582
|
+
ForexSimulationEngine = class {
|
|
583
|
+
constructor() {
|
|
584
|
+
this.listeners = [];
|
|
585
|
+
this.poolTxListeners = [];
|
|
586
|
+
this.cycleTimer = null;
|
|
587
|
+
this.pairStates = /* @__PURE__ */ new Map();
|
|
588
|
+
this.running = false;
|
|
589
|
+
this.openPositions = [];
|
|
590
|
+
this.totalPnl = 0;
|
|
591
|
+
this.totalTrades = 0;
|
|
592
|
+
this.totalPips = 0;
|
|
593
|
+
this.totalLots = 0;
|
|
594
|
+
for (const pair of FOREX_CURRENCY_PAIRS) {
|
|
595
|
+
const jitter = pair.basePrice * rand2(-3e-3, 3e-3);
|
|
596
|
+
const price = pair.basePrice + jitter;
|
|
597
|
+
const halfSpread = pair.spreadPips * pair.pipSize / 2;
|
|
598
|
+
this.pairStates.set(pair.id, {
|
|
599
|
+
pair,
|
|
600
|
+
currentPrice: price,
|
|
601
|
+
bidPrice: price - halfSpread,
|
|
602
|
+
askPrice: price + halfSpread,
|
|
603
|
+
lastSpread: pair.spreadPips
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
// ── Public API ─────────────────────────────────────────────────────────────
|
|
608
|
+
start() {
|
|
609
|
+
this.running = true;
|
|
610
|
+
this.scheduleCycle();
|
|
611
|
+
}
|
|
612
|
+
stop() {
|
|
613
|
+
this.running = false;
|
|
614
|
+
if (this.cycleTimer) {
|
|
615
|
+
clearTimeout(this.cycleTimer);
|
|
616
|
+
this.cycleTimer = null;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
onLog(callback) {
|
|
620
|
+
this.listeners.push(callback);
|
|
621
|
+
return () => {
|
|
622
|
+
this.listeners = this.listeners.filter((l) => l !== callback);
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
onPoolTransaction(callback) {
|
|
626
|
+
this.poolTxListeners.push(callback);
|
|
627
|
+
return () => {
|
|
628
|
+
this.poolTxListeners = this.poolTxListeners.filter((l) => l !== callback);
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
isRunning() {
|
|
632
|
+
return this.running;
|
|
633
|
+
}
|
|
634
|
+
getStats() {
|
|
635
|
+
return {
|
|
636
|
+
totalPnl: this.totalPnl,
|
|
637
|
+
totalTrades: this.totalTrades,
|
|
638
|
+
totalPips: this.totalPips,
|
|
639
|
+
totalLots: this.totalLots,
|
|
640
|
+
positions: this.openPositions.length
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
getPairStates() {
|
|
644
|
+
return this.pairStates;
|
|
645
|
+
}
|
|
646
|
+
emitBootSequence() {
|
|
647
|
+
const bootMessages = [
|
|
648
|
+
{ msg: "Initializing StableFX Engine v2.1.0...", delay: 0 },
|
|
649
|
+
{ msg: "Connecting to Circle StableFX RFQ network...", delay: 500 },
|
|
650
|
+
{ msg: "Loading USDC stablecoin pair feeds (6 pairs)...", delay: 1200 },
|
|
651
|
+
{ msg: "Calibrating PvP settlement engine...", delay: 2e3 },
|
|
652
|
+
{ msg: "Initializing clearing pool ($12.5M)...", delay: 2800 },
|
|
653
|
+
{ msg: "Initializing hedging pool ($7.5M)...", delay: 3400 },
|
|
654
|
+
{ msg: "Initializing insurance pool ($5.0M)...", delay: 4e3 },
|
|
655
|
+
{ msg: "Risk management module online (max exposure: 25%)", delay: 4500 },
|
|
656
|
+
{ msg: "=== StableFX Engine ready. Starting RFQ cycles ===", delay: 5e3 }
|
|
657
|
+
];
|
|
658
|
+
for (const { msg, delay } of bootMessages) {
|
|
659
|
+
setTimeout(() => {
|
|
660
|
+
this.emit({
|
|
661
|
+
id: genId2(),
|
|
662
|
+
timestamp: Date.now(),
|
|
663
|
+
type: "SYSTEM",
|
|
664
|
+
message: msg,
|
|
665
|
+
importance: "medium"
|
|
666
|
+
});
|
|
667
|
+
}, delay);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
destroy() {
|
|
671
|
+
this.stop();
|
|
672
|
+
this.listeners = [];
|
|
673
|
+
this.poolTxListeners = [];
|
|
674
|
+
this.pairStates.clear();
|
|
675
|
+
this.openPositions = [];
|
|
676
|
+
}
|
|
677
|
+
// ── Private Methods ────────────────────────────────────────────────────────
|
|
678
|
+
emit(entry) {
|
|
679
|
+
for (const listener of this.listeners) {
|
|
680
|
+
listener(entry);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
emitPoolTx(tx) {
|
|
684
|
+
for (const listener of this.poolTxListeners) {
|
|
685
|
+
listener(tx);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
generatePoolTxFromEvent(type, data) {
|
|
689
|
+
try {
|
|
690
|
+
const { ForexPoolDataGenerator: ForexPoolDataGenerator2 } = (init_ForexPoolDataGenerator(), __toCommonJS(ForexPoolDataGenerator_exports));
|
|
691
|
+
const generator = ForexPoolDataGenerator2.getInstance();
|
|
692
|
+
if (type === "SETTLE" && data.pnl !== void 0) {
|
|
693
|
+
const tx = generator.generateLiveTransaction("clearing", "fee_collection", Math.abs(data.pnl) * rand2(1e-3, 3e-3));
|
|
694
|
+
this.emitPoolTx(tx);
|
|
695
|
+
} else if (type === "HEDGE") {
|
|
696
|
+
const tx = generator.generateLiveTransaction("hedging", data.pnl && data.pnl < 0 ? "loss_absorption" : "profit_distribution", Math.abs(data.lots || 1) * rand2(50, 200));
|
|
697
|
+
this.emitPoolTx(tx);
|
|
698
|
+
} else if (type === "CLEAR") {
|
|
699
|
+
const tx = generator.generateLiveTransaction("clearing", "profit_distribution", (data.volume || 1e5) * rand2(1e-4, 5e-4));
|
|
700
|
+
this.emitPoolTx(tx);
|
|
701
|
+
}
|
|
702
|
+
} catch {
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
scheduleCycle() {
|
|
706
|
+
if (!this.running) return;
|
|
707
|
+
const interval = rand2(8e3, 14e3);
|
|
708
|
+
this.cycleTimer = setTimeout(() => {
|
|
709
|
+
if (this.running) {
|
|
710
|
+
this.runTradeCycle();
|
|
711
|
+
this.scheduleCycle();
|
|
712
|
+
}
|
|
713
|
+
}, interval);
|
|
714
|
+
}
|
|
715
|
+
simulatePrice(pairId) {
|
|
716
|
+
const state = this.pairStates.get(pairId);
|
|
717
|
+
if (!state) return 0;
|
|
718
|
+
const volatility = state.pair.id.includes("JPYC") ? 8e-4 : 4e-4;
|
|
719
|
+
const drift = rand2(-volatility, volatility);
|
|
720
|
+
const newPrice = state.currentPrice * (1 + drift);
|
|
721
|
+
const halfSpread = (state.pair.spreadPips + rand2(-0.3, 0.3)) * state.pair.pipSize / 2;
|
|
722
|
+
state.currentPrice = newPrice;
|
|
723
|
+
state.bidPrice = newPrice - halfSpread;
|
|
724
|
+
state.askPrice = newPrice + halfSpread;
|
|
725
|
+
state.lastSpread = halfSpread * 2 / state.pair.pipSize;
|
|
726
|
+
return newPrice;
|
|
727
|
+
}
|
|
728
|
+
runTradeCycle() {
|
|
729
|
+
const pairState = pick3(Array.from(this.pairStates.values()));
|
|
730
|
+
const pair = pairState.pair;
|
|
731
|
+
const entries = [];
|
|
732
|
+
let delay = 0;
|
|
733
|
+
const price = this.simulatePrice(pair.id);
|
|
734
|
+
const side = Math.random() > 0.5 ? "BUY" : "SELL";
|
|
735
|
+
const lots = parseFloat(rand2(0.1, 2.5).toFixed(2));
|
|
736
|
+
const notional = lots * 1e5;
|
|
737
|
+
const rfqId = tradeId();
|
|
738
|
+
entries.push({
|
|
739
|
+
entry: {
|
|
740
|
+
type: "RFQ",
|
|
741
|
+
message: `RFQ ${rfqId} | ${pair.symbol} ${side} ${lots.toFixed(2)} lots ($${(notional / 1e3).toFixed(0)}K) | Mid: ${formatRate(price, pair)}`,
|
|
742
|
+
data: { rfqId, pair: pair.id, side, lots, price },
|
|
743
|
+
importance: "medium",
|
|
744
|
+
pairId: pair.id
|
|
745
|
+
},
|
|
746
|
+
delay
|
|
747
|
+
});
|
|
748
|
+
delay += rand2(400, 800);
|
|
749
|
+
const quoteSpread = rand2(0.5, 2) * pair.pipSize;
|
|
750
|
+
const quotePrice = side === "BUY" ? price + quoteSpread : price - quoteSpread;
|
|
751
|
+
const quotePips = Math.abs(quotePrice - price) / pair.pipSize;
|
|
752
|
+
entries.push({
|
|
753
|
+
entry: {
|
|
754
|
+
type: "QUOTE",
|
|
755
|
+
message: `QUOTE ${rfqId} | ${pair.symbol} @ ${formatRate(quotePrice, pair)} | Spread: ${quotePips.toFixed(1)} pips | Valid: 3s`,
|
|
756
|
+
data: { rfqId, quotePrice, spread: quotePips },
|
|
757
|
+
importance: "medium",
|
|
758
|
+
pairId: pair.id
|
|
759
|
+
},
|
|
760
|
+
delay
|
|
761
|
+
});
|
|
762
|
+
delay += rand2(500, 1e3);
|
|
763
|
+
const matched = Math.random() < 0.85;
|
|
764
|
+
if (matched) {
|
|
765
|
+
const matchPrice = quotePrice * (1 + rand2(-5e-5, 5e-5));
|
|
766
|
+
entries.push({
|
|
767
|
+
entry: {
|
|
768
|
+
type: "MATCH",
|
|
769
|
+
message: `MATCH ${rfqId} | ${pair.symbol} ${side} @ ${formatRate(matchPrice, pair)} | ${lots.toFixed(2)} lots | Counterparty: LP-${randInt2(1, 8)}`,
|
|
770
|
+
data: { rfqId, matchPrice, counterparty: `LP-${randInt2(1, 8)}` },
|
|
771
|
+
importance: "high",
|
|
772
|
+
pairId: pair.id
|
|
773
|
+
},
|
|
774
|
+
delay
|
|
775
|
+
});
|
|
776
|
+
delay += rand2(1e3, 2500);
|
|
777
|
+
const settlePrice = matchPrice * (1 + rand2(-2e-5, 2e-5));
|
|
778
|
+
const pips = (settlePrice - price) / pair.pipSize * (side === "BUY" ? 1 : -1);
|
|
779
|
+
const pnl = pips * pair.pipSize * lots * 1e5;
|
|
780
|
+
entries.push({
|
|
781
|
+
entry: {
|
|
782
|
+
type: "SETTLE",
|
|
783
|
+
message: `SETTLE ${rfqId} | PvP confirmed | ${pair.symbol} @ ${formatRate(settlePrice, pair)} | P&L: ${pips >= 0 ? "+" : ""}${pips.toFixed(1)} pips ($${pnl >= 0 ? "+" : ""}${pnl.toFixed(2)})`,
|
|
784
|
+
data: { rfqId, settlePrice, pips, pnl, pvp: true },
|
|
785
|
+
importance: "high",
|
|
786
|
+
pairId: pair.id
|
|
787
|
+
},
|
|
788
|
+
delay
|
|
789
|
+
});
|
|
790
|
+
delay += rand2(300, 600);
|
|
791
|
+
entries.push({
|
|
792
|
+
entry: {
|
|
793
|
+
type: "PVP",
|
|
794
|
+
message: `PvP ${rfqId} | Atomic settlement confirmed on-chain | USDC transferred: $${notional.toLocaleString()} | Gas: ~$0.${randInt2(10, 50)}`,
|
|
795
|
+
data: { rfqId, settled: true, gasWei: randInt2(10, 50) },
|
|
796
|
+
importance: "medium",
|
|
797
|
+
pairId: pair.id
|
|
798
|
+
},
|
|
799
|
+
delay
|
|
800
|
+
});
|
|
801
|
+
this.generatePoolTxFromEvent("SETTLE", { pnl });
|
|
802
|
+
this.totalTrades++;
|
|
803
|
+
this.totalPnl += pnl;
|
|
804
|
+
this.totalPips += pips;
|
|
805
|
+
this.totalLots += lots;
|
|
806
|
+
if (Math.random() < 0.4) {
|
|
807
|
+
this.openPositions.push({
|
|
808
|
+
id: rfqId,
|
|
809
|
+
pairId: pair.id,
|
|
810
|
+
side,
|
|
811
|
+
lots,
|
|
812
|
+
pips,
|
|
813
|
+
entryPrice: matchPrice,
|
|
814
|
+
currentPrice: settlePrice,
|
|
815
|
+
pnl,
|
|
816
|
+
openTime: Date.now()
|
|
817
|
+
});
|
|
818
|
+
if (this.openPositions.length > 5) {
|
|
819
|
+
this.openPositions.shift();
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
} else {
|
|
823
|
+
entries.push({
|
|
824
|
+
entry: {
|
|
825
|
+
type: "MATCH",
|
|
826
|
+
message: `MATCH FAILED ${rfqId} | ${pair.symbol} | No counterparty at requested price | Requoting...`,
|
|
827
|
+
data: { rfqId, matched: false },
|
|
828
|
+
importance: "low",
|
|
829
|
+
pairId: pair.id
|
|
830
|
+
},
|
|
831
|
+
delay
|
|
832
|
+
});
|
|
833
|
+
}
|
|
834
|
+
if (Math.random() < 0.2) {
|
|
835
|
+
delay += rand2(400, 800);
|
|
836
|
+
const hedgePair = pick3(FOREX_CURRENCY_PAIRS);
|
|
837
|
+
const hedgeLots = parseFloat(rand2(0.5, 5).toFixed(2));
|
|
838
|
+
const hedgeDirection = Math.random() > 0.5 ? "LONG" : "SHORT";
|
|
839
|
+
entries.push({
|
|
840
|
+
entry: {
|
|
841
|
+
type: "HEDGE",
|
|
842
|
+
message: `HEDGE | ${hedgePair.symbol} ${hedgeDirection} ${hedgeLots.toFixed(2)} lots | Pool delta neutralization | Exposure: ${rand2(5, 20).toFixed(1)}%`,
|
|
843
|
+
data: { pair: hedgePair.id, direction: hedgeDirection, lots: hedgeLots },
|
|
844
|
+
importance: "medium"
|
|
845
|
+
},
|
|
846
|
+
delay
|
|
847
|
+
});
|
|
848
|
+
this.generatePoolTxFromEvent("HEDGE", { lots: hedgeLots });
|
|
849
|
+
}
|
|
850
|
+
if (Math.random() < 0.15) {
|
|
851
|
+
delay += rand2(300, 600);
|
|
852
|
+
const clearAmount = randInt2(5e4, 5e5);
|
|
853
|
+
entries.push({
|
|
854
|
+
entry: {
|
|
855
|
+
type: "CLEAR",
|
|
856
|
+
message: `CLEAR | Netting cycle complete | Volume: $${(clearAmount / 1e3).toFixed(0)}K | Pairs settled: ${randInt2(2, 6)} | Pool util: ${rand2(60, 85).toFixed(1)}%`,
|
|
857
|
+
data: { volume: clearAmount, pairsSettled: randInt2(2, 6) },
|
|
858
|
+
importance: "low"
|
|
859
|
+
},
|
|
860
|
+
delay
|
|
861
|
+
});
|
|
862
|
+
this.generatePoolTxFromEvent("CLEAR", { volume: clearAmount });
|
|
863
|
+
}
|
|
864
|
+
if (this.openPositions.length > 0 && Math.random() < 0.25) {
|
|
865
|
+
delay += rand2(300, 600);
|
|
866
|
+
const posUpdates = this.openPositions.slice(0, 3).map((pos) => {
|
|
867
|
+
const pState = this.pairStates.get(pos.pairId);
|
|
868
|
+
if (pState) {
|
|
869
|
+
pos.currentPrice = pState.currentPrice;
|
|
870
|
+
pos.pips = (pos.currentPrice - pos.entryPrice) / pState.pair.pipSize * (pos.side === "BUY" ? 1 : -1);
|
|
871
|
+
pos.pnl = pos.pips * pState.pair.pipSize * pos.lots * 1e5;
|
|
872
|
+
}
|
|
873
|
+
return `${pState?.pair.symbol || pos.pairId} ${pos.side}: ${pos.pips >= 0 ? "+" : ""}${pos.pips.toFixed(1)} pips`;
|
|
874
|
+
});
|
|
875
|
+
entries.push({
|
|
876
|
+
entry: {
|
|
877
|
+
type: "POSITION",
|
|
878
|
+
message: `POSITION | ${posUpdates.join(" | ")} | Open: ${this.openPositions.length}`,
|
|
879
|
+
data: { positions: this.openPositions.length },
|
|
880
|
+
importance: "low"
|
|
881
|
+
},
|
|
882
|
+
delay
|
|
883
|
+
});
|
|
884
|
+
if (this.openPositions.length > 2 && Math.random() < 0.3) {
|
|
885
|
+
const closed = this.openPositions.shift();
|
|
886
|
+
this.totalPnl += closed.pnl * rand2(0.01, 0.03);
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
if (Math.random() < 0.3) {
|
|
890
|
+
delay += rand2(300, 600);
|
|
891
|
+
entries.push({
|
|
892
|
+
entry: {
|
|
893
|
+
type: "PNL",
|
|
894
|
+
message: `PNL | Session: $${this.totalPnl >= 0 ? "+" : ""}${this.totalPnl.toFixed(2)} | Trades: ${this.totalTrades} | Pips: ${this.totalPips >= 0 ? "+" : ""}${this.totalPips.toFixed(1)} | Lots: ${this.totalLots.toFixed(2)}`,
|
|
895
|
+
data: { totalPnl: this.totalPnl, totalTrades: this.totalTrades, totalPips: this.totalPips },
|
|
896
|
+
importance: "medium"
|
|
897
|
+
},
|
|
898
|
+
delay
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
if (Math.random() < 0.1) {
|
|
902
|
+
delay += rand2(300, 600);
|
|
903
|
+
entries.push({
|
|
904
|
+
entry: {
|
|
905
|
+
type: "SYSTEM",
|
|
906
|
+
message: `[Market] ${pick3(FX_NEWS)}`,
|
|
907
|
+
importance: "medium"
|
|
908
|
+
},
|
|
909
|
+
delay
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
for (const { entry, delay: d } of entries) {
|
|
913
|
+
setTimeout(() => {
|
|
914
|
+
if (this.running) {
|
|
915
|
+
this.emit({
|
|
916
|
+
...entry,
|
|
917
|
+
id: genId2(),
|
|
918
|
+
timestamp: Date.now()
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
}, d);
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
};
|
|
925
|
+
forexSimulationEngine = new ForexSimulationEngine();
|
|
926
|
+
}
|
|
927
|
+
});
|
|
4
928
|
|
|
5
929
|
// src/config/index.ts
|
|
6
930
|
var DEFAULT_ENGINE_URL = "https://api.one23.io";
|
|
@@ -121,6 +1045,189 @@ var CHAIN_CONFIGS = {
|
|
|
121
1045
|
}
|
|
122
1046
|
};
|
|
123
1047
|
|
|
1048
|
+
// src/types/aiTrading.ts
|
|
1049
|
+
var PENALTY_TIERS = [
|
|
1050
|
+
{ minProgress: 0.75, maxProgress: 1, rate: 0.5, label: "50%" },
|
|
1051
|
+
{ minProgress: 0.5, maxProgress: 0.75, rate: 0.6, label: "60%" },
|
|
1052
|
+
{ minProgress: 0.25, maxProgress: 0.5, rate: 0.7, label: "70%" },
|
|
1053
|
+
{ minProgress: 0, maxProgress: 0.25, rate: 0.8, label: "80%" }
|
|
1054
|
+
];
|
|
1055
|
+
function calculateEarlyWithdrawalPenalty(investedAmount, profit, lockProgress) {
|
|
1056
|
+
const totalValue = investedAmount + profit;
|
|
1057
|
+
const isEarlyWithdrawal = lockProgress < 1;
|
|
1058
|
+
let penaltyRate = 0;
|
|
1059
|
+
if (isEarlyWithdrawal) {
|
|
1060
|
+
if (lockProgress >= 0.75) penaltyRate = 0.5;
|
|
1061
|
+
else if (lockProgress >= 0.5) penaltyRate = 0.6;
|
|
1062
|
+
else if (lockProgress >= 0.25) penaltyRate = 0.7;
|
|
1063
|
+
else penaltyRate = 0.8;
|
|
1064
|
+
}
|
|
1065
|
+
const estimatedPenalty = totalValue * penaltyRate;
|
|
1066
|
+
const estimatedRedemption = totalValue - estimatedPenalty;
|
|
1067
|
+
return { completionRate: lockProgress, penaltyRate, estimatedPenalty, estimatedRedemption, isEarlyWithdrawal };
|
|
1068
|
+
}
|
|
1069
|
+
var STRATEGY_CATEGORIES = {
|
|
1070
|
+
conservative: { labelKey: "ai.category_conservative", color: "#10B981", icon: "\u{1F6E1}\uFE0F" },
|
|
1071
|
+
balanced: { labelKey: "ai.category_balanced", color: "#3B82F6", icon: "\u2696\uFE0F" },
|
|
1072
|
+
aggressive: { labelKey: "ai.category_aggressive", color: "#EF4444", icon: "\u{1F680}" },
|
|
1073
|
+
hedge: { labelKey: "ai.category_hedge", color: "#8B5CF6", icon: "\u{1F512}" },
|
|
1074
|
+
arbitrage: { labelKey: "ai.category_arbitrage", color: "#F59E0B", icon: "\u26A1" },
|
|
1075
|
+
trend: { labelKey: "ai.category_trend", color: "#EC4899", icon: "\u{1F4C8}" },
|
|
1076
|
+
grid: { labelKey: "ai.category_grid", color: "#6366F1", icon: "\u25A6" },
|
|
1077
|
+
dca: { labelKey: "ai.category_dca", color: "#14B8A6", icon: "\u{1F4CA}" }
|
|
1078
|
+
};
|
|
1079
|
+
var RISK_LEVELS = {
|
|
1080
|
+
1: { labelKey: "ai.risk_very_low", color: "#10B981", bgColor: "#D1FAE5" },
|
|
1081
|
+
2: { labelKey: "ai.risk_low", color: "#22C55E", bgColor: "#DCFCE7" },
|
|
1082
|
+
3: { labelKey: "ai.risk_medium", color: "#F59E0B", bgColor: "#FEF3C7" },
|
|
1083
|
+
4: { labelKey: "ai.risk_high", color: "#F97316", bgColor: "#FFEDD5" },
|
|
1084
|
+
5: { labelKey: "ai.risk_very_high", color: "#EF4444", bgColor: "#FEE2E2" }
|
|
1085
|
+
};
|
|
1086
|
+
var ORDER_STATUS_CONFIG = {
|
|
1087
|
+
pending: { labelKey: "ai.status_pending", color: "#F59E0B", bgColor: "#FEF3C7" },
|
|
1088
|
+
active: { labelKey: "ai.status_active", color: "#10B981", bgColor: "#D1FAE5" },
|
|
1089
|
+
paused: { labelKey: "ai.status_paused", color: "#6B7280", bgColor: "#F3F4F6" },
|
|
1090
|
+
completed: { labelKey: "ai.status_completed", color: "#3B82F6", bgColor: "#DBEAFE" },
|
|
1091
|
+
cancelled: { labelKey: "ai.status_cancelled", color: "#EF4444", bgColor: "#FEE2E2" },
|
|
1092
|
+
pending_redemption: { labelKey: "ai.status_pending_redemption", color: "#8B5CF6", bgColor: "#EDE9FE" },
|
|
1093
|
+
redeemed: { labelKey: "ai.status_redeemed", color: "#14B8A6", bgColor: "#CCFBF1" }
|
|
1094
|
+
};
|
|
1095
|
+
|
|
1096
|
+
// src/types/console.ts
|
|
1097
|
+
var AI_LOG_COLORS = {
|
|
1098
|
+
SCAN: "#06B6D4",
|
|
1099
|
+
// Cyan
|
|
1100
|
+
THINKING: "#A855F7",
|
|
1101
|
+
// Purple
|
|
1102
|
+
INDICATOR: "#3B82F6",
|
|
1103
|
+
// Blue
|
|
1104
|
+
ANALYSIS: "#6366F1",
|
|
1105
|
+
// Indigo
|
|
1106
|
+
SIGNAL: "#F59E0B",
|
|
1107
|
+
// Amber
|
|
1108
|
+
STRATEGY: "#D946EF",
|
|
1109
|
+
// Fuchsia
|
|
1110
|
+
DECISION: "#F97316",
|
|
1111
|
+
// Orange
|
|
1112
|
+
ORDER: "#EC4899",
|
|
1113
|
+
// Pink
|
|
1114
|
+
FILLED: "#10B981",
|
|
1115
|
+
// Green
|
|
1116
|
+
PNL: "#22C55E",
|
|
1117
|
+
// Emerald
|
|
1118
|
+
RISK: "#EF4444",
|
|
1119
|
+
// Red
|
|
1120
|
+
NEWS: "#14B8A6",
|
|
1121
|
+
// Teal
|
|
1122
|
+
SYSTEM: "#9CA3AF"
|
|
1123
|
+
// Gray
|
|
1124
|
+
};
|
|
1125
|
+
var FOREX_LOG_COLORS = {
|
|
1126
|
+
RFQ: "#06B6D4",
|
|
1127
|
+
// Cyan
|
|
1128
|
+
QUOTE: "#8B5CF6",
|
|
1129
|
+
// Purple
|
|
1130
|
+
MATCH: "#10B981",
|
|
1131
|
+
// Green
|
|
1132
|
+
SETTLE: "#F59E0B",
|
|
1133
|
+
// Amber
|
|
1134
|
+
PVP: "#3B82F6",
|
|
1135
|
+
// Blue
|
|
1136
|
+
HEDGE: "#EC4899",
|
|
1137
|
+
// Pink
|
|
1138
|
+
CLEAR: "#14B8A6",
|
|
1139
|
+
// Teal
|
|
1140
|
+
POSITION: "#6366F1",
|
|
1141
|
+
// Indigo
|
|
1142
|
+
PNL: "#22C55E",
|
|
1143
|
+
// Emerald
|
|
1144
|
+
SYSTEM: "#9CA3AF"
|
|
1145
|
+
// Gray
|
|
1146
|
+
};
|
|
1147
|
+
var RISK_LEVEL_COLORS = {
|
|
1148
|
+
low: { color: "#10B981", bgColor: "#D1FAE5" },
|
|
1149
|
+
medium: { color: "#F59E0B", bgColor: "#FEF3C7" },
|
|
1150
|
+
high: { color: "#F97316", bgColor: "#FFEDD5" },
|
|
1151
|
+
critical: { color: "#EF4444", bgColor: "#FEE2E2" }
|
|
1152
|
+
};
|
|
1153
|
+
var TRADING_STATUS_COLORS = {
|
|
1154
|
+
active: { color: "#10B981", bgColor: "#D1FAE5" },
|
|
1155
|
+
paused: { color: "#F59E0B", bgColor: "#FEF3C7" },
|
|
1156
|
+
stopped: { color: "#EF4444", bgColor: "#FEE2E2" },
|
|
1157
|
+
cooldown: { color: "#6366F1", bgColor: "#E0E7FF" }
|
|
1158
|
+
};
|
|
1159
|
+
var AGENT_STATUS_COLORS = {
|
|
1160
|
+
active: { color: "#10B981", bgColor: "#D1FAE5", label: "Active" },
|
|
1161
|
+
paused: { color: "#F59E0B", bgColor: "#FEF3C7", label: "Paused" },
|
|
1162
|
+
idle: { color: "#6B7280", bgColor: "#F3F4F6", label: "Idle" },
|
|
1163
|
+
error: { color: "#EF4444", bgColor: "#FEE2E2", label: "Error" },
|
|
1164
|
+
initializing: { color: "#3B82F6", bgColor: "#DBEAFE", label: "Starting" }
|
|
1165
|
+
};
|
|
1166
|
+
var DEFAULT_CONSOLE_OPTIONS = {
|
|
1167
|
+
simulation: true,
|
|
1168
|
+
pollInterval: 5e3,
|
|
1169
|
+
maxLogs: 500,
|
|
1170
|
+
autoStart: false
|
|
1171
|
+
};
|
|
1172
|
+
var DEFAULT_RISK_STATUS = {
|
|
1173
|
+
timestamp: Date.now(),
|
|
1174
|
+
totalExposure: 0,
|
|
1175
|
+
maxExposure: 1e5,
|
|
1176
|
+
exposurePercent: 0,
|
|
1177
|
+
dailyPnl: 0,
|
|
1178
|
+
dailyPnlLimit: 5e3,
|
|
1179
|
+
dailyPnlPercent: 0,
|
|
1180
|
+
dailyTradeCount: 0,
|
|
1181
|
+
dailyTradeLimit: 50,
|
|
1182
|
+
currentDrawdown: 0,
|
|
1183
|
+
maxDrawdown: 15,
|
|
1184
|
+
drawdownPercent: 0,
|
|
1185
|
+
openPositions: 0,
|
|
1186
|
+
maxPositions: 10,
|
|
1187
|
+
riskLevel: "low",
|
|
1188
|
+
tradingStatus: "active",
|
|
1189
|
+
warnings: []
|
|
1190
|
+
};
|
|
1191
|
+
var DEFAULT_CONSOLE_METRICS = {
|
|
1192
|
+
nav: 0,
|
|
1193
|
+
navChange24h: 0,
|
|
1194
|
+
navChangePercent24h: 0,
|
|
1195
|
+
totalPnl: 0,
|
|
1196
|
+
realizedPnl: 0,
|
|
1197
|
+
unrealizedPnl: 0,
|
|
1198
|
+
pnlToday: 0,
|
|
1199
|
+
pnl7d: 0,
|
|
1200
|
+
pnl30d: 0,
|
|
1201
|
+
totalTrades: 0,
|
|
1202
|
+
tradesToday: 0,
|
|
1203
|
+
winRate: 0,
|
|
1204
|
+
winCount: 0,
|
|
1205
|
+
lossCount: 0,
|
|
1206
|
+
avgWin: 0,
|
|
1207
|
+
avgLoss: 0,
|
|
1208
|
+
profitFactor: 0,
|
|
1209
|
+
openPositions: 0,
|
|
1210
|
+
totalExposure: 0,
|
|
1211
|
+
avgLeverage: 0
|
|
1212
|
+
};
|
|
1213
|
+
function calculateRiskLevel(exposurePercent, drawdownPercent, dailyPnlPercent) {
|
|
1214
|
+
const worstMetric = Math.max(exposurePercent, drawdownPercent, Math.abs(dailyPnlPercent));
|
|
1215
|
+
if (worstMetric >= 90) return "critical";
|
|
1216
|
+
if (worstMetric >= 70) return "high";
|
|
1217
|
+
if (worstMetric >= 40) return "medium";
|
|
1218
|
+
return "low";
|
|
1219
|
+
}
|
|
1220
|
+
function formatPnl(pnl) {
|
|
1221
|
+
const sign = pnl >= 0 ? "+" : "";
|
|
1222
|
+
if (Math.abs(pnl) >= 1e6) {
|
|
1223
|
+
return `${sign}$${(pnl / 1e6).toFixed(2)}M`;
|
|
1224
|
+
}
|
|
1225
|
+
if (Math.abs(pnl) >= 1e3) {
|
|
1226
|
+
return `${sign}$${(pnl / 1e3).toFixed(2)}K`;
|
|
1227
|
+
}
|
|
1228
|
+
return `${sign}$${pnl.toFixed(2)}`;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
124
1231
|
// src/services/engine.ts
|
|
125
1232
|
var OneEngineClient = class {
|
|
126
1233
|
constructor(options) {
|
|
@@ -1684,10 +2791,6 @@ var CHAIN_CONFIG = {
|
|
|
1684
2791
|
zksync: { name: "zkSync", icon: "\u2B22", color: "#8C8DFC" },
|
|
1685
2792
|
scroll: { name: "Scroll", icon: "\u25CE", color: "#FFEEDA" }
|
|
1686
2793
|
};
|
|
1687
|
-
var isDesktop = () => {
|
|
1688
|
-
const { width } = Dimensions.get("window");
|
|
1689
|
-
return Platform.OS === "web" && width >= 768;
|
|
1690
|
-
};
|
|
1691
2794
|
var OneChainSelector = ({
|
|
1692
2795
|
supportedChains,
|
|
1693
2796
|
selectedChains,
|
|
@@ -1697,12 +2800,9 @@ var OneChainSelector = ({
|
|
|
1697
2800
|
title,
|
|
1698
2801
|
subtitle,
|
|
1699
2802
|
minSelections = 1,
|
|
1700
|
-
placeholder = "Select chains...",
|
|
1701
2803
|
style,
|
|
1702
2804
|
titleStyle
|
|
1703
2805
|
}) => {
|
|
1704
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
1705
|
-
const desktop = isDesktop();
|
|
1706
2806
|
const handleSelect = (chain) => {
|
|
1707
2807
|
if (multiSelect) {
|
|
1708
2808
|
if (selectedChains.includes(chain) && selectedChains.length <= minSelections) {
|
|
@@ -1713,129 +2813,42 @@ var OneChainSelector = ({
|
|
|
1713
2813
|
if (!selectedChains.includes(chain)) {
|
|
1714
2814
|
onSelectChain(chain);
|
|
1715
2815
|
}
|
|
1716
|
-
setIsOpen(false);
|
|
1717
2816
|
}
|
|
1718
2817
|
};
|
|
1719
|
-
if (desktop) {
|
|
1720
|
-
return /* @__PURE__ */ jsxs(View, { style: [styles.container, style], children: [
|
|
1721
|
-
title && /* @__PURE__ */ jsx(Text, { style: [styles.title, titleStyle], children: title }),
|
|
1722
|
-
subtitle && /* @__PURE__ */ jsx(Text, { style: styles.subtitle, children: subtitle }),
|
|
1723
|
-
/* @__PURE__ */ jsx(View, { style: styles.desktopGrid, children: supportedChains.map((chain) => {
|
|
1724
|
-
const chainInfo = CHAIN_CONFIG[chain] || { name: chain, icon: "\u25CF", color: "#888" };
|
|
1725
|
-
const isSelected = selectedChains.includes(chain);
|
|
1726
|
-
return /* @__PURE__ */ jsxs(
|
|
1727
|
-
TouchableOpacity,
|
|
1728
|
-
{
|
|
1729
|
-
style: [
|
|
1730
|
-
styles.desktopChip,
|
|
1731
|
-
isSelected && styles.desktopChipSelected,
|
|
1732
|
-
isSelected && { borderColor: accentColor, backgroundColor: accentColor + "12" }
|
|
1733
|
-
],
|
|
1734
|
-
onPress: () => handleSelect(chain),
|
|
1735
|
-
activeOpacity: 0.7,
|
|
1736
|
-
children: [
|
|
1737
|
-
/* @__PURE__ */ jsx(View, { style: [styles.desktopIconBg, { backgroundColor: chainInfo.color + "20" }], children: /* @__PURE__ */ jsx(Text, { style: [styles.desktopIcon, { color: chainInfo.color }], children: chainInfo.icon }) }),
|
|
1738
|
-
/* @__PURE__ */ jsx(Text, { style: [
|
|
1739
|
-
styles.desktopChipText,
|
|
1740
|
-
isSelected && { color: accentColor, fontWeight: "600" }
|
|
1741
|
-
], children: chainInfo.name }),
|
|
1742
|
-
isSelected && /* @__PURE__ */ jsx(View, { style: [styles.desktopCheckbox, { backgroundColor: accentColor }], children: /* @__PURE__ */ jsx(Text, { style: styles.desktopCheckIcon, children: "\u2713" }) })
|
|
1743
|
-
]
|
|
1744
|
-
},
|
|
1745
|
-
chain
|
|
1746
|
-
);
|
|
1747
|
-
}) }),
|
|
1748
|
-
multiSelect && selectedChains.length > 0 && /* @__PURE__ */ jsxs(Text, { style: [styles.selectedCount, { color: accentColor }], children: [
|
|
1749
|
-
selectedChains.length,
|
|
1750
|
-
" chain",
|
|
1751
|
-
selectedChains.length > 1 ? "s" : "",
|
|
1752
|
-
" selected"
|
|
1753
|
-
] })
|
|
1754
|
-
] });
|
|
1755
|
-
}
|
|
1756
2818
|
return /* @__PURE__ */ jsxs(View, { style: [styles.container, style], children: [
|
|
1757
2819
|
title && /* @__PURE__ */ jsx(Text, { style: [styles.title, titleStyle], children: title }),
|
|
1758
2820
|
subtitle && /* @__PURE__ */ jsx(Text, { style: styles.subtitle, children: subtitle }),
|
|
1759
|
-
/* @__PURE__ */
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
2821
|
+
/* @__PURE__ */ jsx(View, { style: styles.chainsContainer, children: supportedChains.map((chain) => {
|
|
2822
|
+
const chainInfo = CHAIN_CONFIG[chain] || { name: chain, icon: "\u25CF", color: "#888" };
|
|
2823
|
+
const isSelected = selectedChains.includes(chain);
|
|
2824
|
+
return /* @__PURE__ */ jsxs(
|
|
2825
|
+
TouchableOpacity,
|
|
2826
|
+
{
|
|
2827
|
+
style: [
|
|
2828
|
+
styles.chainChip,
|
|
2829
|
+
isSelected && styles.chainChipSelected,
|
|
2830
|
+
isSelected && { borderColor: accentColor, backgroundColor: accentColor + "15" }
|
|
2831
|
+
],
|
|
2832
|
+
onPress: () => handleSelect(chain),
|
|
2833
|
+
activeOpacity: 0.7,
|
|
2834
|
+
children: [
|
|
2835
|
+
/* @__PURE__ */ jsx(View, { style: [styles.chainIconBg, { backgroundColor: chainInfo.color + "20" }], children: /* @__PURE__ */ jsx(Text, { style: [styles.chainIcon, { color: chainInfo.color }], children: chainInfo.icon }) }),
|
|
2836
|
+
/* @__PURE__ */ jsx(Text, { style: [
|
|
2837
|
+
styles.chainText,
|
|
2838
|
+
isSelected && { color: accentColor, fontWeight: "600" }
|
|
2839
|
+
], children: chainInfo.name }),
|
|
2840
|
+
isSelected && /* @__PURE__ */ jsx(Text, { style: [styles.checkmark, { color: accentColor }], children: "\u2713" })
|
|
2841
|
+
]
|
|
2842
|
+
},
|
|
2843
|
+
chain
|
|
2844
|
+
);
|
|
2845
|
+
}) }),
|
|
2846
|
+
multiSelect && selectedChains.length > 0 && /* @__PURE__ */ jsx(View, { style: styles.selectedInfo, children: /* @__PURE__ */ jsxs(Text, { style: styles.selectedText, children: [
|
|
1782
2847
|
selectedChains.length,
|
|
1783
2848
|
" chain",
|
|
1784
2849
|
selectedChains.length > 1 ? "s" : "",
|
|
1785
2850
|
" selected"
|
|
1786
|
-
] })
|
|
1787
|
-
/* @__PURE__ */ jsx(
|
|
1788
|
-
Modal,
|
|
1789
|
-
{
|
|
1790
|
-
visible: isOpen,
|
|
1791
|
-
transparent: true,
|
|
1792
|
-
animationType: "fade",
|
|
1793
|
-
onRequestClose: () => setIsOpen(false),
|
|
1794
|
-
children: /* @__PURE__ */ jsx(Pressable, { style: styles.modalOverlay, onPress: () => setIsOpen(false), children: /* @__PURE__ */ jsxs(View, { style: styles.modalContent, children: [
|
|
1795
|
-
/* @__PURE__ */ jsxs(View, { style: styles.modalHeader, children: [
|
|
1796
|
-
/* @__PURE__ */ jsx(Text, { style: styles.modalTitle, children: title || "Select Chains" }),
|
|
1797
|
-
/* @__PURE__ */ jsx(TouchableOpacity, { onPress: () => setIsOpen(false), children: /* @__PURE__ */ jsx(Text, { style: styles.modalClose, children: "\u2715" }) })
|
|
1798
|
-
] }),
|
|
1799
|
-
/* @__PURE__ */ jsx(ScrollView, { style: styles.optionsList, showsVerticalScrollIndicator: false, children: supportedChains.map((chain) => {
|
|
1800
|
-
const chainInfo = CHAIN_CONFIG[chain] || { name: chain, icon: "\u25CF", color: "#888" };
|
|
1801
|
-
const isSelected = selectedChains.includes(chain);
|
|
1802
|
-
return /* @__PURE__ */ jsxs(
|
|
1803
|
-
TouchableOpacity,
|
|
1804
|
-
{
|
|
1805
|
-
style: [
|
|
1806
|
-
styles.optionItem,
|
|
1807
|
-
isSelected && styles.optionItemSelected,
|
|
1808
|
-
isSelected && { backgroundColor: accentColor + "10", borderColor: accentColor }
|
|
1809
|
-
],
|
|
1810
|
-
onPress: () => handleSelect(chain),
|
|
1811
|
-
activeOpacity: 0.7,
|
|
1812
|
-
children: [
|
|
1813
|
-
/* @__PURE__ */ jsx(View, { style: [styles.optionIconBg, { backgroundColor: chainInfo.color + "20" }], children: /* @__PURE__ */ jsx(Text, { style: [styles.optionIcon, { color: chainInfo.color }], children: chainInfo.icon }) }),
|
|
1814
|
-
/* @__PURE__ */ jsx(Text, { style: [
|
|
1815
|
-
styles.optionText,
|
|
1816
|
-
isSelected && { color: accentColor, fontWeight: "600" }
|
|
1817
|
-
], children: chainInfo.name }),
|
|
1818
|
-
isSelected ? /* @__PURE__ */ jsx(View, { style: [styles.checkbox, { backgroundColor: accentColor }], children: /* @__PURE__ */ jsx(Text, { style: styles.checkboxIcon, children: "\u2713" }) }) : /* @__PURE__ */ jsx(View, { style: styles.checkboxEmpty })
|
|
1819
|
-
]
|
|
1820
|
-
},
|
|
1821
|
-
chain
|
|
1822
|
-
);
|
|
1823
|
-
}) }),
|
|
1824
|
-
multiSelect && /* @__PURE__ */ jsx(
|
|
1825
|
-
TouchableOpacity,
|
|
1826
|
-
{
|
|
1827
|
-
style: [styles.doneButton, { backgroundColor: accentColor }],
|
|
1828
|
-
onPress: () => setIsOpen(false),
|
|
1829
|
-
children: /* @__PURE__ */ jsxs(Text, { style: styles.doneButtonText, children: [
|
|
1830
|
-
"Done (",
|
|
1831
|
-
selectedChains.length,
|
|
1832
|
-
")"
|
|
1833
|
-
] })
|
|
1834
|
-
}
|
|
1835
|
-
)
|
|
1836
|
-
] }) })
|
|
1837
|
-
}
|
|
1838
|
-
)
|
|
2851
|
+
] }) })
|
|
1839
2852
|
] });
|
|
1840
2853
|
};
|
|
1841
2854
|
var styles = StyleSheet.create({
|
|
@@ -1853,207 +2866,51 @@ var styles = StyleSheet.create({
|
|
|
1853
2866
|
color: "#666",
|
|
1854
2867
|
marginBottom: 12
|
|
1855
2868
|
},
|
|
1856
|
-
|
|
1857
|
-
desktopGrid: {
|
|
2869
|
+
chainsContainer: {
|
|
1858
2870
|
flexDirection: "row",
|
|
1859
2871
|
flexWrap: "wrap",
|
|
1860
|
-
gap:
|
|
1861
|
-
},
|
|
1862
|
-
desktopChip: {
|
|
1863
|
-
flexDirection: "row",
|
|
1864
|
-
alignItems: "center",
|
|
1865
|
-
paddingHorizontal: 14,
|
|
1866
|
-
paddingVertical: 10,
|
|
1867
|
-
backgroundColor: "#fff",
|
|
1868
|
-
borderRadius: 10,
|
|
1869
|
-
borderWidth: 2,
|
|
1870
|
-
borderColor: "#e8e8e8",
|
|
1871
|
-
gap: 10,
|
|
1872
|
-
cursor: "pointer"
|
|
1873
|
-
},
|
|
1874
|
-
desktopChipSelected: {
|
|
1875
|
-
borderWidth: 2
|
|
1876
|
-
},
|
|
1877
|
-
desktopIconBg: {
|
|
1878
|
-
width: 32,
|
|
1879
|
-
height: 32,
|
|
1880
|
-
borderRadius: 16,
|
|
1881
|
-
alignItems: "center",
|
|
1882
|
-
justifyContent: "center"
|
|
1883
|
-
},
|
|
1884
|
-
desktopIcon: {
|
|
1885
|
-
fontSize: 14,
|
|
1886
|
-
fontWeight: "700"
|
|
1887
|
-
},
|
|
1888
|
-
desktopChipText: {
|
|
1889
|
-
fontSize: 14,
|
|
1890
|
-
color: "#444"
|
|
1891
|
-
},
|
|
1892
|
-
desktopCheckbox: {
|
|
1893
|
-
width: 20,
|
|
1894
|
-
height: 20,
|
|
1895
|
-
borderRadius: 10,
|
|
1896
|
-
alignItems: "center",
|
|
1897
|
-
justifyContent: "center",
|
|
1898
|
-
marginLeft: 4
|
|
1899
|
-
},
|
|
1900
|
-
desktopCheckIcon: {
|
|
1901
|
-
fontSize: 12,
|
|
1902
|
-
color: "#fff",
|
|
1903
|
-
fontWeight: "700"
|
|
2872
|
+
gap: 8
|
|
1904
2873
|
},
|
|
1905
|
-
|
|
1906
|
-
dropdownTrigger: {
|
|
2874
|
+
chainChip: {
|
|
1907
2875
|
flexDirection: "row",
|
|
1908
2876
|
alignItems: "center",
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
paddingVertical: 12,
|
|
2877
|
+
paddingHorizontal: 12,
|
|
2878
|
+
paddingVertical: 8,
|
|
1912
2879
|
backgroundColor: "#fff",
|
|
1913
2880
|
borderRadius: 12,
|
|
1914
2881
|
borderWidth: 2,
|
|
1915
2882
|
borderColor: "#e5e5e5",
|
|
1916
|
-
|
|
2883
|
+
gap: 8
|
|
1917
2884
|
},
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
flexDirection: "row",
|
|
1921
|
-
alignItems: "center",
|
|
1922
|
-
gap: 6
|
|
2885
|
+
chainChipSelected: {
|
|
2886
|
+
borderWidth: 2
|
|
1923
2887
|
},
|
|
1924
|
-
|
|
1925
|
-
width:
|
|
1926
|
-
height:
|
|
1927
|
-
borderRadius:
|
|
2888
|
+
chainIconBg: {
|
|
2889
|
+
width: 28,
|
|
2890
|
+
height: 28,
|
|
2891
|
+
borderRadius: 14,
|
|
1928
2892
|
alignItems: "center",
|
|
1929
2893
|
justifyContent: "center"
|
|
1930
2894
|
},
|
|
1931
|
-
|
|
2895
|
+
chainIcon: {
|
|
1932
2896
|
fontSize: 14,
|
|
1933
2897
|
fontWeight: "700"
|
|
1934
2898
|
},
|
|
1935
|
-
|
|
1936
|
-
paddingHorizontal: 8,
|
|
1937
|
-
paddingVertical: 4,
|
|
1938
|
-
backgroundColor: "#f0f0f0",
|
|
1939
|
-
borderRadius: 8
|
|
1940
|
-
},
|
|
1941
|
-
previewMoreText: {
|
|
1942
|
-
fontSize: 12,
|
|
1943
|
-
color: "#666",
|
|
1944
|
-
fontWeight: "600"
|
|
1945
|
-
},
|
|
1946
|
-
placeholderText: {
|
|
2899
|
+
chainText: {
|
|
1947
2900
|
fontSize: 14,
|
|
1948
|
-
color: "#
|
|
1949
|
-
},
|
|
1950
|
-
dropdownArrow: {
|
|
1951
|
-
fontSize: 12,
|
|
1952
|
-
color: "#888",
|
|
1953
|
-
marginLeft: 8
|
|
1954
|
-
},
|
|
1955
|
-
selectedCount: {
|
|
1956
|
-
fontSize: 12,
|
|
1957
|
-
marginTop: 6,
|
|
1958
|
-
fontWeight: "500"
|
|
1959
|
-
},
|
|
1960
|
-
// Modal styles
|
|
1961
|
-
modalOverlay: {
|
|
1962
|
-
flex: 1,
|
|
1963
|
-
backgroundColor: "rgba(0, 0, 0, 0.5)",
|
|
1964
|
-
justifyContent: "center",
|
|
1965
|
-
alignItems: "center"
|
|
1966
|
-
},
|
|
1967
|
-
modalContent: {
|
|
1968
|
-
width: "85%",
|
|
1969
|
-
maxWidth: 340,
|
|
1970
|
-
maxHeight: "70%",
|
|
1971
|
-
backgroundColor: "#fff",
|
|
1972
|
-
borderRadius: 16,
|
|
1973
|
-
overflow: "hidden"
|
|
1974
|
-
},
|
|
1975
|
-
modalHeader: {
|
|
1976
|
-
flexDirection: "row",
|
|
1977
|
-
justifyContent: "space-between",
|
|
1978
|
-
alignItems: "center",
|
|
1979
|
-
paddingHorizontal: 16,
|
|
1980
|
-
paddingVertical: 14,
|
|
1981
|
-
borderBottomWidth: 1,
|
|
1982
|
-
borderBottomColor: "#f0f0f0"
|
|
1983
|
-
},
|
|
1984
|
-
modalTitle: {
|
|
1985
|
-
fontSize: 18,
|
|
1986
|
-
fontWeight: "700",
|
|
1987
|
-
color: "#1a1a1a"
|
|
1988
|
-
},
|
|
1989
|
-
modalClose: {
|
|
1990
|
-
fontSize: 20,
|
|
1991
|
-
color: "#888",
|
|
1992
|
-
padding: 4
|
|
1993
|
-
},
|
|
1994
|
-
optionsList: {
|
|
1995
|
-
padding: 8
|
|
1996
|
-
},
|
|
1997
|
-
optionItem: {
|
|
1998
|
-
flexDirection: "row",
|
|
1999
|
-
alignItems: "center",
|
|
2000
|
-
paddingHorizontal: 12,
|
|
2001
|
-
paddingVertical: 12,
|
|
2002
|
-
borderRadius: 10,
|
|
2003
|
-
borderWidth: 1,
|
|
2004
|
-
borderColor: "transparent",
|
|
2005
|
-
marginBottom: 6,
|
|
2006
|
-
gap: 12
|
|
2007
|
-
},
|
|
2008
|
-
optionItemSelected: {
|
|
2009
|
-
borderWidth: 1
|
|
2010
|
-
},
|
|
2011
|
-
optionIconBg: {
|
|
2012
|
-
width: 36,
|
|
2013
|
-
height: 36,
|
|
2014
|
-
borderRadius: 18,
|
|
2015
|
-
alignItems: "center",
|
|
2016
|
-
justifyContent: "center"
|
|
2901
|
+
color: "#666"
|
|
2017
2902
|
},
|
|
2018
|
-
|
|
2903
|
+
checkmark: {
|
|
2019
2904
|
fontSize: 16,
|
|
2020
2905
|
fontWeight: "700"
|
|
2021
2906
|
},
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
color: "#333"
|
|
2026
|
-
},
|
|
2027
|
-
checkbox: {
|
|
2028
|
-
width: 24,
|
|
2029
|
-
height: 24,
|
|
2030
|
-
borderRadius: 12,
|
|
2031
|
-
alignItems: "center",
|
|
2032
|
-
justifyContent: "center"
|
|
2033
|
-
},
|
|
2034
|
-
checkboxIcon: {
|
|
2035
|
-
fontSize: 14,
|
|
2036
|
-
color: "#fff",
|
|
2037
|
-
fontWeight: "700"
|
|
2038
|
-
},
|
|
2039
|
-
checkboxEmpty: {
|
|
2040
|
-
width: 24,
|
|
2041
|
-
height: 24,
|
|
2042
|
-
borderRadius: 12,
|
|
2043
|
-
borderWidth: 2,
|
|
2044
|
-
borderColor: "#ddd"
|
|
2045
|
-
},
|
|
2046
|
-
doneButton: {
|
|
2047
|
-
marginHorizontal: 16,
|
|
2048
|
-
marginVertical: 12,
|
|
2049
|
-
paddingVertical: 14,
|
|
2050
|
-
borderRadius: 10,
|
|
2051
|
-
alignItems: "center"
|
|
2907
|
+
selectedInfo: {
|
|
2908
|
+
marginTop: 8,
|
|
2909
|
+
paddingVertical: 4
|
|
2052
2910
|
},
|
|
2053
|
-
|
|
2054
|
-
fontSize:
|
|
2055
|
-
|
|
2056
|
-
color: "#fff"
|
|
2911
|
+
selectedText: {
|
|
2912
|
+
fontSize: 12,
|
|
2913
|
+
color: "#888"
|
|
2057
2914
|
}
|
|
2058
2915
|
});
|
|
2059
2916
|
var OneTierSelector = ({
|
|
@@ -2323,30 +3180,23 @@ var styles3 = StyleSheet.create({
|
|
|
2323
3180
|
textAlign: "center"
|
|
2324
3181
|
}
|
|
2325
3182
|
});
|
|
2326
|
-
var
|
|
2327
|
-
"BTC
|
|
2328
|
-
"ETH
|
|
2329
|
-
"
|
|
2330
|
-
"
|
|
2331
|
-
"XRP
|
|
2332
|
-
"DOGE
|
|
2333
|
-
"ADA
|
|
2334
|
-
"AVAX
|
|
2335
|
-
"DOT
|
|
2336
|
-
"MATIC
|
|
2337
|
-
"LINK
|
|
2338
|
-
"UNI
|
|
2339
|
-
"ATOM
|
|
2340
|
-
"LTC
|
|
2341
|
-
"ARB
|
|
2342
|
-
"OP
|
|
2343
|
-
};
|
|
2344
|
-
var PAIR_ICONS = Object.fromEntries(
|
|
2345
|
-
Object.entries(PAIR_CONFIG).map(([key, value]) => [`${key}/USDT`, value.icon])
|
|
2346
|
-
);
|
|
2347
|
-
var isDesktop2 = () => {
|
|
2348
|
-
const { width } = Dimensions.get("window");
|
|
2349
|
-
return Platform.OS === "web" && width >= 768;
|
|
3183
|
+
var PAIR_ICONS = {
|
|
3184
|
+
"BTC/USDT": "\u20BF",
|
|
3185
|
+
"ETH/USDT": "\u039E",
|
|
3186
|
+
"SOL/USDT": "\u25CE",
|
|
3187
|
+
"BNB/USDT": "\u25C6",
|
|
3188
|
+
"XRP/USDT": "\u2715",
|
|
3189
|
+
"DOGE/USDT": "\xD0",
|
|
3190
|
+
"ADA/USDT": "\u25C8",
|
|
3191
|
+
"AVAX/USDT": "\u25B2",
|
|
3192
|
+
"DOT/USDT": "\u25CF",
|
|
3193
|
+
"MATIC/USDT": "\u2B21",
|
|
3194
|
+
"LINK/USDT": "\u25C7",
|
|
3195
|
+
"UNI/USDT": "\u{1F984}",
|
|
3196
|
+
"ATOM/USDT": "\u269B",
|
|
3197
|
+
"LTC/USDT": "\u0141",
|
|
3198
|
+
"ARB/USDT": "\u25C6",
|
|
3199
|
+
"OP/USDT": "\u25C9"
|
|
2350
3200
|
};
|
|
2351
3201
|
var OnePairSelector = ({
|
|
2352
3202
|
supportedPairs,
|
|
@@ -2357,12 +3207,9 @@ var OnePairSelector = ({
|
|
|
2357
3207
|
subtitle,
|
|
2358
3208
|
minSelections = 1,
|
|
2359
3209
|
maxSelections = 0,
|
|
2360
|
-
placeholder = "Select trading pairs...",
|
|
2361
3210
|
style,
|
|
2362
3211
|
titleStyle
|
|
2363
3212
|
}) => {
|
|
2364
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
2365
|
-
const desktop = isDesktop2();
|
|
2366
3213
|
const handleToggle = (pair) => {
|
|
2367
3214
|
const isSelected = selectedPairs.includes(pair);
|
|
2368
3215
|
if (isSelected && selectedPairs.length <= minSelections) {
|
|
@@ -2373,155 +3220,43 @@ var OnePairSelector = ({
|
|
|
2373
3220
|
}
|
|
2374
3221
|
onTogglePair(pair);
|
|
2375
3222
|
};
|
|
2376
|
-
const getPairInfo = (pair) => {
|
|
2377
|
-
return PAIR_CONFIG[pair] || { symbol: `${pair}/USDT`, name: pair, icon: "\u25CF", color: "#888" };
|
|
2378
|
-
};
|
|
2379
|
-
if (desktop) {
|
|
2380
|
-
return /* @__PURE__ */ jsxs(View, { style: [styles4.container, style], children: [
|
|
2381
|
-
title && /* @__PURE__ */ jsx(Text, { style: [styles4.title, titleStyle], children: title }),
|
|
2382
|
-
subtitle && /* @__PURE__ */ jsx(Text, { style: styles4.subtitle, children: subtitle }),
|
|
2383
|
-
/* @__PURE__ */ jsx(View, { style: styles4.desktopGrid, children: supportedPairs.map((pair) => {
|
|
2384
|
-
const pairInfo = getPairInfo(pair);
|
|
2385
|
-
const isSelected = selectedPairs.includes(pair);
|
|
2386
|
-
const isDisabled = !isSelected && maxSelections > 0 && selectedPairs.length >= maxSelections;
|
|
2387
|
-
return /* @__PURE__ */ jsxs(
|
|
2388
|
-
TouchableOpacity,
|
|
2389
|
-
{
|
|
2390
|
-
style: [
|
|
2391
|
-
styles4.desktopChip,
|
|
2392
|
-
isSelected && styles4.desktopChipSelected,
|
|
2393
|
-
isSelected && { borderColor: accentColor, backgroundColor: accentColor + "12" },
|
|
2394
|
-
isDisabled && styles4.desktopChipDisabled
|
|
2395
|
-
],
|
|
2396
|
-
onPress: () => handleToggle(pair),
|
|
2397
|
-
activeOpacity: isDisabled ? 1 : 0.7,
|
|
2398
|
-
children: [
|
|
2399
|
-
/* @__PURE__ */ jsx(View, { style: [styles4.desktopIconBg, { backgroundColor: pairInfo.color + "20" }], children: /* @__PURE__ */ jsx(Text, { style: [styles4.desktopIcon, { color: pairInfo.color }], children: pairInfo.icon }) }),
|
|
2400
|
-
/* @__PURE__ */ jsxs(View, { children: [
|
|
2401
|
-
/* @__PURE__ */ jsx(Text, { style: [
|
|
2402
|
-
styles4.desktopChipText,
|
|
2403
|
-
isSelected && { color: accentColor, fontWeight: "600" },
|
|
2404
|
-
isDisabled && styles4.desktopTextDisabled
|
|
2405
|
-
], children: pair }),
|
|
2406
|
-
/* @__PURE__ */ jsx(Text, { style: [styles4.desktopChipSubtext, isDisabled && styles4.desktopTextDisabled], children: pairInfo.name })
|
|
2407
|
-
] }),
|
|
2408
|
-
isSelected && /* @__PURE__ */ jsx(View, { style: [styles4.desktopCheckbox, { backgroundColor: accentColor }], children: /* @__PURE__ */ jsx(Text, { style: styles4.desktopCheckIcon, children: "\u2713" }) })
|
|
2409
|
-
]
|
|
2410
|
-
},
|
|
2411
|
-
pair
|
|
2412
|
-
);
|
|
2413
|
-
}) }),
|
|
2414
|
-
/* @__PURE__ */ jsxs(View, { style: styles4.infoRow, children: [
|
|
2415
|
-
/* @__PURE__ */ jsxs(Text, { style: [styles4.selectedCount, { color: accentColor }], children: [
|
|
2416
|
-
selectedPairs.length,
|
|
2417
|
-
" pair",
|
|
2418
|
-
selectedPairs.length !== 1 ? "s" : "",
|
|
2419
|
-
" selected"
|
|
2420
|
-
] }),
|
|
2421
|
-
(minSelections > 0 || maxSelections > 0) && /* @__PURE__ */ jsxs(Text, { style: styles4.limitText, children: [
|
|
2422
|
-
minSelections > 0 && `min: ${minSelections}`,
|
|
2423
|
-
minSelections > 0 && maxSelections > 0 && " / ",
|
|
2424
|
-
maxSelections > 0 && `max: ${maxSelections}`
|
|
2425
|
-
] })
|
|
2426
|
-
] })
|
|
2427
|
-
] });
|
|
2428
|
-
}
|
|
2429
3223
|
return /* @__PURE__ */ jsxs(View, { style: [styles4.container, style], children: [
|
|
2430
3224
|
title && /* @__PURE__ */ jsx(Text, { style: [styles4.title, titleStyle], children: title }),
|
|
2431
3225
|
subtitle && /* @__PURE__ */ jsx(Text, { style: styles4.subtitle, children: subtitle }),
|
|
2432
|
-
/* @__PURE__ */
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
] }),
|
|
2467
|
-
/* @__PURE__ */ jsx(
|
|
2468
|
-
Modal,
|
|
2469
|
-
{
|
|
2470
|
-
visible: isOpen,
|
|
2471
|
-
transparent: true,
|
|
2472
|
-
animationType: "fade",
|
|
2473
|
-
onRequestClose: () => setIsOpen(false),
|
|
2474
|
-
children: /* @__PURE__ */ jsx(Pressable, { style: styles4.modalOverlay, onPress: () => setIsOpen(false), children: /* @__PURE__ */ jsxs(View, { style: styles4.modalContent, children: [
|
|
2475
|
-
/* @__PURE__ */ jsxs(View, { style: styles4.modalHeader, children: [
|
|
2476
|
-
/* @__PURE__ */ jsx(Text, { style: styles4.modalTitle, children: title || "Select Trading Pairs" }),
|
|
2477
|
-
/* @__PURE__ */ jsx(TouchableOpacity, { onPress: () => setIsOpen(false), children: /* @__PURE__ */ jsx(Text, { style: styles4.modalClose, children: "\u2715" }) })
|
|
2478
|
-
] }),
|
|
2479
|
-
/* @__PURE__ */ jsx(ScrollView, { style: styles4.optionsList, showsVerticalScrollIndicator: false, children: supportedPairs.map((pair) => {
|
|
2480
|
-
const pairInfo = getPairInfo(pair);
|
|
2481
|
-
const isSelected = selectedPairs.includes(pair);
|
|
2482
|
-
const isDisabled = !isSelected && maxSelections > 0 && selectedPairs.length >= maxSelections;
|
|
2483
|
-
return /* @__PURE__ */ jsxs(
|
|
2484
|
-
TouchableOpacity,
|
|
2485
|
-
{
|
|
2486
|
-
style: [
|
|
2487
|
-
styles4.optionItem,
|
|
2488
|
-
isSelected && styles4.optionItemSelected,
|
|
2489
|
-
isSelected && { backgroundColor: accentColor + "10", borderColor: accentColor },
|
|
2490
|
-
isDisabled && styles4.optionItemDisabled
|
|
2491
|
-
],
|
|
2492
|
-
onPress: () => handleToggle(pair),
|
|
2493
|
-
activeOpacity: isDisabled ? 1 : 0.7,
|
|
2494
|
-
children: [
|
|
2495
|
-
/* @__PURE__ */ jsx(View, { style: [styles4.optionIconBg, { backgroundColor: pairInfo.color + "20" }], children: /* @__PURE__ */ jsx(Text, { style: [styles4.optionIcon, { color: pairInfo.color }], children: pairInfo.icon }) }),
|
|
2496
|
-
/* @__PURE__ */ jsxs(View, { style: styles4.optionTextContainer, children: [
|
|
2497
|
-
/* @__PURE__ */ jsx(Text, { style: [
|
|
2498
|
-
styles4.optionSymbol,
|
|
2499
|
-
isSelected && { color: accentColor, fontWeight: "600" },
|
|
2500
|
-
isDisabled && styles4.optionTextDisabled
|
|
2501
|
-
], children: pair }),
|
|
2502
|
-
/* @__PURE__ */ jsx(Text, { style: [styles4.optionName, isDisabled && styles4.optionTextDisabled], children: pairInfo.name })
|
|
2503
|
-
] }),
|
|
2504
|
-
isSelected ? /* @__PURE__ */ jsx(View, { style: [styles4.checkbox, { backgroundColor: accentColor }], children: /* @__PURE__ */ jsx(Text, { style: styles4.checkboxIcon, children: "\u2713" }) }) : /* @__PURE__ */ jsx(View, { style: [styles4.checkboxEmpty, isDisabled && styles4.checkboxDisabled] })
|
|
2505
|
-
]
|
|
2506
|
-
},
|
|
2507
|
-
pair
|
|
2508
|
-
);
|
|
2509
|
-
}) }),
|
|
2510
|
-
/* @__PURE__ */ jsx(
|
|
2511
|
-
TouchableOpacity,
|
|
2512
|
-
{
|
|
2513
|
-
style: [styles4.doneButton, { backgroundColor: accentColor }],
|
|
2514
|
-
onPress: () => setIsOpen(false),
|
|
2515
|
-
children: /* @__PURE__ */ jsxs(Text, { style: styles4.doneButtonText, children: [
|
|
2516
|
-
"Done (",
|
|
2517
|
-
selectedPairs.length,
|
|
2518
|
-
")"
|
|
2519
|
-
] })
|
|
2520
|
-
}
|
|
2521
|
-
)
|
|
2522
|
-
] }) })
|
|
2523
|
-
}
|
|
2524
|
-
)
|
|
3226
|
+
/* @__PURE__ */ jsx(View, { style: styles4.pairsContainer, children: supportedPairs.map((pair) => {
|
|
3227
|
+
const isSelected = selectedPairs.includes(pair);
|
|
3228
|
+
const icon = PAIR_ICONS[pair] || "\u25CF";
|
|
3229
|
+
const baseSymbol = pair.split("/")[0];
|
|
3230
|
+
return /* @__PURE__ */ jsxs(
|
|
3231
|
+
TouchableOpacity,
|
|
3232
|
+
{
|
|
3233
|
+
style: [
|
|
3234
|
+
styles4.pairChip,
|
|
3235
|
+
isSelected && styles4.pairChipSelected,
|
|
3236
|
+
isSelected && { backgroundColor: accentColor + "15", borderColor: accentColor }
|
|
3237
|
+
],
|
|
3238
|
+
onPress: () => handleToggle(pair),
|
|
3239
|
+
activeOpacity: 0.7,
|
|
3240
|
+
children: [
|
|
3241
|
+
/* @__PURE__ */ jsx(Text, { style: styles4.pairIcon, children: icon }),
|
|
3242
|
+
/* @__PURE__ */ jsx(Text, { style: [
|
|
3243
|
+
styles4.pairText,
|
|
3244
|
+
isSelected && { color: accentColor, fontWeight: "600" }
|
|
3245
|
+
], children: baseSymbol }),
|
|
3246
|
+
isSelected && /* @__PURE__ */ jsx(Text, { style: [styles4.checkmark, { color: accentColor }], children: "\u2713" })
|
|
3247
|
+
]
|
|
3248
|
+
},
|
|
3249
|
+
pair
|
|
3250
|
+
);
|
|
3251
|
+
}) }),
|
|
3252
|
+
/* @__PURE__ */ jsx(View, { style: styles4.selectedInfo, children: /* @__PURE__ */ jsxs(Text, { style: styles4.selectedText, children: [
|
|
3253
|
+
selectedPairs.length,
|
|
3254
|
+
" pair",
|
|
3255
|
+
selectedPairs.length !== 1 ? "s" : "",
|
|
3256
|
+
" selected",
|
|
3257
|
+
minSelections > 0 && ` (min: ${minSelections})`,
|
|
3258
|
+
maxSelections > 0 && ` (max: ${maxSelections})`
|
|
3259
|
+
] }) })
|
|
2525
3260
|
] });
|
|
2526
3261
|
};
|
|
2527
3262
|
var styles4 = StyleSheet.create({
|
|
@@ -2539,248 +3274,1432 @@ var styles4 = StyleSheet.create({
|
|
|
2539
3274
|
color: "#666",
|
|
2540
3275
|
marginBottom: 12
|
|
2541
3276
|
},
|
|
2542
|
-
|
|
2543
|
-
desktopGrid: {
|
|
3277
|
+
pairsContainer: {
|
|
2544
3278
|
flexDirection: "row",
|
|
2545
3279
|
flexWrap: "wrap",
|
|
2546
|
-
gap:
|
|
3280
|
+
gap: 8
|
|
2547
3281
|
},
|
|
2548
|
-
|
|
3282
|
+
pairChip: {
|
|
2549
3283
|
flexDirection: "row",
|
|
2550
3284
|
alignItems: "center",
|
|
2551
|
-
paddingHorizontal:
|
|
2552
|
-
paddingVertical:
|
|
3285
|
+
paddingHorizontal: 12,
|
|
3286
|
+
paddingVertical: 8,
|
|
2553
3287
|
backgroundColor: "#fff",
|
|
2554
|
-
borderRadius:
|
|
2555
|
-
borderWidth:
|
|
2556
|
-
borderColor: "#
|
|
2557
|
-
gap:
|
|
2558
|
-
cursor: "pointer",
|
|
2559
|
-
minWidth: 140
|
|
3288
|
+
borderRadius: 8,
|
|
3289
|
+
borderWidth: 1,
|
|
3290
|
+
borderColor: "#e5e5e5",
|
|
3291
|
+
gap: 6
|
|
2560
3292
|
},
|
|
2561
|
-
|
|
3293
|
+
pairChipSelected: {
|
|
2562
3294
|
borderWidth: 2
|
|
2563
3295
|
},
|
|
2564
|
-
|
|
2565
|
-
|
|
3296
|
+
pairIcon: {
|
|
3297
|
+
fontSize: 14
|
|
2566
3298
|
},
|
|
2567
|
-
|
|
2568
|
-
width: 36,
|
|
2569
|
-
height: 36,
|
|
2570
|
-
borderRadius: 18,
|
|
2571
|
-
alignItems: "center",
|
|
2572
|
-
justifyContent: "center"
|
|
2573
|
-
},
|
|
2574
|
-
desktopIcon: {
|
|
2575
|
-
fontSize: 16,
|
|
2576
|
-
fontWeight: "700"
|
|
2577
|
-
},
|
|
2578
|
-
desktopChipText: {
|
|
3299
|
+
pairText: {
|
|
2579
3300
|
fontSize: 14,
|
|
2580
|
-
|
|
2581
|
-
color: "#333"
|
|
2582
|
-
},
|
|
2583
|
-
desktopChipSubtext: {
|
|
2584
|
-
fontSize: 11,
|
|
2585
|
-
color: "#888",
|
|
2586
|
-
marginTop: 1
|
|
2587
|
-
},
|
|
2588
|
-
desktopTextDisabled: {
|
|
2589
|
-
color: "#bbb"
|
|
2590
|
-
},
|
|
2591
|
-
desktopCheckbox: {
|
|
2592
|
-
width: 20,
|
|
2593
|
-
height: 20,
|
|
2594
|
-
borderRadius: 10,
|
|
2595
|
-
alignItems: "center",
|
|
2596
|
-
justifyContent: "center",
|
|
2597
|
-
marginLeft: "auto"
|
|
2598
|
-
},
|
|
2599
|
-
desktopCheckIcon: {
|
|
2600
|
-
fontSize: 12,
|
|
2601
|
-
color: "#fff",
|
|
2602
|
-
fontWeight: "700"
|
|
2603
|
-
},
|
|
2604
|
-
// Mobile dropdown styles
|
|
2605
|
-
dropdownTrigger: {
|
|
2606
|
-
flexDirection: "row",
|
|
2607
|
-
alignItems: "center",
|
|
2608
|
-
justifyContent: "space-between",
|
|
2609
|
-
paddingHorizontal: 14,
|
|
2610
|
-
paddingVertical: 12,
|
|
2611
|
-
backgroundColor: "#fff",
|
|
2612
|
-
borderRadius: 12,
|
|
2613
|
-
borderWidth: 2,
|
|
2614
|
-
borderColor: "#e5e5e5",
|
|
2615
|
-
minHeight: 52
|
|
2616
|
-
},
|
|
2617
|
-
selectedPreview: {
|
|
2618
|
-
flex: 1,
|
|
2619
|
-
flexDirection: "row",
|
|
2620
|
-
alignItems: "center",
|
|
2621
|
-
gap: 6
|
|
2622
|
-
},
|
|
2623
|
-
previewChip: {
|
|
2624
|
-
width: 32,
|
|
2625
|
-
height: 32,
|
|
2626
|
-
borderRadius: 16,
|
|
2627
|
-
alignItems: "center",
|
|
2628
|
-
justifyContent: "center"
|
|
3301
|
+
color: "#666"
|
|
2629
3302
|
},
|
|
2630
|
-
|
|
3303
|
+
checkmark: {
|
|
2631
3304
|
fontSize: 14,
|
|
2632
3305
|
fontWeight: "700"
|
|
2633
3306
|
},
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
paddingVertical: 4
|
|
2637
|
-
backgroundColor: "#f0f0f0",
|
|
2638
|
-
borderRadius: 8
|
|
3307
|
+
selectedInfo: {
|
|
3308
|
+
marginTop: 8,
|
|
3309
|
+
paddingVertical: 4
|
|
2639
3310
|
},
|
|
2640
|
-
|
|
3311
|
+
selectedText: {
|
|
2641
3312
|
fontSize: 12,
|
|
2642
|
-
color: "#666",
|
|
2643
|
-
fontWeight: "600"
|
|
2644
|
-
},
|
|
2645
|
-
placeholderText: {
|
|
2646
|
-
fontSize: 14,
|
|
2647
|
-
color: "#999"
|
|
2648
|
-
},
|
|
2649
|
-
dropdownArrow: {
|
|
2650
|
-
fontSize: 12,
|
|
2651
|
-
color: "#888",
|
|
2652
|
-
marginLeft: 8
|
|
2653
|
-
},
|
|
2654
|
-
infoRow: {
|
|
2655
|
-
flexDirection: "row",
|
|
2656
|
-
justifyContent: "space-between",
|
|
2657
|
-
alignItems: "center",
|
|
2658
|
-
marginTop: 6
|
|
2659
|
-
},
|
|
2660
|
-
selectedCount: {
|
|
2661
|
-
fontSize: 12,
|
|
2662
|
-
fontWeight: "500"
|
|
2663
|
-
},
|
|
2664
|
-
limitText: {
|
|
2665
|
-
fontSize: 11,
|
|
2666
3313
|
color: "#888"
|
|
2667
|
-
}
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
3314
|
+
}
|
|
3315
|
+
});
|
|
3316
|
+
var OneForexPoolCard = ({
|
|
3317
|
+
pool,
|
|
3318
|
+
poolName,
|
|
3319
|
+
showMetrics = true,
|
|
3320
|
+
accentColor,
|
|
3321
|
+
style,
|
|
3322
|
+
dark = true
|
|
3323
|
+
}) => {
|
|
3324
|
+
const color = accentColor || pool.color;
|
|
3325
|
+
const bg = dark ? "#111111" : "#ffffff";
|
|
3326
|
+
const border = dark ? "#1a1a1a" : "#e5e5e5";
|
|
3327
|
+
const textPrimary = dark ? "#ffffff" : "#1a1a1a";
|
|
3328
|
+
const textSecondary = dark ? "#9ca3af" : "#666666";
|
|
3329
|
+
const textMuted = dark ? "#666666" : "#999999";
|
|
3330
|
+
const barBg = dark ? "#1a1a1a" : "#e5e5e5";
|
|
3331
|
+
return /* @__PURE__ */ jsxs(View, { style: [styles5.container, { backgroundColor: bg, borderColor: border }, style], children: [
|
|
3332
|
+
/* @__PURE__ */ jsxs(View, { style: styles5.header, children: [
|
|
3333
|
+
/* @__PURE__ */ jsx(View, { style: [styles5.dot, { backgroundColor: color }] }),
|
|
3334
|
+
/* @__PURE__ */ jsx(Text, { style: [styles5.name, { color: textPrimary }], children: poolName || pool.nameKey }),
|
|
3335
|
+
/* @__PURE__ */ jsxs(Text, { style: [styles5.alloc, { color: textSecondary }], children: [
|
|
3336
|
+
(pool.allocation * 100).toFixed(0),
|
|
3337
|
+
"%"
|
|
3338
|
+
] })
|
|
3339
|
+
] }),
|
|
3340
|
+
/* @__PURE__ */ jsx(View, { style: [styles5.barOuter, { backgroundColor: barBg }], children: /* @__PURE__ */ jsx(View, { style: [styles5.barFill, { width: `${pool.utilization * 100}%`, backgroundColor: color }] }) }),
|
|
3341
|
+
/* @__PURE__ */ jsxs(View, { style: styles5.statsRow, children: [
|
|
3342
|
+
/* @__PURE__ */ jsxs(Text, { style: [styles5.statValue, { color: textSecondary }], children: [
|
|
3343
|
+
"$",
|
|
3344
|
+
(pool.totalSize / 1e6).toFixed(1),
|
|
3345
|
+
"M"
|
|
3346
|
+
] }),
|
|
3347
|
+
/* @__PURE__ */ jsxs(Text, { style: [styles5.statLabel, { color: textMuted }], children: [
|
|
3348
|
+
(pool.utilization * 100).toFixed(1),
|
|
3349
|
+
"% util"
|
|
3350
|
+
] })
|
|
3351
|
+
] }),
|
|
3352
|
+
showMetrics && /* @__PURE__ */ jsxs(View, { style: [styles5.metricsRow, { borderTopColor: border }], children: [
|
|
3353
|
+
/* @__PURE__ */ jsxs(View, { style: styles5.metricItem, children: [
|
|
3354
|
+
/* @__PURE__ */ jsx(Text, { style: [styles5.metricLabel, { color: textMuted }], children: "APY 7d" }),
|
|
3355
|
+
/* @__PURE__ */ jsxs(Text, { style: [styles5.metricValue, { color: "#10B981" }], children: [
|
|
3356
|
+
pool.apy7d.toFixed(1),
|
|
3357
|
+
"%"
|
|
3358
|
+
] })
|
|
3359
|
+
] }),
|
|
3360
|
+
/* @__PURE__ */ jsxs(View, { style: styles5.metricItem, children: [
|
|
3361
|
+
/* @__PURE__ */ jsx(Text, { style: [styles5.metricLabel, { color: textMuted }], children: "24h Flow" }),
|
|
3362
|
+
/* @__PURE__ */ jsxs(Text, { style: [styles5.metricValue, { color: pool.netFlow24h >= 0 ? "#10B981" : "#EF4444" }], children: [
|
|
3363
|
+
pool.netFlow24h >= 0 ? "+" : "",
|
|
3364
|
+
"$",
|
|
3365
|
+
(pool.netFlow24h / 1e3).toFixed(0),
|
|
3366
|
+
"K"
|
|
3367
|
+
] })
|
|
3368
|
+
] }),
|
|
3369
|
+
/* @__PURE__ */ jsxs(View, { style: styles5.metricItem, children: [
|
|
3370
|
+
/* @__PURE__ */ jsx(Text, { style: [styles5.metricLabel, { color: textMuted }], children: "Txs" }),
|
|
3371
|
+
/* @__PURE__ */ jsx(Text, { style: [styles5.metricValue, { color: textPrimary }], children: pool.txCount24h })
|
|
3372
|
+
] })
|
|
3373
|
+
] })
|
|
3374
|
+
] });
|
|
3375
|
+
};
|
|
3376
|
+
var styles5 = StyleSheet.create({
|
|
3377
|
+
container: { borderRadius: 8, borderWidth: 1, padding: 14 },
|
|
3378
|
+
header: { flexDirection: "row", alignItems: "center", marginBottom: 8, gap: 8 },
|
|
3379
|
+
dot: { width: 8, height: 8, borderRadius: 4 },
|
|
3380
|
+
name: { fontSize: 13, fontWeight: "600", flex: 1 },
|
|
3381
|
+
alloc: { fontSize: 12 },
|
|
3382
|
+
barOuter: { height: 6, borderRadius: 3, overflow: "hidden", marginBottom: 6 },
|
|
3383
|
+
barFill: { height: "100%", borderRadius: 3 },
|
|
3384
|
+
statsRow: { flexDirection: "row", justifyContent: "space-between" },
|
|
3385
|
+
statValue: { fontSize: 12, fontWeight: "600" },
|
|
3386
|
+
statLabel: { fontSize: 11 },
|
|
3387
|
+
metricsRow: { flexDirection: "row", justifyContent: "space-between", paddingTop: 8, marginTop: 8, borderTopWidth: 1 },
|
|
3388
|
+
metricItem: { alignItems: "center", flex: 1 },
|
|
3389
|
+
metricLabel: { fontSize: 9, textTransform: "uppercase", letterSpacing: 0.5, marginBottom: 2 },
|
|
3390
|
+
metricValue: { fontSize: 12, fontWeight: "600" }
|
|
3391
|
+
});
|
|
3392
|
+
|
|
3393
|
+
// src/components/ai/OneForexCapitalSplit.tsx
|
|
3394
|
+
init_forex();
|
|
3395
|
+
var OneForexCapitalSplit = ({
|
|
3396
|
+
amount,
|
|
3397
|
+
labels = {},
|
|
3398
|
+
showPoolBreakdown = true,
|
|
3399
|
+
style,
|
|
3400
|
+
dark = false
|
|
3401
|
+
}) => {
|
|
3402
|
+
const allocs = computePoolAllocations(amount);
|
|
3403
|
+
const bg = dark ? "#111111" : "#ffffff";
|
|
3404
|
+
const border = dark ? "#1a1a1a" : "#e5e5e5";
|
|
3405
|
+
const textPrimary = dark ? "#ffffff" : "#1a1a1a";
|
|
3406
|
+
const textSecondary = dark ? "#9ca3af" : "#666666";
|
|
3407
|
+
const itemBg = dark ? "#0a0a0a" : "#f5f5f5";
|
|
3408
|
+
return /* @__PURE__ */ jsxs(View, { style: [styles6.container, { backgroundColor: bg, borderColor: border }, style], children: [
|
|
3409
|
+
labels.title && /* @__PURE__ */ jsx(Text, { style: [styles6.title, { color: textPrimary }], children: labels.title }),
|
|
3410
|
+
/* @__PURE__ */ jsxs(View, { style: styles6.splitRow, children: [
|
|
3411
|
+
/* @__PURE__ */ jsxs(View, { style: [styles6.splitItem, { backgroundColor: itemBg }], children: [
|
|
3412
|
+
/* @__PURE__ */ jsx(View, { style: [styles6.dot, { backgroundColor: "#0EA5E9" }] }),
|
|
3413
|
+
/* @__PURE__ */ jsx(Text, { style: [styles6.splitLabel, { color: textSecondary }], children: labels.tradingCapital || "Active Trading (RFQ)" }),
|
|
3414
|
+
/* @__PURE__ */ jsx(Text, { style: [styles6.splitPct, { color: textSecondary }], children: "50%" }),
|
|
3415
|
+
/* @__PURE__ */ jsxs(Text, { style: [styles6.splitAmt, { color: textPrimary }], children: [
|
|
3416
|
+
"$",
|
|
3417
|
+
allocs.tradingCapital.toLocaleString()
|
|
3418
|
+
] })
|
|
3419
|
+
] }),
|
|
3420
|
+
/* @__PURE__ */ jsxs(View, { style: [styles6.splitItem, { backgroundColor: itemBg }], children: [
|
|
3421
|
+
/* @__PURE__ */ jsx(View, { style: [styles6.dot, { backgroundColor: "#8B5CF6" }] }),
|
|
3422
|
+
/* @__PURE__ */ jsx(Text, { style: [styles6.splitLabel, { color: textSecondary }], children: labels.poolReserves || "Pool Reserves" }),
|
|
3423
|
+
/* @__PURE__ */ jsx(Text, { style: [styles6.splitPct, { color: textSecondary }], children: "50%" }),
|
|
3424
|
+
/* @__PURE__ */ jsxs(Text, { style: [styles6.splitAmt, { color: textPrimary }], children: [
|
|
3425
|
+
"$",
|
|
3426
|
+
allocs.totalPoolReserves.toLocaleString()
|
|
3427
|
+
] })
|
|
3428
|
+
] })
|
|
3429
|
+
] }),
|
|
3430
|
+
showPoolBreakdown && amount > 0 && /* @__PURE__ */ jsx(View, { style: [styles6.breakdown, { borderTopColor: border }], children: FOREX_POOL_DEFAULTS.map((pool) => {
|
|
3431
|
+
const poolAmt = allocs[pool.id];
|
|
3432
|
+
return /* @__PURE__ */ jsxs(View, { style: styles6.poolRow, children: [
|
|
3433
|
+
/* @__PURE__ */ jsx(View, { style: [styles6.poolDot, { backgroundColor: pool.color }] }),
|
|
3434
|
+
/* @__PURE__ */ jsx(Text, { style: [styles6.poolName, { color: textSecondary }], children: labels?.[pool.id] || pool.nameKey }),
|
|
3435
|
+
/* @__PURE__ */ jsx(View, { style: [styles6.poolBar, { backgroundColor: dark ? "#1a1a1a" : "#e5e5e5" }], children: /* @__PURE__ */ jsx(View, { style: [styles6.poolBarFill, { width: `${pool.allocation * 100}%`, backgroundColor: pool.color }] }) }),
|
|
3436
|
+
/* @__PURE__ */ jsxs(Text, { style: [styles6.poolAmt, { color: textPrimary }], children: [
|
|
3437
|
+
"$",
|
|
3438
|
+
poolAmt.toLocaleString()
|
|
3439
|
+
] })
|
|
3440
|
+
] }, pool.id);
|
|
3441
|
+
}) })
|
|
3442
|
+
] });
|
|
3443
|
+
};
|
|
3444
|
+
var styles6 = StyleSheet.create({
|
|
3445
|
+
container: { borderRadius: 8, borderWidth: 1, padding: 14 },
|
|
3446
|
+
title: { fontSize: 14, fontWeight: "600", marginBottom: 12 },
|
|
3447
|
+
splitRow: { gap: 8 },
|
|
3448
|
+
splitItem: { flexDirection: "row", alignItems: "center", paddingVertical: 10, paddingHorizontal: 12, borderRadius: 8 },
|
|
3449
|
+
dot: { width: 10, height: 10, borderRadius: 5, marginRight: 8 },
|
|
3450
|
+
splitLabel: { flex: 1, fontSize: 13, fontWeight: "500" },
|
|
3451
|
+
splitPct: { fontSize: 12, fontWeight: "600", marginRight: 12 },
|
|
3452
|
+
splitAmt: { fontSize: 14, fontWeight: "700" },
|
|
3453
|
+
breakdown: { marginTop: 12, paddingTop: 12, borderTopWidth: 1 },
|
|
3454
|
+
poolRow: { flexDirection: "row", alignItems: "center", marginBottom: 8 },
|
|
3455
|
+
poolDot: { width: 8, height: 8, borderRadius: 4, marginRight: 8 },
|
|
3456
|
+
poolName: { width: 80, fontSize: 12 },
|
|
3457
|
+
poolBar: { flex: 1, height: 6, borderRadius: 3, overflow: "hidden", marginHorizontal: 8 },
|
|
3458
|
+
poolBarFill: { height: "100%", borderRadius: 3 },
|
|
3459
|
+
poolAmt: { width: 70, fontSize: 12, fontWeight: "600", textAlign: "right" }
|
|
3460
|
+
});
|
|
3461
|
+
var MONO = Platform.OS === "ios" ? "Courier New" : "monospace";
|
|
3462
|
+
var OneForexConsoleView = ({
|
|
3463
|
+
logs,
|
|
3464
|
+
maxItems = 100,
|
|
3465
|
+
autoScroll = true,
|
|
3466
|
+
style,
|
|
3467
|
+
height = 400
|
|
3468
|
+
}) => {
|
|
3469
|
+
const scrollRef = useRef(null);
|
|
3470
|
+
const visibleLogs = logs.slice(-maxItems);
|
|
3471
|
+
useEffect(() => {
|
|
3472
|
+
if (autoScroll && scrollRef.current) {
|
|
3473
|
+
setTimeout(() => scrollRef.current?.scrollToEnd({ animated: true }), 50);
|
|
3474
|
+
}
|
|
3475
|
+
}, [logs.length, autoScroll]);
|
|
3476
|
+
const formatTime = (ts) => {
|
|
3477
|
+
const d = new Date(ts);
|
|
3478
|
+
return `${d.getHours().toString().padStart(2, "0")}:${d.getMinutes().toString().padStart(2, "0")}:${d.getSeconds().toString().padStart(2, "0")}`;
|
|
3479
|
+
};
|
|
3480
|
+
return /* @__PURE__ */ jsx(View, { style: [styles7.container, { height }, style], children: /* @__PURE__ */ jsxs(ScrollView, { ref: scrollRef, style: styles7.scroll, contentContainerStyle: styles7.scrollContent, children: [
|
|
3481
|
+
visibleLogs.map((log) => /* @__PURE__ */ jsxs(View, { style: styles7.logRow, children: [
|
|
3482
|
+
/* @__PURE__ */ jsx(Text, { style: styles7.timestamp, children: formatTime(log.timestamp) }),
|
|
3483
|
+
/* @__PURE__ */ jsx(Text, { style: [styles7.type, { color: FOREX_LOG_COLORS[log.type] || "#9CA3AF" }], children: log.type.padEnd(8) }),
|
|
3484
|
+
/* @__PURE__ */ jsx(Text, { style: [
|
|
3485
|
+
styles7.message,
|
|
3486
|
+
log.importance === "high" && styles7.messageHigh
|
|
3487
|
+
], numberOfLines: 2, children: log.message })
|
|
3488
|
+
] }, log.id)),
|
|
3489
|
+
visibleLogs.length === 0 && /* @__PURE__ */ jsx(Text, { style: styles7.emptyText, children: "Waiting for trading activity..." })
|
|
3490
|
+
] }) });
|
|
3491
|
+
};
|
|
3492
|
+
var T = {
|
|
3493
|
+
base: "#0A0A0C",
|
|
3494
|
+
border: "#2A2A35",
|
|
3495
|
+
muted: "#555560",
|
|
3496
|
+
secondary: "#9CA3AF"
|
|
3497
|
+
};
|
|
3498
|
+
var styles7 = StyleSheet.create({
|
|
3499
|
+
container: { backgroundColor: T.base, borderRadius: 8, borderWidth: 1, borderColor: T.border, overflow: "hidden" },
|
|
3500
|
+
scroll: { flex: 1 },
|
|
3501
|
+
scrollContent: { padding: 8 },
|
|
3502
|
+
logRow: { flexDirection: "row", paddingVertical: 3 },
|
|
3503
|
+
timestamp: { fontFamily: MONO, fontSize: 10, color: T.muted, width: 60, marginRight: 6 },
|
|
3504
|
+
type: { fontFamily: MONO, fontSize: 10, fontWeight: "700", width: 65, marginRight: 6 },
|
|
3505
|
+
message: { fontFamily: MONO, fontSize: 10, color: T.secondary, flex: 1 },
|
|
3506
|
+
messageHigh: { color: "#ffffff", fontWeight: "600" },
|
|
3507
|
+
emptyText: { fontFamily: MONO, fontSize: 11, color: T.muted, textAlign: "center", paddingVertical: 40 }
|
|
3508
|
+
});
|
|
3509
|
+
|
|
3510
|
+
// src/components/ai/OneForexPairSelector.tsx
|
|
3511
|
+
init_forex();
|
|
3512
|
+
var OneForexPairSelector = ({
|
|
3513
|
+
selectedPairs,
|
|
3514
|
+
onTogglePair,
|
|
3515
|
+
accentColor = "#0EA5E9",
|
|
3516
|
+
title,
|
|
3517
|
+
subtitle,
|
|
3518
|
+
pairs = FOREX_CURRENCY_PAIRS,
|
|
3519
|
+
style
|
|
3520
|
+
}) => {
|
|
3521
|
+
const handleToggle = (pairId) => {
|
|
3522
|
+
if (selectedPairs.includes(pairId) && selectedPairs.length <= 1) return;
|
|
3523
|
+
onTogglePair(pairId);
|
|
3524
|
+
};
|
|
3525
|
+
return /* @__PURE__ */ jsxs(View, { style: [styles8.container, style], children: [
|
|
3526
|
+
title && /* @__PURE__ */ jsx(Text, { style: styles8.title, children: title }),
|
|
3527
|
+
subtitle && /* @__PURE__ */ jsx(Text, { style: styles8.subtitle, children: subtitle }),
|
|
3528
|
+
/* @__PURE__ */ jsx(View, { style: styles8.pairGrid, children: pairs.map((pair) => {
|
|
3529
|
+
const isSelected = selectedPairs.includes(pair.id);
|
|
3530
|
+
return /* @__PURE__ */ jsxs(
|
|
3531
|
+
TouchableOpacity,
|
|
3532
|
+
{
|
|
3533
|
+
style: [
|
|
3534
|
+
styles8.pairBtn,
|
|
3535
|
+
isSelected && styles8.pairBtnActive,
|
|
3536
|
+
isSelected && { borderColor: accentColor, backgroundColor: accentColor + "08" }
|
|
3537
|
+
],
|
|
3538
|
+
onPress: () => handleToggle(pair.id),
|
|
3539
|
+
activeOpacity: 0.7,
|
|
3540
|
+
children: [
|
|
3541
|
+
/* @__PURE__ */ jsx(Text, { style: styles8.pairFlag, children: pair.flag }),
|
|
3542
|
+
/* @__PURE__ */ jsxs(View, { style: styles8.pairInfo, children: [
|
|
3543
|
+
/* @__PURE__ */ jsx(Text, { style: [styles8.pairSymbol, isSelected && { color: accentColor, fontWeight: "600" }], children: pair.symbol }),
|
|
3544
|
+
/* @__PURE__ */ jsx(Text, { style: styles8.pairName, children: pair.name })
|
|
3545
|
+
] }),
|
|
3546
|
+
isSelected && /* @__PURE__ */ jsx(Text, { style: [styles8.check, { color: accentColor }], children: "\u2713" })
|
|
3547
|
+
]
|
|
3548
|
+
},
|
|
3549
|
+
pair.id
|
|
3550
|
+
);
|
|
3551
|
+
}) }),
|
|
3552
|
+
/* @__PURE__ */ jsxs(Text, { style: styles8.selectedInfo, children: [
|
|
3553
|
+
selectedPairs.length,
|
|
3554
|
+
" pair",
|
|
3555
|
+
selectedPairs.length !== 1 ? "s" : "",
|
|
3556
|
+
" selected (min: 1)"
|
|
3557
|
+
] })
|
|
3558
|
+
] });
|
|
3559
|
+
};
|
|
3560
|
+
var styles8 = StyleSheet.create({
|
|
3561
|
+
container: { marginBottom: 16 },
|
|
3562
|
+
title: { fontSize: 16, fontWeight: "600", color: "#1a1a1a", marginBottom: 4 },
|
|
3563
|
+
subtitle: { fontSize: 12, color: "#666", marginBottom: 12 },
|
|
3564
|
+
pairGrid: { gap: 8 },
|
|
3565
|
+
pairBtn: {
|
|
2706
3566
|
flexDirection: "row",
|
|
2707
3567
|
alignItems: "center",
|
|
2708
3568
|
paddingHorizontal: 12,
|
|
2709
3569
|
paddingVertical: 12,
|
|
2710
|
-
borderRadius:
|
|
2711
|
-
borderWidth: 1,
|
|
2712
|
-
borderColor: "
|
|
2713
|
-
|
|
2714
|
-
gap:
|
|
2715
|
-
},
|
|
2716
|
-
optionItemSelected: {
|
|
2717
|
-
borderWidth: 1
|
|
2718
|
-
},
|
|
2719
|
-
optionItemDisabled: {
|
|
2720
|
-
opacity: 0.5
|
|
2721
|
-
},
|
|
2722
|
-
optionIconBg: {
|
|
2723
|
-
width: 40,
|
|
2724
|
-
height: 40,
|
|
2725
|
-
borderRadius: 20,
|
|
2726
|
-
alignItems: "center",
|
|
2727
|
-
justifyContent: "center"
|
|
2728
|
-
},
|
|
2729
|
-
optionIcon: {
|
|
2730
|
-
fontSize: 18,
|
|
2731
|
-
fontWeight: "700"
|
|
2732
|
-
},
|
|
2733
|
-
optionTextContainer: {
|
|
2734
|
-
flex: 1
|
|
2735
|
-
},
|
|
2736
|
-
optionSymbol: {
|
|
2737
|
-
fontSize: 15,
|
|
2738
|
-
fontWeight: "500",
|
|
2739
|
-
color: "#333"
|
|
2740
|
-
},
|
|
2741
|
-
optionName: {
|
|
2742
|
-
fontSize: 12,
|
|
2743
|
-
color: "#888",
|
|
2744
|
-
marginTop: 1
|
|
2745
|
-
},
|
|
2746
|
-
optionTextDisabled: {
|
|
2747
|
-
color: "#bbb"
|
|
2748
|
-
},
|
|
2749
|
-
checkbox: {
|
|
2750
|
-
width: 24,
|
|
2751
|
-
height: 24,
|
|
2752
|
-
borderRadius: 12,
|
|
2753
|
-
alignItems: "center",
|
|
2754
|
-
justifyContent: "center"
|
|
2755
|
-
},
|
|
2756
|
-
checkboxIcon: {
|
|
2757
|
-
fontSize: 14,
|
|
2758
|
-
color: "#fff",
|
|
2759
|
-
fontWeight: "700"
|
|
2760
|
-
},
|
|
2761
|
-
checkboxEmpty: {
|
|
2762
|
-
width: 24,
|
|
2763
|
-
height: 24,
|
|
2764
|
-
borderRadius: 12,
|
|
2765
|
-
borderWidth: 2,
|
|
2766
|
-
borderColor: "#ddd"
|
|
3570
|
+
borderRadius: 8,
|
|
3571
|
+
borderWidth: 1.5,
|
|
3572
|
+
borderColor: "#e5e5e5",
|
|
3573
|
+
backgroundColor: "#fff",
|
|
3574
|
+
gap: 10
|
|
2767
3575
|
},
|
|
2768
|
-
|
|
2769
|
-
|
|
3576
|
+
pairBtnActive: { borderWidth: 2 },
|
|
3577
|
+
pairFlag: { fontSize: 20 },
|
|
3578
|
+
pairInfo: { flex: 1 },
|
|
3579
|
+
pairSymbol: { fontSize: 14, color: "#666" },
|
|
3580
|
+
pairName: { fontSize: 11, color: "#999" },
|
|
3581
|
+
check: { fontSize: 16, fontWeight: "700" },
|
|
3582
|
+
selectedInfo: { fontSize: 12, color: "#888", marginTop: 8 }
|
|
3583
|
+
});
|
|
3584
|
+
var MONO2 = Platform.OS === "ios" ? "Courier New" : "monospace";
|
|
3585
|
+
var OneForexTradeHistory = ({
|
|
3586
|
+
trades,
|
|
3587
|
+
maxItems = 50,
|
|
3588
|
+
showSettlementDetails = true,
|
|
3589
|
+
showTxHash = true,
|
|
3590
|
+
emptyText = "No trade history yet",
|
|
3591
|
+
style
|
|
3592
|
+
}) => {
|
|
3593
|
+
const visibleTrades = trades.slice(-maxItems).reverse();
|
|
3594
|
+
if (visibleTrades.length === 0) {
|
|
3595
|
+
return /* @__PURE__ */ jsx(View, { style: [styles9.empty, style], children: /* @__PURE__ */ jsx(Text, { style: styles9.emptyText, children: emptyText }) });
|
|
3596
|
+
}
|
|
3597
|
+
return /* @__PURE__ */ jsx(ScrollView, { style: [styles9.container, style], contentContainerStyle: styles9.scrollContent, children: visibleTrades.map((trade) => /* @__PURE__ */ jsxs(View, { style: styles9.card, children: [
|
|
3598
|
+
/* @__PURE__ */ jsxs(View, { style: styles9.header, children: [
|
|
3599
|
+
/* @__PURE__ */ jsx(Text, { style: styles9.pair, children: trade.pairSymbol }),
|
|
3600
|
+
/* @__PURE__ */ jsx(View, { style: [
|
|
3601
|
+
styles9.sideBadge,
|
|
3602
|
+
{ backgroundColor: trade.side === "BUY" ? "#10B98118" : "#EF444418", borderColor: trade.side === "BUY" ? "#10B98140" : "#EF444440" }
|
|
3603
|
+
], children: /* @__PURE__ */ jsx(Text, { style: [styles9.sideText, { color: trade.side === "BUY" ? "#10B981" : "#EF4444" }], children: trade.side }) }),
|
|
3604
|
+
/* @__PURE__ */ jsxs(Text, { style: [styles9.pnl, { color: trade.pnl >= 0 ? "#10B981" : "#EF4444" }], children: [
|
|
3605
|
+
trade.pnl >= 0 ? "+" : "",
|
|
3606
|
+
"$",
|
|
3607
|
+
trade.pnl.toFixed(2)
|
|
3608
|
+
] })
|
|
3609
|
+
] }),
|
|
3610
|
+
/* @__PURE__ */ jsxs(View, { style: styles9.details, children: [
|
|
3611
|
+
/* @__PURE__ */ jsxs(Text, { style: styles9.detail, children: [
|
|
3612
|
+
trade.lots.toFixed(2),
|
|
3613
|
+
" lots | ",
|
|
3614
|
+
trade.pips >= 0 ? "+" : "",
|
|
3615
|
+
trade.pips.toFixed(1),
|
|
3616
|
+
" pips"
|
|
3617
|
+
] }),
|
|
3618
|
+
/* @__PURE__ */ jsx(Text, { style: styles9.time, children: new Date(trade.timestamp).toLocaleString() })
|
|
3619
|
+
] }),
|
|
3620
|
+
showSettlementDetails && trade.clearingFee !== void 0 && /* @__PURE__ */ jsx(View, { style: styles9.settlement, children: /* @__PURE__ */ jsxs(Text, { style: styles9.settlementText, children: [
|
|
3621
|
+
"CLR: $",
|
|
3622
|
+
trade.clearingFee.toFixed(2),
|
|
3623
|
+
" | HDG: $",
|
|
3624
|
+
(trade.hedgingCost || 0).toFixed(2),
|
|
3625
|
+
" | INS: $",
|
|
3626
|
+
(trade.insuranceReserve || 0).toFixed(2)
|
|
3627
|
+
] }) }),
|
|
3628
|
+
showTxHash && trade.txHash && /* @__PURE__ */ jsxs(Text, { style: styles9.txHash, children: [
|
|
3629
|
+
trade.txHash.slice(0, 10),
|
|
3630
|
+
"...",
|
|
3631
|
+
trade.txHash.slice(-6)
|
|
3632
|
+
] })
|
|
3633
|
+
] }, trade.id)) });
|
|
3634
|
+
};
|
|
3635
|
+
var styles9 = StyleSheet.create({
|
|
3636
|
+
container: { flex: 1 },
|
|
3637
|
+
scrollContent: { paddingBottom: 16 },
|
|
3638
|
+
empty: { alignItems: "center", justifyContent: "center", padding: 40 },
|
|
3639
|
+
emptyText: { fontSize: 14, color: "#666" },
|
|
3640
|
+
card: { backgroundColor: "#111111", borderRadius: 6, borderWidth: 1, borderColor: "#1a1a1a", padding: 12, marginBottom: 8 },
|
|
3641
|
+
header: { flexDirection: "row", alignItems: "center", gap: 8 },
|
|
3642
|
+
pair: { fontSize: 13, fontWeight: "600", color: "#ffffff" },
|
|
3643
|
+
sideBadge: { paddingHorizontal: 6, paddingVertical: 2, borderRadius: 3, borderWidth: 1 },
|
|
3644
|
+
sideText: { fontSize: 9, fontWeight: "700", letterSpacing: 0.5 },
|
|
3645
|
+
pnl: { fontFamily: MONO2, marginLeft: "auto", fontSize: 13, fontWeight: "700" },
|
|
3646
|
+
details: { flexDirection: "row", justifyContent: "space-between", marginTop: 6 },
|
|
3647
|
+
detail: { fontFamily: MONO2, fontSize: 11, color: "#9ca3af" },
|
|
3648
|
+
time: { fontSize: 11, color: "#666" },
|
|
3649
|
+
settlement: { marginTop: 6, paddingTop: 6, borderTopWidth: 1, borderTopColor: "#1a1a1a" },
|
|
3650
|
+
settlementText: { fontFamily: MONO2, fontSize: 10, color: "#666" },
|
|
3651
|
+
txHash: { fontFamily: MONO2, fontSize: 9, color: "#444", marginTop: 2 }
|
|
3652
|
+
});
|
|
3653
|
+
|
|
3654
|
+
// src/hooks/useForexTrading.ts
|
|
3655
|
+
init_forex();
|
|
3656
|
+
var _forexAccessToken = null;
|
|
3657
|
+
var _forexEngineUrl = "https://api.one23.io";
|
|
3658
|
+
function setForexAccessToken(token) {
|
|
3659
|
+
_forexAccessToken = token;
|
|
3660
|
+
}
|
|
3661
|
+
function clearForexAccessToken() {
|
|
3662
|
+
_forexAccessToken = null;
|
|
3663
|
+
}
|
|
3664
|
+
function setForexEngineUrl(url) {
|
|
3665
|
+
_forexEngineUrl = url;
|
|
3666
|
+
}
|
|
3667
|
+
async function forexApi(path, options) {
|
|
3668
|
+
try {
|
|
3669
|
+
const headers = {
|
|
3670
|
+
"Content-Type": "application/json"
|
|
3671
|
+
};
|
|
3672
|
+
if (_forexAccessToken) {
|
|
3673
|
+
headers["Authorization"] = `Bearer ${_forexAccessToken}`;
|
|
3674
|
+
}
|
|
3675
|
+
const res = await fetch(`${_forexEngineUrl}${path}`, { ...options, headers });
|
|
3676
|
+
if (!res.ok) return null;
|
|
3677
|
+
const json = await res.json();
|
|
3678
|
+
return json?.data ?? json;
|
|
3679
|
+
} catch {
|
|
3680
|
+
return null;
|
|
3681
|
+
}
|
|
3682
|
+
}
|
|
3683
|
+
function useForexPools(options) {
|
|
3684
|
+
const [pools, setPools] = useState(FOREX_POOL_DEFAULTS);
|
|
3685
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
3686
|
+
const [error, setError] = useState(null);
|
|
3687
|
+
const fetchPools = useCallback(async () => {
|
|
3688
|
+
setIsLoading(true);
|
|
3689
|
+
try {
|
|
3690
|
+
const data = await forexApi("/api/forex/pools");
|
|
3691
|
+
if (data?.pools) {
|
|
3692
|
+
setPools(data.pools.map((p) => ({
|
|
3693
|
+
id: p.type ?? p.id,
|
|
3694
|
+
nameKey: `forex.pool_${p.type ?? p.id}`,
|
|
3695
|
+
descriptionKey: `forex.pool_${p.type ?? p.id}_desc`,
|
|
3696
|
+
allocation: p.allocation ?? (p.type === "clearing" ? 0.5 : p.type === "hedging" ? 0.3 : 0.2),
|
|
3697
|
+
totalSize: p.totalSize ?? p.total_size ?? 0,
|
|
3698
|
+
utilization: p.utilization ?? 0,
|
|
3699
|
+
color: p.type === "clearing" ? "#3B82F6" : p.type === "hedging" ? "#F59E0B" : "#10B981",
|
|
3700
|
+
apy7d: p.apy7d ?? 0,
|
|
3701
|
+
apy30d: p.apy30d ?? 0,
|
|
3702
|
+
netFlow24h: p.netFlow24h ?? 0,
|
|
3703
|
+
txCount24h: p.txCount24h ?? 0,
|
|
3704
|
+
txCountTotal: p.txCountTotal ?? 0,
|
|
3705
|
+
totalDeposits: p.totalDeposits ?? 0,
|
|
3706
|
+
totalWithdrawals: p.totalWithdrawals ?? 0,
|
|
3707
|
+
profitDistributed: p.profitDistributed ?? 0,
|
|
3708
|
+
lastUpdated: p.lastUpdated ?? Date.now()
|
|
3709
|
+
})));
|
|
3710
|
+
}
|
|
3711
|
+
setError(null);
|
|
3712
|
+
} catch (err) {
|
|
3713
|
+
setError(err instanceof Error ? err.message : "Failed to fetch pools");
|
|
3714
|
+
} finally {
|
|
3715
|
+
setIsLoading(false);
|
|
3716
|
+
}
|
|
3717
|
+
}, []);
|
|
3718
|
+
useEffect(() => {
|
|
3719
|
+
fetchPools();
|
|
3720
|
+
if (options?.refreshInterval) {
|
|
3721
|
+
const timer = setInterval(fetchPools, options.refreshInterval);
|
|
3722
|
+
return () => clearInterval(timer);
|
|
3723
|
+
}
|
|
3724
|
+
}, [fetchPools, options?.refreshInterval]);
|
|
3725
|
+
return { pools, isLoading, error, refresh: fetchPools };
|
|
3726
|
+
}
|
|
3727
|
+
function useForexInvestments(options) {
|
|
3728
|
+
const [investments, setInvestments] = useState([]);
|
|
3729
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
3730
|
+
const [error, setError] = useState(null);
|
|
3731
|
+
const fetchInvestments = useCallback(async () => {
|
|
3732
|
+
setIsLoading(true);
|
|
3733
|
+
try {
|
|
3734
|
+
const data = await forexApi("/api/forex/investments");
|
|
3735
|
+
if (data?.investments) {
|
|
3736
|
+
setInvestments(data.investments.map(mapInvestment));
|
|
3737
|
+
}
|
|
3738
|
+
setError(null);
|
|
3739
|
+
} catch {
|
|
3740
|
+
setError("Failed to fetch investments");
|
|
3741
|
+
} finally {
|
|
3742
|
+
setIsLoading(false);
|
|
3743
|
+
}
|
|
3744
|
+
}, []);
|
|
3745
|
+
const createInvestment = useCallback(async (params) => {
|
|
3746
|
+
setIsLoading(true);
|
|
3747
|
+
try {
|
|
3748
|
+
const data = await forexApi("/api/forex/investments", {
|
|
3749
|
+
method: "POST",
|
|
3750
|
+
body: JSON.stringify(params)
|
|
3751
|
+
});
|
|
3752
|
+
if (data?.investment) {
|
|
3753
|
+
const inv2 = mapInvestment(data.investment);
|
|
3754
|
+
setInvestments((prev) => [inv2, ...prev]);
|
|
3755
|
+
return inv2;
|
|
3756
|
+
}
|
|
3757
|
+
const inv = createLocalInvestment(params);
|
|
3758
|
+
setInvestments((prev) => [inv, ...prev]);
|
|
3759
|
+
return inv;
|
|
3760
|
+
} catch {
|
|
3761
|
+
const inv = createLocalInvestment(params);
|
|
3762
|
+
setInvestments((prev) => [inv, ...prev]);
|
|
3763
|
+
return inv;
|
|
3764
|
+
} finally {
|
|
3765
|
+
setIsLoading(false);
|
|
3766
|
+
}
|
|
3767
|
+
}, []);
|
|
3768
|
+
const redeemInvestment = useCallback(async (investmentId) => {
|
|
3769
|
+
try {
|
|
3770
|
+
await forexApi(`/api/forex/investments/${investmentId}/redeem`, { method: "POST" });
|
|
3771
|
+
setInvestments((prev) => prev.map(
|
|
3772
|
+
(inv) => inv.id === investmentId ? { ...inv, status: "redeemed" } : inv
|
|
3773
|
+
));
|
|
3774
|
+
return true;
|
|
3775
|
+
} catch {
|
|
3776
|
+
return false;
|
|
3777
|
+
}
|
|
3778
|
+
}, []);
|
|
3779
|
+
useEffect(() => {
|
|
3780
|
+
fetchInvestments();
|
|
3781
|
+
if (options?.refreshInterval) {
|
|
3782
|
+
const timer = setInterval(fetchInvestments, options.refreshInterval);
|
|
3783
|
+
return () => clearInterval(timer);
|
|
3784
|
+
}
|
|
3785
|
+
}, [fetchInvestments, options?.refreshInterval]);
|
|
3786
|
+
const portfolioSummary = useMemo(() => {
|
|
3787
|
+
const active = investments.filter((i) => i.status === "active");
|
|
3788
|
+
return {
|
|
3789
|
+
totalInvested: active.reduce((s, i) => s + i.amount, 0),
|
|
3790
|
+
totalValue: active.reduce((s, i) => s + i.currentValue, 0),
|
|
3791
|
+
totalProfit: active.reduce((s, i) => s + i.profit, 0),
|
|
3792
|
+
activeCount: active.length
|
|
3793
|
+
};
|
|
3794
|
+
}, [investments]);
|
|
3795
|
+
return { investments, isLoading, error, createInvestment, redeemInvestment, refresh: fetchInvestments, portfolioSummary };
|
|
3796
|
+
}
|
|
3797
|
+
function useForexSimulation(options) {
|
|
3798
|
+
const maxLogs = options?.maxLogs ?? 500;
|
|
3799
|
+
const [logs, setLogs] = useState([]);
|
|
3800
|
+
const [poolTxs, setPoolTxs] = useState([]);
|
|
3801
|
+
const [isRunning, setIsRunning] = useState(false);
|
|
3802
|
+
const [stats, setStats] = useState({ totalPnl: 0, totalTrades: 0, totalPips: 0, totalLots: 0 });
|
|
3803
|
+
const engineRef = useRef(null);
|
|
3804
|
+
const getEngine = useCallback(() => {
|
|
3805
|
+
if (!engineRef.current) {
|
|
3806
|
+
try {
|
|
3807
|
+
const { forexSimulationEngine: forexSimulationEngine2 } = (init_ForexSimulationEngine(), __toCommonJS(ForexSimulationEngine_exports));
|
|
3808
|
+
engineRef.current = forexSimulationEngine2;
|
|
3809
|
+
} catch {
|
|
3810
|
+
}
|
|
3811
|
+
}
|
|
3812
|
+
return engineRef.current;
|
|
3813
|
+
}, []);
|
|
3814
|
+
const start = useCallback(() => {
|
|
3815
|
+
const engine = getEngine();
|
|
3816
|
+
if (!engine) return;
|
|
3817
|
+
if (!engine.isRunning()) engine.start();
|
|
3818
|
+
setIsRunning(true);
|
|
3819
|
+
}, [getEngine]);
|
|
3820
|
+
const stop = useCallback(() => {
|
|
3821
|
+
const engine = getEngine();
|
|
3822
|
+
if (engine) engine.stop();
|
|
3823
|
+
setIsRunning(false);
|
|
3824
|
+
}, [getEngine]);
|
|
3825
|
+
const clearLogs = useCallback(() => {
|
|
3826
|
+
setLogs([]);
|
|
3827
|
+
setPoolTxs([]);
|
|
3828
|
+
}, []);
|
|
3829
|
+
useEffect(() => {
|
|
3830
|
+
const engine = getEngine();
|
|
3831
|
+
if (!engine) return;
|
|
3832
|
+
const unsubLog = engine.onLog((entry) => {
|
|
3833
|
+
setLogs((prev) => {
|
|
3834
|
+
const next = [...prev, entry];
|
|
3835
|
+
return next.length > maxLogs ? next.slice(-maxLogs) : next;
|
|
3836
|
+
});
|
|
3837
|
+
const s = engine.getStats();
|
|
3838
|
+
setStats({ totalPnl: s.totalPnl, totalTrades: s.totalTrades, totalPips: s.totalPips, totalLots: s.totalLots });
|
|
3839
|
+
});
|
|
3840
|
+
const unsubTx = engine.onPoolTransaction((tx) => {
|
|
3841
|
+
setPoolTxs((prev) => [...prev.slice(-999), tx]);
|
|
3842
|
+
});
|
|
3843
|
+
return () => {
|
|
3844
|
+
unsubLog();
|
|
3845
|
+
unsubTx();
|
|
3846
|
+
};
|
|
3847
|
+
}, [getEngine, maxLogs]);
|
|
3848
|
+
return { logs, poolTransactions: poolTxs, isRunning, stats, start, stop, clearLogs };
|
|
3849
|
+
}
|
|
3850
|
+
function useForexPoolData() {
|
|
3851
|
+
const [snapshots, setSnapshots] = useState({ clearing: [], hedging: [], insurance: [] });
|
|
3852
|
+
const [transactions, setTransactions] = useState([]);
|
|
3853
|
+
const [isInitialized, setIsInitialized] = useState(false);
|
|
3854
|
+
const initialize = useCallback(() => {
|
|
3855
|
+
if (isInitialized) return;
|
|
3856
|
+
try {
|
|
3857
|
+
const { ForexPoolDataGenerator: ForexPoolDataGenerator2 } = (init_ForexPoolDataGenerator(), __toCommonJS(ForexPoolDataGenerator_exports));
|
|
3858
|
+
const gen = ForexPoolDataGenerator2.getInstance();
|
|
3859
|
+
setSnapshots(gen.generateAllSnapshots());
|
|
3860
|
+
setTransactions(gen.generateAllTransactions());
|
|
3861
|
+
setIsInitialized(true);
|
|
3862
|
+
} catch {
|
|
3863
|
+
}
|
|
3864
|
+
}, [isInitialized]);
|
|
3865
|
+
return { snapshots, transactions, isInitialized, initialize };
|
|
3866
|
+
}
|
|
3867
|
+
function useForexTrading(options) {
|
|
3868
|
+
const pools = useForexPools({ refreshInterval: options?.poolRefreshInterval });
|
|
3869
|
+
const investments = useForexInvestments({ refreshInterval: options?.investmentRefreshInterval });
|
|
3870
|
+
const simulation = useForexSimulation();
|
|
3871
|
+
const poolData = useForexPoolData();
|
|
3872
|
+
return {
|
|
3873
|
+
pools,
|
|
3874
|
+
investments,
|
|
3875
|
+
simulation,
|
|
3876
|
+
poolData,
|
|
3877
|
+
capitalSplit: FOREX_CAPITAL_SPLIT,
|
|
3878
|
+
agent: FOREX_AGENT,
|
|
3879
|
+
currencyPairs: (init_forex(), __toCommonJS(forex_exports)).FOREX_CURRENCY_PAIRS,
|
|
3880
|
+
cycleOptions: (init_forex(), __toCommonJS(forex_exports)).FOREX_CYCLE_OPTIONS,
|
|
3881
|
+
computePoolAllocations,
|
|
3882
|
+
estimateProfit: estimateForexProfit
|
|
3883
|
+
};
|
|
3884
|
+
}
|
|
3885
|
+
function mapInvestment(raw) {
|
|
3886
|
+
const cycleDays = raw.cycleDays ?? raw.cycle_days ?? 90;
|
|
3887
|
+
const cycleOption = FOREX_CYCLE_OPTIONS.find((c) => c.days === cycleDays) || FOREX_CYCLE_OPTIONS[2];
|
|
3888
|
+
const amount = typeof raw.amount === "string" ? parseFloat(raw.amount) : raw.amount ?? 0;
|
|
3889
|
+
const allocs = computePoolAllocations(amount);
|
|
3890
|
+
return {
|
|
3891
|
+
id: raw.id,
|
|
3892
|
+
userId: raw.userId ?? raw.user_id,
|
|
3893
|
+
amount,
|
|
3894
|
+
currentValue: raw.currentValue ?? raw.current_value ?? amount,
|
|
3895
|
+
profit: raw.profit ?? 0,
|
|
3896
|
+
status: raw.status ?? "active",
|
|
3897
|
+
selectedPairs: raw.selectedPairs ?? raw.selected_pairs ?? [],
|
|
3898
|
+
cycleDays,
|
|
3899
|
+
cycleOption,
|
|
3900
|
+
feeRate: raw.feeRate ?? cycleOption.feeRate,
|
|
3901
|
+
commissionRate: raw.commissionRate ?? cycleOption.commissionRate,
|
|
3902
|
+
startDate: raw.startDate ?? raw.start_date ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
3903
|
+
endDate: raw.endDate ?? raw.end_date ?? "",
|
|
3904
|
+
tradingCapital: raw.tradingCapital ?? allocs.tradingCapital,
|
|
3905
|
+
totalPoolReserves: raw.totalPoolReserves ?? allocs.totalPoolReserves,
|
|
3906
|
+
poolAllocations: raw.poolAllocations ?? {
|
|
3907
|
+
clearing: allocs.clearing,
|
|
3908
|
+
hedging: allocs.hedging,
|
|
3909
|
+
insurance: allocs.insurance
|
|
3910
|
+
},
|
|
3911
|
+
tradeWeight: raw.tradeWeight ?? 0,
|
|
3912
|
+
totalLots: raw.totalLots ?? 0,
|
|
3913
|
+
totalPips: raw.totalPips ?? 0,
|
|
3914
|
+
totalTrades: raw.totalTrades ?? 0,
|
|
3915
|
+
positions: raw.positions ?? [],
|
|
3916
|
+
tradeHistory: raw.tradeHistory ?? [],
|
|
3917
|
+
redeemedAt: raw.redeemedAt,
|
|
3918
|
+
createdAt: raw.createdAt,
|
|
3919
|
+
updatedAt: raw.updatedAt
|
|
3920
|
+
};
|
|
3921
|
+
}
|
|
3922
|
+
function createLocalInvestment(params) {
|
|
3923
|
+
const { amount, selectedPairs, cycleDays } = params;
|
|
3924
|
+
const cycleOption = FOREX_CYCLE_OPTIONS.find((c) => c.days === cycleDays) || FOREX_CYCLE_OPTIONS[2];
|
|
3925
|
+
const allocs = computePoolAllocations(amount);
|
|
3926
|
+
const now = /* @__PURE__ */ new Date();
|
|
3927
|
+
const endDate = new Date(now);
|
|
3928
|
+
endDate.setDate(endDate.getDate() + cycleDays);
|
|
3929
|
+
return {
|
|
3930
|
+
id: `fx_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
3931
|
+
amount,
|
|
3932
|
+
currentValue: amount,
|
|
3933
|
+
profit: 0,
|
|
3934
|
+
status: "active",
|
|
3935
|
+
selectedPairs,
|
|
3936
|
+
cycleDays,
|
|
3937
|
+
cycleOption,
|
|
3938
|
+
startDate: now.toISOString(),
|
|
3939
|
+
endDate: endDate.toISOString(),
|
|
3940
|
+
tradingCapital: allocs.tradingCapital,
|
|
3941
|
+
totalPoolReserves: allocs.totalPoolReserves,
|
|
3942
|
+
poolAllocations: { clearing: allocs.clearing, hedging: allocs.hedging, insurance: allocs.insurance },
|
|
3943
|
+
tradeWeight: 0,
|
|
3944
|
+
totalLots: 0,
|
|
3945
|
+
totalPips: 0,
|
|
3946
|
+
totalTrades: 0,
|
|
3947
|
+
positions: [],
|
|
3948
|
+
tradeHistory: []
|
|
3949
|
+
};
|
|
3950
|
+
}
|
|
3951
|
+
|
|
3952
|
+
// src/react-native.ts
|
|
3953
|
+
init_ForexSimulationEngine();
|
|
3954
|
+
init_ForexPoolDataGenerator();
|
|
3955
|
+
|
|
3956
|
+
// src/services/forex/BotSimulationEngine.ts
|
|
3957
|
+
var STRATEGY_PERSONALITIES = [
|
|
3958
|
+
{
|
|
3959
|
+
id: "balanced-01",
|
|
3960
|
+
name: "Balanced Alpha",
|
|
3961
|
+
shortName: "BAL",
|
|
3962
|
+
color: "#3B82F6",
|
|
3963
|
+
scanIntervalMin: 25e3,
|
|
3964
|
+
// Slower: 25-40s between cycles
|
|
3965
|
+
scanIntervalMax: 4e4,
|
|
3966
|
+
tradeFrequency: 0.4,
|
|
3967
|
+
positionSizeMin: 15,
|
|
3968
|
+
positionSizeMax: 35,
|
|
3969
|
+
leverageMin: 3,
|
|
3970
|
+
leverageMax: 10,
|
|
3971
|
+
primaryIndicators: ["RSI", "MACD"],
|
|
3972
|
+
riskTolerance: "medium",
|
|
3973
|
+
preferredPairs: ["BTC/USDT", "ETH/USDT", "SOL/USDT"],
|
|
3974
|
+
rsiBias: 50
|
|
2770
3975
|
},
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
3976
|
+
{
|
|
3977
|
+
id: "conservative-01",
|
|
3978
|
+
name: "Conservative Shield",
|
|
3979
|
+
shortName: "CON",
|
|
3980
|
+
color: "#10B981",
|
|
3981
|
+
scanIntervalMin: 35e3,
|
|
3982
|
+
// Slower: 35-55s between cycles
|
|
3983
|
+
scanIntervalMax: 55e3,
|
|
3984
|
+
tradeFrequency: 0.25,
|
|
3985
|
+
positionSizeMin: 10,
|
|
3986
|
+
positionSizeMax: 20,
|
|
3987
|
+
leverageMin: 2,
|
|
3988
|
+
leverageMax: 5,
|
|
3989
|
+
primaryIndicators: ["Bollinger", "Volume"],
|
|
3990
|
+
riskTolerance: "low",
|
|
3991
|
+
preferredPairs: ["BTC/USDT", "ETH/USDT"],
|
|
3992
|
+
rsiBias: 45
|
|
2777
3993
|
},
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
3994
|
+
{
|
|
3995
|
+
id: "aggressive-01",
|
|
3996
|
+
name: "Aggressive Momentum",
|
|
3997
|
+
shortName: "AGG",
|
|
3998
|
+
color: "#EF4444",
|
|
3999
|
+
scanIntervalMin: 18e3,
|
|
4000
|
+
// Slower: 18-30s between cycles
|
|
4001
|
+
scanIntervalMax: 3e4,
|
|
4002
|
+
tradeFrequency: 0.5,
|
|
4003
|
+
positionSizeMin: 25,
|
|
4004
|
+
positionSizeMax: 50,
|
|
4005
|
+
leverageMin: 5,
|
|
4006
|
+
leverageMax: 20,
|
|
4007
|
+
primaryIndicators: ["RSI", "MACD", "EMA", "Volume"],
|
|
4008
|
+
riskTolerance: "high",
|
|
4009
|
+
preferredPairs: ["BTC/USDT", "ETH/USDT", "SOL/USDT", "DOGE/USDT", "AVAX/USDT"],
|
|
4010
|
+
rsiBias: 55
|
|
4011
|
+
}
|
|
4012
|
+
];
|
|
4013
|
+
var PAIR_PRICES = {
|
|
4014
|
+
"BTC/USDT": 67500,
|
|
4015
|
+
"ETH/USDT": 3450,
|
|
4016
|
+
"BNB/USDT": 605,
|
|
4017
|
+
"SOL/USDT": 178,
|
|
4018
|
+
"XRP/USDT": 0.62,
|
|
4019
|
+
"DOGE/USDT": 0.165,
|
|
4020
|
+
"ADA/USDT": 0.45,
|
|
4021
|
+
"AVAX/USDT": 38.5,
|
|
4022
|
+
"ARB/USDT": 1.18,
|
|
4023
|
+
"MATIC/USDT": 0.72,
|
|
4024
|
+
"LINK/USDT": 14.5,
|
|
4025
|
+
"UNI/USDT": 7.8,
|
|
4026
|
+
"AAVE/USDT": 92,
|
|
4027
|
+
"OP/USDT": 2.45,
|
|
4028
|
+
"APT/USDT": 8.9,
|
|
4029
|
+
"INJ/USDT": 24.5,
|
|
4030
|
+
"TIA/USDT": 11.2,
|
|
4031
|
+
"SUI/USDT": 1.65,
|
|
4032
|
+
"DOT/USDT": 7.2,
|
|
4033
|
+
"ATOM/USDT": 9.8,
|
|
4034
|
+
"FIL/USDT": 5.6,
|
|
4035
|
+
"LTC/USDT": 72,
|
|
4036
|
+
"NEAR/USDT": 5.1,
|
|
4037
|
+
"FTM/USDT": 0.42
|
|
4038
|
+
};
|
|
4039
|
+
var CHAIN_INFO = {
|
|
4040
|
+
ethereum: { name: "Ethereum", shortName: "ETH", icon: "\u039E" },
|
|
4041
|
+
arbitrum: { name: "Arbitrum", shortName: "ARB", icon: "\u25C6" },
|
|
4042
|
+
bsc: { name: "BSC", shortName: "BSC", icon: "\u25C6" },
|
|
4043
|
+
base: { name: "Base", shortName: "BASE", icon: "\u25CF" },
|
|
4044
|
+
polygon: { name: "Polygon", shortName: "POLY", icon: "\u2B21" },
|
|
4045
|
+
optimism: { name: "Optimism", shortName: "OP", icon: "\u25C9" },
|
|
4046
|
+
avalanche: { name: "Avalanche", shortName: "AVAX", icon: "\u25B2" },
|
|
4047
|
+
linea: { name: "Linea", shortName: "LINEA", icon: "\u2550" },
|
|
4048
|
+
zksync: { name: "zkSync", shortName: "ZK", icon: "\u2B22" },
|
|
4049
|
+
scroll: { name: "Scroll", shortName: "SCRL", icon: "\u25CE" }
|
|
4050
|
+
};
|
|
4051
|
+
var NEWS_HEADLINES = [
|
|
4052
|
+
"Fed signals potential rate pause, crypto markets react positively",
|
|
4053
|
+
"Major institutional investor increases BTC allocation by 15%",
|
|
4054
|
+
"On-chain data shows whale accumulation pattern forming",
|
|
4055
|
+
"DeFi TVL reaches new monthly high across major protocols",
|
|
4056
|
+
"Exchange outflows surge as holders move to cold storage",
|
|
4057
|
+
"Options market signals increased volatility expected this week",
|
|
4058
|
+
"Mining difficulty adjustment approaching, hash rate stable",
|
|
4059
|
+
"Regulatory clarity in EU boosts market sentiment",
|
|
4060
|
+
"Stablecoin supply expanding, potential bullish indicator",
|
|
4061
|
+
"Social sentiment score shifts to extreme greed zone",
|
|
4062
|
+
"Cross-chain bridge volume hits record daily high",
|
|
4063
|
+
"Layer 2 adoption metrics show 40% MoM growth"
|
|
4064
|
+
];
|
|
4065
|
+
var idCounter2 = 0;
|
|
4066
|
+
function genId3() {
|
|
4067
|
+
return `log_${Date.now()}_${++idCounter2}`;
|
|
4068
|
+
}
|
|
4069
|
+
function rand3(min, max) {
|
|
4070
|
+
return min + Math.random() * (max - min);
|
|
4071
|
+
}
|
|
4072
|
+
function randInt3(min, max) {
|
|
4073
|
+
return Math.floor(rand3(min, max + 1));
|
|
4074
|
+
}
|
|
4075
|
+
function pick4(arr) {
|
|
4076
|
+
return arr[Math.floor(Math.random() * arr.length)];
|
|
4077
|
+
}
|
|
4078
|
+
function clamp(val, min, max) {
|
|
4079
|
+
return Math.max(min, Math.min(max, val));
|
|
4080
|
+
}
|
|
4081
|
+
function formatPrice(price) {
|
|
4082
|
+
if (price >= 1e3) return price.toFixed(2);
|
|
4083
|
+
if (price >= 1) return price.toFixed(3);
|
|
4084
|
+
return price.toFixed(5);
|
|
4085
|
+
}
|
|
4086
|
+
var BotSimulationEngine = class {
|
|
4087
|
+
constructor() {
|
|
4088
|
+
this.listeners = [];
|
|
4089
|
+
this.botTimers = /* @__PURE__ */ new Map();
|
|
4090
|
+
this.botStates = /* @__PURE__ */ new Map();
|
|
4091
|
+
this.priceState = /* @__PURE__ */ new Map();
|
|
4092
|
+
this.indicatorState = /* @__PURE__ */ new Map();
|
|
4093
|
+
this.running = false;
|
|
4094
|
+
this.userPairs = [];
|
|
4095
|
+
this.userChains = [];
|
|
4096
|
+
for (const [pair, base] of Object.entries(PAIR_PRICES)) {
|
|
4097
|
+
this.priceState.set(pair, base * (1 + rand3(-0.02, 0.02)));
|
|
4098
|
+
}
|
|
2782
4099
|
}
|
|
2783
|
-
|
|
4100
|
+
// ── Public API ─────────────────────────────────────────────────────────────
|
|
4101
|
+
getStrategies() {
|
|
4102
|
+
return STRATEGY_PERSONALITIES;
|
|
4103
|
+
}
|
|
4104
|
+
start(strategyIds, userPairs, userChains) {
|
|
4105
|
+
this.running = true;
|
|
4106
|
+
this.userPairs = (userPairs || []).map((p) => p.includes("/") ? p : `${p}/USDT`).filter((p) => p in PAIR_PRICES);
|
|
4107
|
+
this.userChains = (userChains || []).filter((c) => c in CHAIN_INFO);
|
|
4108
|
+
const strategies = strategyIds ? STRATEGY_PERSONALITIES.filter((s) => strategyIds.includes(s.id)) : STRATEGY_PERSONALITIES;
|
|
4109
|
+
for (const strategy of strategies) {
|
|
4110
|
+
this.initBotState(strategy);
|
|
4111
|
+
this.scheduleCycle(strategy);
|
|
4112
|
+
}
|
|
4113
|
+
}
|
|
4114
|
+
stop(strategyIds) {
|
|
4115
|
+
const ids = strategyIds || Array.from(this.botTimers.keys());
|
|
4116
|
+
for (const id of ids) {
|
|
4117
|
+
const timer = this.botTimers.get(id);
|
|
4118
|
+
if (timer) {
|
|
4119
|
+
clearTimeout(timer);
|
|
4120
|
+
this.botTimers.delete(id);
|
|
4121
|
+
}
|
|
4122
|
+
}
|
|
4123
|
+
if (!strategyIds) {
|
|
4124
|
+
this.running = false;
|
|
4125
|
+
}
|
|
4126
|
+
}
|
|
4127
|
+
onLog(callback) {
|
|
4128
|
+
this.listeners.push(callback);
|
|
4129
|
+
return () => {
|
|
4130
|
+
this.listeners = this.listeners.filter((l) => l !== callback);
|
|
4131
|
+
};
|
|
4132
|
+
}
|
|
4133
|
+
getBotState(strategyId) {
|
|
4134
|
+
return this.botStates.get(strategyId);
|
|
4135
|
+
}
|
|
4136
|
+
getAllBotStates() {
|
|
4137
|
+
return this.botStates;
|
|
4138
|
+
}
|
|
4139
|
+
isRunning() {
|
|
4140
|
+
return this.running;
|
|
4141
|
+
}
|
|
4142
|
+
emitBootSequence() {
|
|
4143
|
+
const bootMessages = [
|
|
4144
|
+
{ msg: "Initializing ONE Trading Engine v3.2.1...", delay: 0 },
|
|
4145
|
+
{ msg: "Loading market data feeds...", delay: 500 },
|
|
4146
|
+
{ msg: "Connecting to exchange WebSocket streams...", delay: 1200 },
|
|
4147
|
+
{ msg: "Calibrating indicator engines (RSI, MACD, EMA, Bollinger)...", delay: 2e3 },
|
|
4148
|
+
{ msg: "Loading strategy personalities: balanced-01, conservative-01, aggressive-01", delay: 2800 },
|
|
4149
|
+
{ msg: "Risk management module initialized (max drawdown: 15%)", delay: 3600 },
|
|
4150
|
+
{ msg: "Portfolio allocation engine ready", delay: 4200 },
|
|
4151
|
+
{ msg: "=== All systems online. Starting trading cycles ===", delay: 5e3 }
|
|
4152
|
+
];
|
|
4153
|
+
for (const { msg, delay } of bootMessages) {
|
|
4154
|
+
setTimeout(() => {
|
|
4155
|
+
this.emit({
|
|
4156
|
+
id: genId3(),
|
|
4157
|
+
timestamp: Date.now(),
|
|
4158
|
+
strategyId: "system",
|
|
4159
|
+
strategyName: "SYSTEM",
|
|
4160
|
+
type: "SYSTEM",
|
|
4161
|
+
message: msg,
|
|
4162
|
+
importance: "medium"
|
|
4163
|
+
});
|
|
4164
|
+
}, delay);
|
|
4165
|
+
}
|
|
4166
|
+
}
|
|
4167
|
+
destroy() {
|
|
4168
|
+
this.stop();
|
|
4169
|
+
this.listeners = [];
|
|
4170
|
+
this.botStates.clear();
|
|
4171
|
+
this.priceState.clear();
|
|
4172
|
+
this.indicatorState.clear();
|
|
4173
|
+
this.userPairs = [];
|
|
4174
|
+
this.userChains = [];
|
|
4175
|
+
}
|
|
4176
|
+
// ── Private Methods ────────────────────────────────────────────────────────
|
|
4177
|
+
emit(entry) {
|
|
4178
|
+
for (const listener of this.listeners) {
|
|
4179
|
+
listener(entry);
|
|
4180
|
+
}
|
|
4181
|
+
}
|
|
4182
|
+
getActivePairs(strategy) {
|
|
4183
|
+
return this.userPairs.length > 0 ? this.userPairs : strategy.preferredPairs;
|
|
4184
|
+
}
|
|
4185
|
+
getActiveChain() {
|
|
4186
|
+
const chains = this.userChains.length > 0 ? this.userChains : ["ethereum", "arbitrum", "bsc"];
|
|
4187
|
+
return pick4(chains);
|
|
4188
|
+
}
|
|
4189
|
+
getChainLabel(chainId) {
|
|
4190
|
+
const info = CHAIN_INFO[chainId];
|
|
4191
|
+
return info ? info.shortName : chainId;
|
|
4192
|
+
}
|
|
4193
|
+
initBotState(strategy) {
|
|
4194
|
+
const activePairs = this.getActivePairs(strategy);
|
|
4195
|
+
const pair = pick4(activePairs);
|
|
4196
|
+
const price = this.priceState.get(pair) || PAIR_PRICES[pair] || 5e4;
|
|
4197
|
+
const indicators = this.generateIndicators(strategy, price);
|
|
4198
|
+
this.indicatorState.set(strategy.id, indicators);
|
|
4199
|
+
this.botStates.set(strategy.id, {
|
|
4200
|
+
strategyId: strategy.id,
|
|
4201
|
+
strategyName: strategy.name,
|
|
4202
|
+
isRunning: true,
|
|
4203
|
+
currentPair: pair,
|
|
4204
|
+
currentPrice: price,
|
|
4205
|
+
indicators,
|
|
4206
|
+
openPositions: [],
|
|
4207
|
+
totalPnl: rand3(-50, 200),
|
|
4208
|
+
totalTrades: randInt3(5, 25),
|
|
4209
|
+
winRate: rand3(0.48, 0.68),
|
|
4210
|
+
lastSignal: "HOLD",
|
|
4211
|
+
lastSignalConfidence: 0
|
|
4212
|
+
});
|
|
4213
|
+
}
|
|
4214
|
+
scheduleCycle(strategy) {
|
|
4215
|
+
if (!this.running) return;
|
|
4216
|
+
const interval = rand3(strategy.scanIntervalMin, strategy.scanIntervalMax);
|
|
4217
|
+
const timer = setTimeout(() => {
|
|
4218
|
+
if (this.running) {
|
|
4219
|
+
this.runBotCycle(strategy);
|
|
4220
|
+
this.scheduleCycle(strategy);
|
|
4221
|
+
}
|
|
4222
|
+
}, interval);
|
|
4223
|
+
this.botTimers.set(strategy.id, timer);
|
|
4224
|
+
}
|
|
4225
|
+
async runBotCycle(strategy) {
|
|
4226
|
+
const state = this.botStates.get(strategy.id);
|
|
4227
|
+
if (!state) return;
|
|
4228
|
+
const activePairs = this.getActivePairs(strategy);
|
|
4229
|
+
const pair = pick4(activePairs);
|
|
4230
|
+
const price = this.simulatePrice(pair);
|
|
4231
|
+
const indicators = this.generateIndicators(strategy, price);
|
|
4232
|
+
this.indicatorState.set(strategy.id, indicators);
|
|
4233
|
+
state.currentPair = pair;
|
|
4234
|
+
state.currentPrice = price;
|
|
4235
|
+
state.indicators = indicators;
|
|
4236
|
+
const entries = [];
|
|
4237
|
+
let delay = 0;
|
|
4238
|
+
const chain = this.getActiveChain();
|
|
4239
|
+
const chainLabel = this.getChainLabel(chain);
|
|
4240
|
+
entries.push({
|
|
4241
|
+
entry: {
|
|
4242
|
+
strategyId: strategy.id,
|
|
4243
|
+
strategyName: strategy.shortName,
|
|
4244
|
+
type: "SCAN",
|
|
4245
|
+
message: `Scanning ${pair} on ${chainLabel} | Price: $${formatPrice(price)}`,
|
|
4246
|
+
data: { pair, chain, chainLabel },
|
|
4247
|
+
importance: "low"
|
|
4248
|
+
},
|
|
4249
|
+
delay
|
|
4250
|
+
});
|
|
4251
|
+
delay += rand3(800, 1500);
|
|
4252
|
+
const thinkingMessages = this.generateThinkingProcess(strategy, pair, price);
|
|
4253
|
+
for (const thinking of thinkingMessages) {
|
|
4254
|
+
entries.push({
|
|
4255
|
+
entry: {
|
|
4256
|
+
strategyId: strategy.id,
|
|
4257
|
+
strategyName: strategy.shortName,
|
|
4258
|
+
type: "THINKING",
|
|
4259
|
+
message: thinking,
|
|
4260
|
+
importance: "low"
|
|
4261
|
+
},
|
|
4262
|
+
delay
|
|
4263
|
+
});
|
|
4264
|
+
delay += rand3(600, 1200);
|
|
4265
|
+
}
|
|
4266
|
+
const indicatorParts = [];
|
|
4267
|
+
if (strategy.primaryIndicators.includes("RSI") || strategy.primaryIndicators.includes("MACD")) {
|
|
4268
|
+
indicatorParts.push(`RSI: ${indicators.rsi.toFixed(1)}`);
|
|
4269
|
+
}
|
|
4270
|
+
if (strategy.primaryIndicators.includes("MACD") || strategy.primaryIndicators.includes("RSI")) {
|
|
4271
|
+
indicatorParts.push(`MACD: ${indicators.macd.histogram > 0 ? "+" : ""}${indicators.macd.histogram.toFixed(3)}`);
|
|
4272
|
+
}
|
|
4273
|
+
if (strategy.primaryIndicators.includes("EMA")) {
|
|
4274
|
+
indicatorParts.push(`EMA: ${indicators.ema.short.toFixed(1)}/${indicators.ema.long.toFixed(1)}`);
|
|
4275
|
+
if (indicators.ema.crossover !== "none") {
|
|
4276
|
+
indicatorParts.push(`[${indicators.ema.crossover.toUpperCase()} CROSS]`);
|
|
4277
|
+
}
|
|
4278
|
+
}
|
|
4279
|
+
if (strategy.primaryIndicators.includes("Bollinger")) {
|
|
4280
|
+
indicatorParts.push(`BB: ${indicators.bollinger.position.toFixed(1)}% width=${indicators.bollinger.width.toFixed(2)}`);
|
|
4281
|
+
}
|
|
4282
|
+
if (strategy.primaryIndicators.includes("Volume")) {
|
|
4283
|
+
indicatorParts.push(`Vol: ${indicators.volume.ratio.toFixed(2)}x avg`);
|
|
4284
|
+
}
|
|
4285
|
+
entries.push({
|
|
4286
|
+
entry: {
|
|
4287
|
+
strategyId: strategy.id,
|
|
4288
|
+
strategyName: strategy.shortName,
|
|
4289
|
+
type: "INDICATOR",
|
|
4290
|
+
message: indicatorParts.join(" | "),
|
|
4291
|
+
data: { indicators },
|
|
4292
|
+
importance: "low"
|
|
4293
|
+
},
|
|
4294
|
+
delay
|
|
4295
|
+
});
|
|
4296
|
+
delay += rand3(800, 1500);
|
|
4297
|
+
if (Math.random() < 0.12) {
|
|
4298
|
+
const sentiment = Math.random() > 0.4 ? "Bullish" : "Bearish";
|
|
4299
|
+
entries.push({
|
|
4300
|
+
entry: {
|
|
4301
|
+
strategyId: strategy.id,
|
|
4302
|
+
strategyName: strategy.shortName,
|
|
4303
|
+
type: "NEWS",
|
|
4304
|
+
message: `[${sentiment}] ${pick4(NEWS_HEADLINES)}`,
|
|
4305
|
+
importance: "medium"
|
|
4306
|
+
},
|
|
4307
|
+
delay
|
|
4308
|
+
});
|
|
4309
|
+
delay += rand3(1e3, 1800);
|
|
4310
|
+
}
|
|
4311
|
+
if (Math.random() < 0.4) {
|
|
4312
|
+
const analysis = this.generateAnalysis(strategy, indicators, pair);
|
|
4313
|
+
entries.push({
|
|
4314
|
+
entry: {
|
|
4315
|
+
strategyId: strategy.id,
|
|
4316
|
+
strategyName: strategy.shortName,
|
|
4317
|
+
type: "ANALYSIS",
|
|
4318
|
+
message: analysis,
|
|
4319
|
+
importance: "medium"
|
|
4320
|
+
},
|
|
4321
|
+
delay
|
|
4322
|
+
});
|
|
4323
|
+
delay += rand3(1e3, 2e3);
|
|
4324
|
+
}
|
|
4325
|
+
const signal = this.evaluateSignal(strategy, indicators);
|
|
4326
|
+
state.lastSignal = signal.direction;
|
|
4327
|
+
state.lastSignalConfidence = signal.confidence;
|
|
4328
|
+
if (signal.direction !== "HOLD") {
|
|
4329
|
+
const strategyContext = this.generateStrategyContext(strategy, signal, indicators, pair);
|
|
4330
|
+
entries.push({
|
|
4331
|
+
entry: {
|
|
4332
|
+
strategyId: strategy.id,
|
|
4333
|
+
strategyName: strategy.shortName,
|
|
4334
|
+
type: "STRATEGY",
|
|
4335
|
+
message: strategyContext,
|
|
4336
|
+
data: {
|
|
4337
|
+
strategy: strategy.name,
|
|
4338
|
+
riskTolerance: strategy.riskTolerance,
|
|
4339
|
+
primaryIndicators: strategy.primaryIndicators,
|
|
4340
|
+
signal: signal.direction,
|
|
4341
|
+
confidence: signal.confidence
|
|
4342
|
+
},
|
|
4343
|
+
importance: "high"
|
|
4344
|
+
},
|
|
4345
|
+
delay
|
|
4346
|
+
});
|
|
4347
|
+
delay += rand3(1500, 2500);
|
|
4348
|
+
entries.push({
|
|
4349
|
+
entry: {
|
|
4350
|
+
strategyId: strategy.id,
|
|
4351
|
+
strategyName: strategy.shortName,
|
|
4352
|
+
type: "SIGNAL",
|
|
4353
|
+
message: `${signal.direction} signal detected | Confidence: ${(signal.confidence * 100).toFixed(1)}% | ${signal.reason}`,
|
|
4354
|
+
data: { signal },
|
|
4355
|
+
importance: "high"
|
|
4356
|
+
},
|
|
4357
|
+
delay
|
|
4358
|
+
});
|
|
4359
|
+
delay += rand3(1200, 2e3);
|
|
4360
|
+
const decision = this.makeTradeDecision(strategy, signal, state);
|
|
4361
|
+
if (decision.execute) {
|
|
4362
|
+
entries.push({
|
|
4363
|
+
entry: {
|
|
4364
|
+
strategyId: strategy.id,
|
|
4365
|
+
strategyName: strategy.shortName,
|
|
4366
|
+
type: "DECISION",
|
|
4367
|
+
message: `Execute ${signal.direction} | Size: ${decision.positionSize.toFixed(1)}% | Leverage: ${decision.leverage}x | Risk/Reward: 1:${decision.riskReward.toFixed(1)}`,
|
|
4368
|
+
data: {
|
|
4369
|
+
strategyName: strategy.name,
|
|
4370
|
+
strategyId: strategy.id,
|
|
4371
|
+
riskTolerance: strategy.riskTolerance,
|
|
4372
|
+
signalReason: signal.reason,
|
|
4373
|
+
confidence: signal.confidence
|
|
4374
|
+
},
|
|
4375
|
+
importance: "high"
|
|
4376
|
+
},
|
|
4377
|
+
delay
|
|
4378
|
+
});
|
|
4379
|
+
delay += rand3(1e3, 1800);
|
|
4380
|
+
const orderId = `ORD_${Date.now().toString(36).toUpperCase()}`;
|
|
4381
|
+
const orderPrice = signal.direction === "LONG" ? price * (1 - rand3(1e-4, 5e-4)) : price * (1 + rand3(1e-4, 5e-4));
|
|
4382
|
+
entries.push({
|
|
4383
|
+
entry: {
|
|
4384
|
+
strategyId: strategy.id,
|
|
4385
|
+
strategyName: strategy.shortName,
|
|
4386
|
+
type: "ORDER",
|
|
4387
|
+
message: `Submitting ${signal.direction} order | ${pair} @ $${formatPrice(orderPrice)} on ${chainLabel} | ID: ${orderId}`,
|
|
4388
|
+
data: {
|
|
4389
|
+
orderId,
|
|
4390
|
+
pair,
|
|
4391
|
+
side: signal.direction,
|
|
4392
|
+
price: orderPrice,
|
|
4393
|
+
leverage: decision.leverage,
|
|
4394
|
+
chain,
|
|
4395
|
+
chainLabel,
|
|
4396
|
+
strategyName: strategy.name,
|
|
4397
|
+
strategyContext,
|
|
4398
|
+
signalReason: signal.reason
|
|
4399
|
+
},
|
|
4400
|
+
importance: "high"
|
|
4401
|
+
},
|
|
4402
|
+
delay
|
|
4403
|
+
});
|
|
4404
|
+
delay += rand3(2e3, 4e3);
|
|
4405
|
+
const fillPrice = orderPrice * (1 + rand3(-3e-4, 3e-4));
|
|
4406
|
+
const slippage = Math.abs(fillPrice - orderPrice) / orderPrice * 100;
|
|
4407
|
+
entries.push({
|
|
4408
|
+
entry: {
|
|
4409
|
+
strategyId: strategy.id,
|
|
4410
|
+
strategyName: strategy.shortName,
|
|
4411
|
+
type: "FILLED",
|
|
4412
|
+
message: `Order FILLED | ${pair} ${signal.direction} @ $${formatPrice(fillPrice)} on ${chainLabel} | Slippage: ${slippage.toFixed(4)}% | ID: ${orderId}`,
|
|
4413
|
+
data: {
|
|
4414
|
+
orderId,
|
|
4415
|
+
fillPrice,
|
|
4416
|
+
slippage,
|
|
4417
|
+
chain,
|
|
4418
|
+
chainLabel,
|
|
4419
|
+
strategyName: strategy.name,
|
|
4420
|
+
executedBy: strategy.id
|
|
4421
|
+
},
|
|
4422
|
+
importance: "high"
|
|
4423
|
+
},
|
|
4424
|
+
delay
|
|
4425
|
+
});
|
|
4426
|
+
const position = {
|
|
4427
|
+
id: orderId,
|
|
4428
|
+
pair,
|
|
4429
|
+
side: signal.direction,
|
|
4430
|
+
entryPrice: fillPrice,
|
|
4431
|
+
currentPrice: price,
|
|
4432
|
+
size: decision.positionSize,
|
|
4433
|
+
leverage: decision.leverage,
|
|
4434
|
+
pnl: 0,
|
|
4435
|
+
pnlPercent: 0
|
|
4436
|
+
};
|
|
4437
|
+
state.openPositions = [...state.openPositions.slice(-2), position];
|
|
4438
|
+
state.totalTrades++;
|
|
4439
|
+
} else {
|
|
4440
|
+
entries.push({
|
|
4441
|
+
entry: {
|
|
4442
|
+
strategyId: strategy.id,
|
|
4443
|
+
strategyName: strategy.shortName,
|
|
4444
|
+
type: "DECISION",
|
|
4445
|
+
message: `SKIP - ${decision.reason}`,
|
|
4446
|
+
importance: "medium"
|
|
4447
|
+
},
|
|
4448
|
+
delay
|
|
4449
|
+
});
|
|
4450
|
+
}
|
|
4451
|
+
}
|
|
4452
|
+
if (state.openPositions.length > 0 && Math.random() < 0.5) {
|
|
4453
|
+
delay += rand3(1500, 2500);
|
|
4454
|
+
let totalPositionPnl = 0;
|
|
4455
|
+
const pnlParts = [];
|
|
4456
|
+
for (const pos of state.openPositions) {
|
|
4457
|
+
pos.currentPrice = this.simulatePrice(pos.pair);
|
|
4458
|
+
const priceDiff = pos.side === "LONG" ? (pos.currentPrice - pos.entryPrice) / pos.entryPrice : (pos.entryPrice - pos.currentPrice) / pos.entryPrice;
|
|
4459
|
+
pos.pnlPercent = priceDiff * pos.leverage * 100;
|
|
4460
|
+
pos.pnl = priceDiff * pos.leverage * pos.size;
|
|
4461
|
+
totalPositionPnl += pos.pnl;
|
|
4462
|
+
pnlParts.push(`${pos.pair} ${pos.side}: ${pos.pnlPercent >= 0 ? "+" : ""}${pos.pnlPercent.toFixed(2)}%`);
|
|
4463
|
+
}
|
|
4464
|
+
state.totalPnl += totalPositionPnl * rand3(0.01, 0.05);
|
|
4465
|
+
if (state.openPositions.length > 1 && Math.random() < 0.3) {
|
|
4466
|
+
const closed = state.openPositions.shift();
|
|
4467
|
+
const finalPnl = closed.pnlPercent;
|
|
4468
|
+
if (finalPnl > 0) {
|
|
4469
|
+
state.winRate = state.winRate * 0.95 + 0.05;
|
|
4470
|
+
} else {
|
|
4471
|
+
state.winRate = state.winRate * 0.95;
|
|
4472
|
+
}
|
|
4473
|
+
state.winRate = clamp(state.winRate, 0.35, 0.75);
|
|
4474
|
+
pnlParts.push(`CLOSED ${closed.pair}: ${finalPnl >= 0 ? "+" : ""}${finalPnl.toFixed(2)}%`);
|
|
4475
|
+
}
|
|
4476
|
+
entries.push({
|
|
4477
|
+
entry: {
|
|
4478
|
+
strategyId: strategy.id,
|
|
4479
|
+
strategyName: strategy.shortName,
|
|
4480
|
+
type: "PNL",
|
|
4481
|
+
message: pnlParts.join(" | "),
|
|
4482
|
+
data: { totalPnl: state.totalPnl, positions: state.openPositions.length },
|
|
4483
|
+
importance: "medium"
|
|
4484
|
+
},
|
|
4485
|
+
delay
|
|
4486
|
+
});
|
|
4487
|
+
}
|
|
4488
|
+
if (Math.random() < 0.2) {
|
|
4489
|
+
delay += rand3(1e3, 2e3);
|
|
4490
|
+
const exposure = state.openPositions.reduce((sum, p) => sum + p.size * p.leverage, 0);
|
|
4491
|
+
const maxDrawdown = rand3(2, 12);
|
|
4492
|
+
entries.push({
|
|
4493
|
+
entry: {
|
|
4494
|
+
strategyId: strategy.id,
|
|
4495
|
+
strategyName: strategy.shortName,
|
|
4496
|
+
type: "RISK",
|
|
4497
|
+
message: `Portfolio exposure: ${exposure.toFixed(1)}% | Max drawdown: ${maxDrawdown.toFixed(1)}% | Open positions: ${state.openPositions.length} | Win rate: ${(state.winRate * 100).toFixed(1)}%`,
|
|
4498
|
+
importance: exposure > 80 ? "high" : "low"
|
|
4499
|
+
},
|
|
4500
|
+
delay
|
|
4501
|
+
});
|
|
4502
|
+
}
|
|
4503
|
+
for (const { entry, delay: d } of entries) {
|
|
4504
|
+
setTimeout(() => {
|
|
4505
|
+
if (this.running) {
|
|
4506
|
+
this.emit({
|
|
4507
|
+
...entry,
|
|
4508
|
+
id: genId3(),
|
|
4509
|
+
timestamp: Date.now()
|
|
4510
|
+
});
|
|
4511
|
+
}
|
|
4512
|
+
}, d);
|
|
4513
|
+
}
|
|
4514
|
+
}
|
|
4515
|
+
simulatePrice(pair) {
|
|
4516
|
+
const current = this.priceState.get(pair) || PAIR_PRICES[pair] || 5e4;
|
|
4517
|
+
const volatility = pair.includes("DOGE") ? 5e-3 : pair.includes("BTC") ? 2e-3 : 3e-3;
|
|
4518
|
+
const drift = rand3(-volatility, volatility);
|
|
4519
|
+
const newPrice = current * (1 + drift);
|
|
4520
|
+
this.priceState.set(pair, newPrice);
|
|
4521
|
+
return newPrice;
|
|
4522
|
+
}
|
|
4523
|
+
generateIndicators(strategy, price) {
|
|
4524
|
+
const prev = this.indicatorState.get(strategy.id);
|
|
4525
|
+
const prevRsi = prev?.rsi ?? strategy.rsiBias;
|
|
4526
|
+
const rsiMean = strategy.rsiBias;
|
|
4527
|
+
const rsiDrift = rand3(-8, 8);
|
|
4528
|
+
const rsiReversion = (rsiMean - prevRsi) * 0.15;
|
|
4529
|
+
const rsi = clamp(prevRsi + rsiDrift + rsiReversion, 8, 95);
|
|
4530
|
+
const macdBias = rsi > 65 ? 0.3 : rsi < 35 ? -0.3 : 0;
|
|
4531
|
+
const prevHist = prev?.macd.histogram ?? 0;
|
|
4532
|
+
const histogram = clamp(prevHist * 0.7 + rand3(-0.5, 0.5) + macdBias, -2, 2);
|
|
4533
|
+
const macdValue = histogram * rand3(0.8, 1.5);
|
|
4534
|
+
const macdSignal = macdValue - histogram;
|
|
4535
|
+
const prevShort = prev?.ema.short ?? price;
|
|
4536
|
+
const prevLong = prev?.ema.long ?? price;
|
|
4537
|
+
const emaShort = prevShort * 0.9 + price * 0.1;
|
|
4538
|
+
const emaLong = prevLong * 0.95 + price * 0.05;
|
|
4539
|
+
let crossover = "none";
|
|
4540
|
+
if (prevShort <= prevLong && emaShort > emaLong) crossover = "golden";
|
|
4541
|
+
else if (prevShort >= prevLong && emaShort < emaLong) crossover = "death";
|
|
4542
|
+
const bbMiddle = price;
|
|
4543
|
+
const bbWidth = price * rand3(0.01, 0.04);
|
|
4544
|
+
const bbUpper = bbMiddle + bbWidth;
|
|
4545
|
+
const bbLower = bbMiddle - bbWidth;
|
|
4546
|
+
const bbPosition = (price - bbLower) / (bbUpper - bbLower) * 100;
|
|
4547
|
+
const volRatio = rand3(0.3, 2.5);
|
|
4548
|
+
const volCurrent = rand3(1e5, 5e6);
|
|
4549
|
+
return {
|
|
4550
|
+
rsi,
|
|
4551
|
+
macd: { value: macdValue, signal: macdSignal, histogram },
|
|
4552
|
+
ema: { short: emaShort, long: emaLong, crossover },
|
|
4553
|
+
bollinger: { upper: bbUpper, middle: bbMiddle, lower: bbLower, width: bbWidth / price, position: bbPosition },
|
|
4554
|
+
volume: { current: volCurrent, average: volCurrent / volRatio, ratio: volRatio }
|
|
4555
|
+
};
|
|
4556
|
+
}
|
|
4557
|
+
generateThinkingProcess(strategy, pair, price) {
|
|
4558
|
+
const thoughts = [];
|
|
4559
|
+
const pairBase = pair.split("/")[0];
|
|
4560
|
+
const thinkingTemplates = [
|
|
4561
|
+
`Analyzing ${pairBase} market structure...`,
|
|
4562
|
+
`Checking ${strategy.primaryIndicators.join(", ")} confluence...`,
|
|
4563
|
+
`Evaluating risk parameters for ${strategy.riskTolerance} tolerance...`,
|
|
4564
|
+
`Scanning order book depth at $${formatPrice(price)}...`,
|
|
4565
|
+
`Cross-referencing with historical patterns...`,
|
|
4566
|
+
`Calculating optimal entry zone...`,
|
|
4567
|
+
`Assessing market sentiment indicators...`,
|
|
4568
|
+
`Monitoring whale activity on ${pairBase}...`,
|
|
4569
|
+
`Comparing momentum across timeframes...`,
|
|
4570
|
+
`Validating support/resistance levels...`
|
|
4571
|
+
];
|
|
4572
|
+
const numThoughts = randInt3(1, 3);
|
|
4573
|
+
const shuffled = [...thinkingTemplates].sort(() => Math.random() - 0.5);
|
|
4574
|
+
for (let i = 0; i < numThoughts; i++) {
|
|
4575
|
+
thoughts.push(shuffled[i]);
|
|
4576
|
+
}
|
|
4577
|
+
return thoughts;
|
|
4578
|
+
}
|
|
4579
|
+
generateStrategyContext(strategy, signal, indicators, pair) {
|
|
4580
|
+
const contexts = [];
|
|
4581
|
+
contexts.push(`[${strategy.name}]`);
|
|
4582
|
+
const riskLevel = strategy.riskTolerance === "high" ? "aggressive" : strategy.riskTolerance === "low" ? "conservative" : "balanced";
|
|
4583
|
+
contexts.push(`Risk: ${riskLevel}`);
|
|
4584
|
+
if (indicators.rsi < 35 || indicators.rsi > 65) {
|
|
4585
|
+
contexts.push(`RSI ${indicators.rsi < 35 ? "oversold" : "overbought"} (${indicators.rsi.toFixed(1)})`);
|
|
4586
|
+
}
|
|
4587
|
+
if (indicators.ema.crossover !== "none") {
|
|
4588
|
+
contexts.push(`EMA ${indicators.ema.crossover} cross`);
|
|
4589
|
+
}
|
|
4590
|
+
if (Math.abs(indicators.macd.histogram) > 0.3) {
|
|
4591
|
+
contexts.push(`MACD ${indicators.macd.histogram > 0 ? "bullish" : "bearish"} momentum`);
|
|
4592
|
+
}
|
|
4593
|
+
const confLevel = signal.confidence > 0.7 ? "HIGH" : signal.confidence > 0.5 ? "MEDIUM" : "LOW";
|
|
4594
|
+
contexts.push(`Confidence: ${confLevel}`);
|
|
4595
|
+
return contexts.join(" | ");
|
|
4596
|
+
}
|
|
4597
|
+
generateAnalysis(strategy, indicators, pair) {
|
|
4598
|
+
const analyses = [];
|
|
4599
|
+
if (indicators.rsi > 70) {
|
|
4600
|
+
analyses.push(`RSI at ${indicators.rsi.toFixed(1)} - overbought territory, watching for reversal`);
|
|
4601
|
+
} else if (indicators.rsi < 30) {
|
|
4602
|
+
analyses.push(`RSI at ${indicators.rsi.toFixed(1)} - oversold, potential bounce setup`);
|
|
4603
|
+
} else if (indicators.rsi > 55) {
|
|
4604
|
+
analyses.push(`RSI trending bullish at ${indicators.rsi.toFixed(1)}`);
|
|
4605
|
+
} else {
|
|
4606
|
+
analyses.push(`RSI neutral at ${indicators.rsi.toFixed(1)}, no clear direction`);
|
|
4607
|
+
}
|
|
4608
|
+
if (indicators.macd.histogram > 0.5) {
|
|
4609
|
+
analyses.push("MACD histogram expanding positive - momentum building");
|
|
4610
|
+
} else if (indicators.macd.histogram < -0.5) {
|
|
4611
|
+
analyses.push("MACD histogram expanding negative - bearish pressure");
|
|
4612
|
+
}
|
|
4613
|
+
if (indicators.ema.crossover === "golden") {
|
|
4614
|
+
analyses.push("EMA golden cross detected - strong bullish signal");
|
|
4615
|
+
} else if (indicators.ema.crossover === "death") {
|
|
4616
|
+
analyses.push("EMA death cross detected - bearish warning");
|
|
4617
|
+
}
|
|
4618
|
+
if (indicators.bollinger.position > 90) {
|
|
4619
|
+
analyses.push(`Price near upper Bollinger band (${indicators.bollinger.position.toFixed(0)}%) - potential resistance`);
|
|
4620
|
+
} else if (indicators.bollinger.position < 10) {
|
|
4621
|
+
analyses.push(`Price near lower Bollinger band (${indicators.bollinger.position.toFixed(0)}%) - potential support`);
|
|
4622
|
+
}
|
|
4623
|
+
if (indicators.volume.ratio > 1.8) {
|
|
4624
|
+
analyses.push(`Volume spike ${indicators.volume.ratio.toFixed(1)}x average - high activity`);
|
|
4625
|
+
}
|
|
4626
|
+
return analyses.length > 0 ? analyses.join(" | ") : `${pair} consolidating - waiting for clearer setup`;
|
|
4627
|
+
}
|
|
4628
|
+
evaluateSignal(strategy, indicators) {
|
|
4629
|
+
let bullScore = 0;
|
|
4630
|
+
let bearScore = 0;
|
|
4631
|
+
const reasons = [];
|
|
4632
|
+
if (indicators.rsi < 30) {
|
|
4633
|
+
bullScore += 2;
|
|
4634
|
+
reasons.push("RSI oversold");
|
|
4635
|
+
} else if (indicators.rsi < 40) {
|
|
4636
|
+
bullScore += 1;
|
|
4637
|
+
reasons.push("RSI low");
|
|
4638
|
+
} else if (indicators.rsi > 70) {
|
|
4639
|
+
bearScore += 2;
|
|
4640
|
+
reasons.push("RSI overbought");
|
|
4641
|
+
} else if (indicators.rsi > 60) {
|
|
4642
|
+
bearScore += 1;
|
|
4643
|
+
reasons.push("RSI high");
|
|
4644
|
+
}
|
|
4645
|
+
if (indicators.macd.histogram > 0.3) {
|
|
4646
|
+
bullScore += 1.5;
|
|
4647
|
+
reasons.push("MACD bullish");
|
|
4648
|
+
} else if (indicators.macd.histogram < -0.3) {
|
|
4649
|
+
bearScore += 1.5;
|
|
4650
|
+
reasons.push("MACD bearish");
|
|
4651
|
+
}
|
|
4652
|
+
if (indicators.ema.crossover === "golden") {
|
|
4653
|
+
bullScore += 2.5;
|
|
4654
|
+
reasons.push("Golden cross");
|
|
4655
|
+
} else if (indicators.ema.crossover === "death") {
|
|
4656
|
+
bearScore += 2.5;
|
|
4657
|
+
reasons.push("Death cross");
|
|
4658
|
+
} else if (indicators.ema.short > indicators.ema.long) {
|
|
4659
|
+
bullScore += 0.5;
|
|
4660
|
+
} else {
|
|
4661
|
+
bearScore += 0.5;
|
|
4662
|
+
}
|
|
4663
|
+
if (indicators.bollinger.position < 15) {
|
|
4664
|
+
bullScore += 1;
|
|
4665
|
+
reasons.push("BB support");
|
|
4666
|
+
} else if (indicators.bollinger.position > 85) {
|
|
4667
|
+
bearScore += 1;
|
|
4668
|
+
reasons.push("BB resistance");
|
|
4669
|
+
}
|
|
4670
|
+
if (indicators.volume.ratio > 1.5) {
|
|
4671
|
+
if (bullScore > bearScore) bullScore += 1;
|
|
4672
|
+
else bearScore += 1;
|
|
4673
|
+
reasons.push("Volume confirms");
|
|
4674
|
+
}
|
|
4675
|
+
const netScore = bullScore - bearScore;
|
|
4676
|
+
const confidence = Math.min(Math.abs(netScore) / 6, 0.95);
|
|
4677
|
+
const threshold = strategy.riskTolerance === "high" ? 1.5 : strategy.riskTolerance === "medium" ? 2 : 2.5;
|
|
4678
|
+
if (Math.random() > strategy.tradeFrequency) {
|
|
4679
|
+
return { direction: "HOLD", confidence: 0, reason: "Cycle skip" };
|
|
4680
|
+
}
|
|
4681
|
+
if (netScore > threshold) {
|
|
4682
|
+
return { direction: "LONG", confidence, reason: reasons.slice(0, 3).join(", ") };
|
|
4683
|
+
} else if (netScore < -threshold) {
|
|
4684
|
+
return { direction: "SHORT", confidence, reason: reasons.slice(0, 3).join(", ") };
|
|
4685
|
+
}
|
|
4686
|
+
return { direction: "HOLD", confidence: 0, reason: "No clear signal" };
|
|
4687
|
+
}
|
|
4688
|
+
makeTradeDecision(strategy, signal, state) {
|
|
4689
|
+
if (state.openPositions.length >= 3) {
|
|
4690
|
+
return { execute: false, positionSize: 0, leverage: 0, riskReward: 0, reason: "Max positions reached (3)" };
|
|
4691
|
+
}
|
|
4692
|
+
const minConfidence = strategy.riskTolerance === "high" ? 0.3 : strategy.riskTolerance === "medium" ? 0.45 : 0.6;
|
|
4693
|
+
if (signal.confidence < minConfidence) {
|
|
4694
|
+
return { execute: false, positionSize: 0, leverage: 0, riskReward: 0, reason: `Confidence too low (${(signal.confidence * 100).toFixed(0)}% < ${(minConfidence * 100).toFixed(0)}%)` };
|
|
4695
|
+
}
|
|
4696
|
+
const positionSize = rand3(strategy.positionSizeMin, strategy.positionSizeMax);
|
|
4697
|
+
const leverage = randInt3(strategy.leverageMin, strategy.leverageMax);
|
|
4698
|
+
const riskReward = rand3(1.2, 3.5);
|
|
4699
|
+
return { execute: true, positionSize, leverage, riskReward, reason: "" };
|
|
4700
|
+
}
|
|
4701
|
+
};
|
|
4702
|
+
var botSimulationEngine = new BotSimulationEngine();
|
|
2784
4703
|
|
|
2785
4704
|
// src/react-native.ts
|
|
2786
4705
|
function createCachedEngineClient(storage, options) {
|
|
@@ -2963,6 +4882,6 @@ function getExplorerUrl(chainId, hash, type = "tx") {
|
|
|
2963
4882
|
return `${baseUrl}/${type}/${hash}`;
|
|
2964
4883
|
}
|
|
2965
4884
|
|
|
2966
|
-
export { CHAIN_CONFIG, CHAIN_CONFIGS, COINGECKO_IDS, DEFAULT_SHARE_RATES, OneChainSelector, OneCycleSelector, OneEngineClient, OnePairSelector, OneSDKError, OneTierSelector, PAIR_ICONS, PriceService, TOKEN_NAMES, capitalize, checksumAddress, createCachedEngineClient, createDeepLinkHandler, createOneEngineClient, formatCryptoAmount, formatDate, formatDateTime, formatNumber, formatPercent, formatRelativeTime, formatTokenAmount, formatUSD, generateShareContent, getConfig, getExplorerUrl, initOneSDK, isOneSDKError, isValidAddress, isValidEmail, isValidPhone, omit, parseQRCode, pick, priceService, retry, shortenAddress, sleep, slugify, truncate };
|
|
4885
|
+
export { AGENT_STATUS_COLORS, AI_LOG_COLORS, CHAIN_CONFIG, CHAIN_CONFIGS, COINGECKO_IDS, DEFAULT_CONSOLE_METRICS, DEFAULT_CONSOLE_OPTIONS, DEFAULT_RISK_STATUS, DEFAULT_SHARE_RATES, FOREX_AGENT, FOREX_CAPITAL_SPLIT, FOREX_CURRENCY_PAIRS, FOREX_CYCLE_OPTIONS, FOREX_LOG_COLORS, FOREX_POOL_DEFAULTS, ForexPoolDataGenerator, ORDER_STATUS_CONFIG, OneChainSelector, OneCycleSelector, OneEngineClient, OneForexCapitalSplit, OneForexConsoleView, OneForexPairSelector, OneForexPoolCard, OneForexTradeHistory, OnePairSelector, OneSDKError, OneTierSelector, PAIR_ICONS, PENALTY_TIERS, PriceService, RISK_LEVELS, RISK_LEVEL_COLORS, STRATEGY_CATEGORIES, TOKEN_NAMES, TRADING_STATUS_COLORS, botSimulationEngine, calculateEarlyWithdrawalPenalty, calculateForexNetProfit, calculateRiskLevel, capitalize, checksumAddress, clearForexAccessToken, computePoolAllocations, createCachedEngineClient, createDeepLinkHandler, createOneEngineClient, estimateForexProfit, forexSimulationEngine, formatCryptoAmount, formatDate, formatDateTime, formatNumber, formatPercent, formatPnl, formatRelativeTime, formatTokenAmount, formatUSD, generateShareContent, getConfig, getExplorerUrl, initOneSDK, isOneSDKError, isValidAddress, isValidEmail, isValidPhone, omit, parseQRCode, pick, priceService, retry, setForexAccessToken, setForexEngineUrl, shortenAddress, sleep, slugify, truncate, useForexInvestments, useForexPoolData, useForexPools, useForexSimulation, useForexTrading };
|
|
2967
4886
|
//# sourceMappingURL=react-native.mjs.map
|
|
2968
4887
|
//# sourceMappingURL=react-native.mjs.map
|