@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.
Files changed (106) hide show
  1. package/README.md +339 -0
  2. package/dist/ForexPoolDataGenerator--__twRwl.d.mts +76 -0
  3. package/dist/ForexPoolDataGenerator-eUgwsU_B.d.ts +76 -0
  4. package/dist/OneForexTradeHistory-TlKxjbFF.d.ts +250 -0
  5. package/dist/OneForexTradeHistory-iDySMcw0.d.mts +250 -0
  6. package/dist/components/index.d.mts +539 -0
  7. package/dist/components/index.d.ts +539 -0
  8. package/dist/components/index.js +7295 -0
  9. package/dist/components/index.js.map +1 -0
  10. package/dist/components/index.mjs +7243 -0
  11. package/dist/components/index.mjs.map +1 -0
  12. package/dist/config/index.d.mts +1 -0
  13. package/dist/config/index.d.ts +1 -0
  14. package/dist/console-BfTMA7ah.d.mts +504 -0
  15. package/dist/console-BfTMA7ah.d.ts +504 -0
  16. package/dist/hooks/index.d.mts +323 -1
  17. package/dist/hooks/index.d.ts +323 -1
  18. package/dist/hooks/index.js +3223 -0
  19. package/dist/hooks/index.js.map +1 -1
  20. package/dist/hooks/index.mjs +3204 -1
  21. package/dist/hooks/index.mjs.map +1 -1
  22. package/dist/index.d.mts +18 -352
  23. package/dist/index.d.ts +18 -352
  24. package/dist/index.js +8646 -574
  25. package/dist/index.js.map +1 -1
  26. package/dist/index.mjs +8449 -432
  27. package/dist/index.mjs.map +1 -1
  28. package/dist/providers/index.d.mts +31 -31
  29. package/dist/providers/index.d.ts +31 -31
  30. package/dist/providers/index.js +140 -153
  31. package/dist/providers/index.js.map +1 -1
  32. package/dist/providers/index.mjs +100 -109
  33. package/dist/providers/index.mjs.map +1 -1
  34. package/dist/react-native.d.mts +8 -144
  35. package/dist/react-native.d.ts +8 -144
  36. package/dist/react-native.js +2640 -689
  37. package/dist/react-native.js.map +1 -1
  38. package/dist/react-native.mjs +2610 -691
  39. package/dist/react-native.mjs.map +1 -1
  40. package/dist/services/index.d.mts +85 -4
  41. package/dist/services/index.d.ts +85 -4
  42. package/dist/services/index.js +1621 -0
  43. package/dist/services/index.js.map +1 -1
  44. package/dist/services/index.mjs +1619 -1
  45. package/dist/services/index.mjs.map +1 -1
  46. package/dist/types/index.d.mts +203 -1
  47. package/dist/types/index.d.ts +203 -1
  48. package/dist/types/index.js +275 -0
  49. package/dist/types/index.js.map +1 -1
  50. package/dist/types/index.mjs +251 -0
  51. package/dist/types/index.mjs.map +1 -1
  52. package/dist/useForexTrading-BleeSor8.d.mts +80 -0
  53. package/dist/useForexTrading-ZgW_G40Q.d.ts +80 -0
  54. package/package.json +9 -2
  55. package/src/components/OneConnectButton.tsx +24 -1
  56. package/src/components/OneNFTGallery.tsx +13 -7
  57. package/src/components/OneOfframpWidget.tsx +4 -3
  58. package/src/components/OnePayWidget.tsx +10 -1
  59. package/src/components/OneSendWidget.tsx +3 -3
  60. package/src/components/OneSwapWidget.tsx +4 -4
  61. package/src/components/OneTransactionButton.tsx +28 -3
  62. package/src/components/OneWalletBalance.tsx +1 -1
  63. package/src/components/ai/OneChainSelector.tsx +63 -336
  64. package/src/components/ai/OneForexCapitalSplit.tsx +112 -0
  65. package/src/components/ai/OneForexConsoleView.tsx +90 -0
  66. package/src/components/ai/OneForexPairSelector.tsx +101 -0
  67. package/src/components/ai/OneForexPoolCard.tsx +105 -0
  68. package/src/components/ai/OneForexTradeHistory.tsx +107 -0
  69. package/src/components/ai/OnePairSelector.tsx +77 -434
  70. package/src/components/ai/console/OneAIQuantConsole.tsx +423 -0
  71. package/src/components/ai/console/OneAgentCard.tsx +383 -0
  72. package/src/components/ai/console/OneAgentConsole.tsx +469 -0
  73. package/src/components/ai/console/OneDecisionTimeline.tsx +433 -0
  74. package/src/components/ai/console/OneMetricsDashboard.tsx +493 -0
  75. package/src/components/ai/console/OnePositionCard.tsx +406 -0
  76. package/src/components/ai/console/OnePositionDetail.tsx +600 -0
  77. package/src/components/ai/console/OneRiskIndicator.tsx +464 -0
  78. package/src/components/ai/console/OneTradingConsole.tsx +660 -0
  79. package/src/components/ai/console/index.ts +17 -0
  80. package/src/components/ai/index.ts +10 -0
  81. package/src/hooks/index.ts +46 -0
  82. package/src/hooks/useAIDecisions.ts +280 -0
  83. package/src/hooks/useAIPositions.ts +349 -0
  84. package/src/hooks/useAIQuantConsole.ts +283 -0
  85. package/src/hooks/useAIRiskStatus.ts +276 -0
  86. package/src/hooks/useAITrading.ts +190 -0
  87. package/src/hooks/useBotSimulation.ts +201 -0
  88. package/src/hooks/useForexTrading.ts +430 -0
  89. package/src/hooks/useTradingConsole.ts +243 -0
  90. package/src/index.ts +123 -5
  91. package/src/providers/OneProvider.tsx +181 -5
  92. package/src/providers/index.ts +22 -8
  93. package/src/react-native.ts +41 -0
  94. package/src/services/forex/BotSimulationEngine.ts +968 -0
  95. package/src/services/forex/ForexPoolDataGenerator.ts +542 -0
  96. package/src/services/forex/ForexSimulationEngine.ts +482 -0
  97. package/src/services/forex/index.ts +21 -0
  98. package/src/services/index.ts +16 -0
  99. package/src/types/aiTrading.ts +151 -0
  100. package/src/types/console.ts +380 -0
  101. package/src/types/forex.ts +282 -0
  102. package/src/types/index.ts +106 -0
  103. package/dist/price-CgqXPnT3.d.ts +0 -13
  104. package/dist/price-ClbLHHjv.d.mts +0 -13
  105. package/dist/supabase-BT0c7q9e.d.mts +0 -82
  106. package/dist/supabase-BT0c7q9e.d.ts +0 -82
@@ -2,6 +2,492 @@
2
2
 
3
3
  var supabaseJs = require('@supabase/supabase-js');
4
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_CURRENCY_PAIRS, FOREX_POOL_DEFAULTS, FOREX_AGENT;
28
+ var init_forex = __esm({
29
+ "src/types/forex.ts"() {
30
+ FOREX_CURRENCY_PAIRS = [
31
+ { 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 },
32
+ { 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 },
33
+ { 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 },
34
+ { 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 },
35
+ { 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 },
36
+ { 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 }
37
+ ];
38
+ FOREX_POOL_DEFAULTS = [
39
+ { 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() },
40
+ { 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() },
41
+ { 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() }
42
+ ];
43
+ FOREX_AGENT = {
44
+ id: "stablefx-01",
45
+ nameKey: "forex.agent_name",
46
+ descriptionKey: "forex.agent_description",
47
+ icon: "\u{1F4B1}",
48
+ color: "#0EA5E9",
49
+ supportedPairs: FOREX_CURRENCY_PAIRS.map((p) => p.id),
50
+ dailyRoiMin: 2e-3,
51
+ dailyRoiMax: 5e-3,
52
+ totalManaged: 25e6,
53
+ totalUsers: 3847,
54
+ winRate: 72.5
55
+ };
56
+ }
57
+ });
58
+
59
+ // src/services/forex/ForexPoolDataGenerator.ts
60
+ var ForexPoolDataGenerator_exports = {};
61
+ __export(ForexPoolDataGenerator_exports, {
62
+ ForexPoolDataGenerator: () => exports.ForexPoolDataGenerator
63
+ });
64
+ function rand(min, max) {
65
+ return min + Math.random() * (max - min);
66
+ }
67
+ function randInt(min, max) {
68
+ return Math.floor(rand(min, max + 1));
69
+ }
70
+ function pick(arr) {
71
+ return arr[Math.floor(Math.random() * arr.length)];
72
+ }
73
+ function genTxHash() {
74
+ const chars = "0123456789abcdef";
75
+ let hash = "0x";
76
+ for (let i = 0; i < 64; i++) hash += chars[Math.floor(Math.random() * 16)];
77
+ return hash;
78
+ }
79
+ function formatDate(d) {
80
+ return d.toISOString().split("T")[0];
81
+ }
82
+ function genId(prefix) {
83
+ return `${prefix}_${Date.now().toString(36)}_${(++_idCounter).toString(36)}`;
84
+ }
85
+ var _idCounter, POOL_PARAMS, ForexPoolDataGeneratorClass, _instance; exports.ForexPoolDataGenerator = void 0;
86
+ var init_ForexPoolDataGenerator = __esm({
87
+ "src/services/forex/ForexPoolDataGenerator.ts"() {
88
+ init_forex();
89
+ _idCounter = 0;
90
+ POOL_PARAMS = {
91
+ clearing: {
92
+ meanDailyPnlPct: 35e-5,
93
+ stddevPnlPct: 15e-5,
94
+ utilizationMin: 0.7,
95
+ utilizationMax: 0.85,
96
+ depositsPerDay: [15, 25],
97
+ withdrawalsPerDay: [8, 12],
98
+ profitDistPerDay: 5,
99
+ avgDepositSize: 25e3,
100
+ avgWithdrawalSize: 18e3
101
+ },
102
+ hedging: {
103
+ meanDailyPnlPct: 22e-5,
104
+ stddevPnlPct: 2e-4,
105
+ utilizationMin: 0.55,
106
+ utilizationMax: 0.75,
107
+ depositsPerDay: [8, 15],
108
+ withdrawalsPerDay: [5, 8],
109
+ profitDistPerDay: 3,
110
+ avgDepositSize: 18e3,
111
+ avgWithdrawalSize: 12e3
112
+ },
113
+ insurance: {
114
+ meanDailyPnlPct: 13e-5,
115
+ stddevPnlPct: 8e-5,
116
+ utilizationMin: 0.3,
117
+ utilizationMax: 0.5,
118
+ depositsPerDay: [5, 10],
119
+ withdrawalsPerDay: [3, 5],
120
+ profitDistPerDay: 2,
121
+ avgDepositSize: 12e3,
122
+ avgWithdrawalSize: 8e3
123
+ }
124
+ };
125
+ ForexPoolDataGeneratorClass = class {
126
+ constructor() {
127
+ this.snapshotCache = null;
128
+ this.transactionCache = null;
129
+ this.baseBlockNumber = 195e5;
130
+ }
131
+ // ── Public API ─────────────────────────────────────────────────────────
132
+ generateAllSnapshots() {
133
+ if (this.snapshotCache) return this.snapshotCache;
134
+ const result = {
135
+ clearing: [],
136
+ hedging: [],
137
+ insurance: []
138
+ };
139
+ for (const pool of FOREX_POOL_DEFAULTS) {
140
+ result[pool.id] = this.generatePoolSnapshots(pool.id, pool.totalSize);
141
+ }
142
+ this.snapshotCache = result;
143
+ return result;
144
+ }
145
+ generateAllTransactions() {
146
+ if (this.transactionCache) return this.transactionCache;
147
+ const allTx = [];
148
+ for (const pool of FOREX_POOL_DEFAULTS) {
149
+ const snapshots = this.snapshotCache?.[pool.id] || this.generatePoolSnapshots(pool.id, pool.totalSize);
150
+ const txs = this.generatePoolTransactions(pool.id, snapshots);
151
+ allTx.push(...txs);
152
+ }
153
+ const now = /* @__PURE__ */ new Date();
154
+ for (let i = 0; i < 60; i++) {
155
+ const day = new Date(now);
156
+ day.setDate(day.getDate() - (60 - i));
157
+ const dayOfWeek = day.getDay();
158
+ if (dayOfWeek === 2 || dayOfWeek === 4 || dayOfWeek === 5 && Math.random() < 0.4) {
159
+ const fromPool = pick(["clearing", "hedging", "insurance"]);
160
+ const toOptions = ["clearing", "hedging", "insurance"].filter((p) => p !== fromPool);
161
+ const toPool = pick(toOptions);
162
+ const amount = rand(5e4, 2e5);
163
+ const ts = day.getTime() + randInt(10, 18) * 36e5;
164
+ allTx.push({
165
+ id: genId("ipt"),
166
+ poolId: fromPool,
167
+ type: "inter_pool_transfer",
168
+ amount: -amount,
169
+ balanceBefore: 0,
170
+ balanceAfter: 0,
171
+ txHash: genTxHash(),
172
+ blockNumber: this.baseBlockNumber + i * 7200 + randInt(0, 100),
173
+ timestamp: ts,
174
+ description: `Transfer to ${toPool} pool`
175
+ });
176
+ allTx.push({
177
+ id: genId("ipt"),
178
+ poolId: toPool,
179
+ type: "inter_pool_transfer",
180
+ amount,
181
+ balanceBefore: 0,
182
+ balanceAfter: 0,
183
+ txHash: genTxHash(),
184
+ blockNumber: this.baseBlockNumber + i * 7200 + randInt(100, 200),
185
+ timestamp: ts + 5e3,
186
+ description: `Transfer from ${fromPool} pool`
187
+ });
188
+ }
189
+ if (dayOfWeek === 3 && Math.random() < 0.85) {
190
+ const pool = pick(FOREX_POOL_DEFAULTS);
191
+ const rebalanceAmt = rand(2e4, 1e5);
192
+ const ts = day.getTime() + randInt(2, 6) * 36e5;
193
+ allTx.push({
194
+ id: genId("rrb"),
195
+ poolId: pool.id,
196
+ type: "reserve_rebalance",
197
+ amount: Math.random() < 0.5 ? rebalanceAmt : -rebalanceAmt,
198
+ balanceBefore: 0,
199
+ balanceAfter: 0,
200
+ txHash: genTxHash(),
201
+ blockNumber: this.baseBlockNumber + i * 7200 + randInt(200, 300),
202
+ timestamp: ts,
203
+ description: "Automated reserve rebalance"
204
+ });
205
+ }
206
+ }
207
+ allTx.sort((a, b) => a.timestamp - b.timestamp);
208
+ const runningBalance = {
209
+ clearing: FOREX_POOL_DEFAULTS[0].totalSize * 0.85,
210
+ hedging: FOREX_POOL_DEFAULTS[1].totalSize * 0.82,
211
+ insurance: FOREX_POOL_DEFAULTS[2].totalSize * 0.88
212
+ };
213
+ for (const tx of allTx) {
214
+ tx.balanceBefore = runningBalance[tx.poolId];
215
+ runningBalance[tx.poolId] += tx.amount;
216
+ tx.balanceAfter = runningBalance[tx.poolId];
217
+ }
218
+ this.transactionCache = allTx;
219
+ return allTx;
220
+ }
221
+ generateTradeHistory(investmentAmount, startDate, selectedPairs) {
222
+ const trades = [];
223
+ const start = new Date(startDate);
224
+ const now = /* @__PURE__ */ new Date();
225
+ const dayCount = Math.min(60, Math.ceil((now.getTime() - start.getTime()) / 864e5));
226
+ let cumulativePnl = 0;
227
+ let blockNum = this.baseBlockNumber + randInt(0, 5e3);
228
+ for (let d = 0; d < dayCount; d++) {
229
+ const day = new Date(start);
230
+ day.setDate(day.getDate() + d);
231
+ const dayOfWeek = day.getDay();
232
+ const baseCount = dayOfWeek === 0 || dayOfWeek === 6 ? randInt(1, 2) : randInt(3, 8);
233
+ for (let t = 0; t < baseCount; t++) {
234
+ const pair = FOREX_CURRENCY_PAIRS.find((p) => p.id === pick(selectedPairs)) || pick(FOREX_CURRENCY_PAIRS);
235
+ const side = Math.random() > 0.5 ? "BUY" : "SELL";
236
+ const lots = parseFloat(rand(0.1, 2.5).toFixed(2));
237
+ const rfqPrice = pair.basePrice * (1 + rand(-3e-3, 3e-3));
238
+ const quoteSpread = rand(0.5, 2) * pair.pipSize;
239
+ const quotePrice = side === "BUY" ? rfqPrice + quoteSpread : rfqPrice - quoteSpread;
240
+ const matched = Math.random() < 0.85;
241
+ if (!matched) continue;
242
+ const matchPrice = quotePrice * (1 + rand(-5e-5, 5e-5));
243
+ const settlePrice = matchPrice * (1 + rand(-2e-5, 2e-5));
244
+ const pips = (settlePrice - rfqPrice) / pair.pipSize * (side === "BUY" ? 1 : -1);
245
+ const pnl = pips * pair.pipSize * lots * 1e5;
246
+ const isWin = Math.random() < FOREX_AGENT.winRate / 100;
247
+ const finalPnl = isWin ? Math.abs(pnl) : -Math.abs(pnl) * rand(0.3, 0.8);
248
+ cumulativePnl += finalPnl;
249
+ const clearingFee = Math.abs(finalPnl) * rand(1e-3, 3e-3);
250
+ const hedgingCost = Math.abs(finalPnl) * rand(5e-4, 2e-3);
251
+ const insuranceReserve = Math.abs(finalPnl) * rand(3e-4, 1e-3);
252
+ blockNum += randInt(1, 20);
253
+ const timestamp = day.getTime() + randInt(0, 23) * 36e5 + randInt(0, 36e5);
254
+ trades.push({
255
+ id: genId("FXT"),
256
+ timestamp,
257
+ pairId: pair.id,
258
+ pairSymbol: pair.symbol,
259
+ side,
260
+ rfqPrice,
261
+ quotePrice,
262
+ matchPrice,
263
+ settlePrice,
264
+ lots,
265
+ pips: isWin ? Math.abs(pips) : -Math.abs(pips) * rand(0.3, 0.8),
266
+ pnl: finalPnl,
267
+ status: "SETTLED",
268
+ pvpSettled: true,
269
+ clearingFee,
270
+ hedgingCost,
271
+ insuranceReserve,
272
+ txHash: genTxHash(),
273
+ blockNumber: blockNum,
274
+ cycleDay: d + 1,
275
+ cumulativePnl
276
+ });
277
+ }
278
+ }
279
+ trades.sort((a, b) => a.timestamp - b.timestamp);
280
+ return trades;
281
+ }
282
+ generateLiveTransaction(poolId, type, baseAmount) {
283
+ const params = POOL_PARAMS[poolId];
284
+ let amount;
285
+ switch (type) {
286
+ case "deposit":
287
+ amount = baseAmount ?? rand(params.avgDepositSize * 0.5, params.avgDepositSize * 1.5);
288
+ break;
289
+ case "withdrawal":
290
+ amount = -(baseAmount ?? rand(params.avgWithdrawalSize * 0.5, params.avgWithdrawalSize * 1.5));
291
+ break;
292
+ case "profit_distribution":
293
+ amount = baseAmount ?? rand(500, 5e3);
294
+ break;
295
+ case "fee_collection":
296
+ amount = baseAmount ?? rand(100, 2e3);
297
+ break;
298
+ case "loss_absorption":
299
+ amount = -(baseAmount ?? rand(200, 3e3));
300
+ break;
301
+ default:
302
+ amount = baseAmount ?? rand(-5e3, 5e3);
303
+ }
304
+ const pool = FOREX_POOL_DEFAULTS.find((p) => p.id === poolId);
305
+ const balanceBefore = pool.totalSize;
306
+ return {
307
+ id: genId("ptx"),
308
+ poolId,
309
+ type,
310
+ amount,
311
+ balanceBefore,
312
+ balanceAfter: balanceBefore + amount,
313
+ txHash: genTxHash(),
314
+ blockNumber: this.baseBlockNumber + Math.floor(Date.now() / 12e3),
315
+ timestamp: Date.now(),
316
+ description: this.getTxDescription(type, poolId, Math.abs(amount))
317
+ };
318
+ }
319
+ // ── Private Methods ────────────────────────────────────────────────────
320
+ generatePoolSnapshots(poolId, currentSize) {
321
+ const params = POOL_PARAMS[poolId];
322
+ const snapshots = [];
323
+ const now = /* @__PURE__ */ new Date();
324
+ let balance = currentSize * rand(0.82, 0.88);
325
+ let cumulativePnl = 0;
326
+ for (let i = 59; i >= 0; i--) {
327
+ const day = new Date(now);
328
+ day.setDate(day.getDate() - i);
329
+ const dayOfWeek = day.getDay();
330
+ const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;
331
+ const openBalance = balance;
332
+ const activityMultiplier = isWeekend ? 0.2 : 1;
333
+ const isDrawdown = !isWeekend && Math.random() < 0.2;
334
+ let dailyPnlPct;
335
+ if (isDrawdown) {
336
+ dailyPnlPct = -rand(1e-4, params.stddevPnlPct * 2);
337
+ } else {
338
+ dailyPnlPct = this.gaussianRandom(params.meanDailyPnlPct, params.stddevPnlPct);
339
+ }
340
+ dailyPnlPct *= activityMultiplier;
341
+ const dailyPnl = balance * dailyPnlPct;
342
+ cumulativePnl += dailyPnl;
343
+ const depositCount = isWeekend ? randInt(1, Math.ceil(params.depositsPerDay[0] * 0.2)) : randInt(params.depositsPerDay[0], params.depositsPerDay[1]);
344
+ const withdrawalCount = isWeekend ? randInt(0, Math.ceil(params.withdrawalsPerDay[0] * 0.2)) : randInt(params.withdrawalsPerDay[0], params.withdrawalsPerDay[1]);
345
+ const deposits = depositCount * params.avgDepositSize * rand(0.7, 1.3) * activityMultiplier;
346
+ const withdrawals = withdrawalCount * params.avgWithdrawalSize * rand(0.7, 1.3) * activityMultiplier;
347
+ const netFlow = deposits - withdrawals;
348
+ balance += dailyPnl + netFlow;
349
+ const txCount = depositCount + withdrawalCount + Math.round(params.profitDistPerDay * activityMultiplier);
350
+ const utilization = rand(params.utilizationMin, params.utilizationMax);
351
+ const activeUsers = Math.round(rand(80, 400) * activityMultiplier);
352
+ snapshots.push({
353
+ poolId,
354
+ date: formatDate(day),
355
+ openBalance,
356
+ closeBalance: balance,
357
+ deposits,
358
+ withdrawals,
359
+ netFlow,
360
+ dailyPnl,
361
+ dailyPnlPct,
362
+ cumulativePnl,
363
+ utilization,
364
+ txCount,
365
+ activeUsers
366
+ });
367
+ }
368
+ return snapshots;
369
+ }
370
+ generatePoolTransactions(poolId, snapshots) {
371
+ const params = POOL_PARAMS[poolId];
372
+ const transactions = [];
373
+ for (const snap of snapshots) {
374
+ const day = new Date(snap.date);
375
+ const dayOfWeek = day.getDay();
376
+ const isWeekend = dayOfWeek === 0 || dayOfWeek === 6;
377
+ const mult = isWeekend ? 0.2 : 1;
378
+ const depositCount = Math.round(randInt(params.depositsPerDay[0], params.depositsPerDay[1]) * mult);
379
+ const withdrawalCount = Math.round(randInt(params.withdrawalsPerDay[0], params.withdrawalsPerDay[1]) * mult);
380
+ const profitCount = Math.round(params.profitDistPerDay * mult);
381
+ for (let i = 0; i < depositCount; i++) {
382
+ const amount = rand(params.avgDepositSize * 0.3, params.avgDepositSize * 2);
383
+ const ts = day.getTime() + randInt(0, 23) * 36e5 + randInt(0, 36e5);
384
+ transactions.push({
385
+ id: genId("dep"),
386
+ poolId,
387
+ type: "deposit",
388
+ amount,
389
+ balanceBefore: 0,
390
+ balanceAfter: 0,
391
+ txHash: genTxHash(),
392
+ blockNumber: this.baseBlockNumber + Math.floor(ts / 12e3) + randInt(0, 50),
393
+ timestamp: ts,
394
+ description: `Deposit to ${poolId} pool`
395
+ });
396
+ }
397
+ for (let i = 0; i < withdrawalCount; i++) {
398
+ const amount = rand(params.avgWithdrawalSize * 0.3, params.avgWithdrawalSize * 2);
399
+ const ts = day.getTime() + randInt(0, 23) * 36e5 + randInt(0, 36e5);
400
+ transactions.push({
401
+ id: genId("wdr"),
402
+ poolId,
403
+ type: "withdrawal",
404
+ amount: -amount,
405
+ balanceBefore: 0,
406
+ balanceAfter: 0,
407
+ txHash: genTxHash(),
408
+ blockNumber: this.baseBlockNumber + Math.floor(ts / 12e3) + randInt(0, 50),
409
+ timestamp: ts,
410
+ description: `Withdrawal from ${poolId} pool`
411
+ });
412
+ }
413
+ for (let i = 0; i < profitCount; i++) {
414
+ const amount = rand(500, 8e3);
415
+ const ts = day.getTime() + randInt(6, 22) * 36e5 + randInt(0, 36e5);
416
+ transactions.push({
417
+ id: genId("prd"),
418
+ poolId,
419
+ type: "profit_distribution",
420
+ amount,
421
+ balanceBefore: 0,
422
+ balanceAfter: 0,
423
+ txHash: genTxHash(),
424
+ blockNumber: this.baseBlockNumber + Math.floor(ts / 12e3) + randInt(0, 50),
425
+ timestamp: ts,
426
+ description: `Profit distribution from ${poolId} pool`
427
+ });
428
+ }
429
+ if (!isWeekend) {
430
+ const feeCount = randInt(1, 2);
431
+ for (let i = 0; i < feeCount; i++) {
432
+ const amount = rand(100, 3e3);
433
+ const ts = day.getTime() + randInt(8, 20) * 36e5;
434
+ transactions.push({
435
+ id: genId("fee"),
436
+ poolId,
437
+ type: "fee_collection",
438
+ amount,
439
+ balanceBefore: 0,
440
+ balanceAfter: 0,
441
+ txHash: genTxHash(),
442
+ blockNumber: this.baseBlockNumber + Math.floor(ts / 12e3) + randInt(0, 50),
443
+ timestamp: ts,
444
+ description: `Fee collection for ${poolId} pool`
445
+ });
446
+ }
447
+ }
448
+ }
449
+ return transactions;
450
+ }
451
+ gaussianRandom(mean, stddev) {
452
+ let u = 0, v = 0;
453
+ while (u === 0) u = Math.random();
454
+ while (v === 0) v = Math.random();
455
+ const z = Math.sqrt(-2 * Math.log(u)) * Math.cos(2 * Math.PI * v);
456
+ return mean + z * stddev;
457
+ }
458
+ getTxDescription(type, poolId, amount) {
459
+ const fmt = `$${amount.toLocaleString(void 0, { maximumFractionDigits: 0 })}`;
460
+ switch (type) {
461
+ case "deposit":
462
+ return `Deposit ${fmt} to ${poolId} pool`;
463
+ case "withdrawal":
464
+ return `Withdrawal ${fmt} from ${poolId} pool`;
465
+ case "profit_distribution":
466
+ return `Profit distribution ${fmt} from ${poolId}`;
467
+ case "loss_absorption":
468
+ return `Loss absorbed ${fmt} by ${poolId} pool`;
469
+ case "inter_pool_transfer":
470
+ return `Inter-pool transfer ${fmt}`;
471
+ case "fee_collection":
472
+ return `Fee collected ${fmt} in ${poolId}`;
473
+ case "reserve_rebalance":
474
+ return `Reserve rebalance ${fmt} in ${poolId}`;
475
+ default:
476
+ return `${type} ${fmt}`;
477
+ }
478
+ }
479
+ };
480
+ _instance = null;
481
+ exports.ForexPoolDataGenerator = {
482
+ getInstance() {
483
+ if (!_instance) {
484
+ _instance = new ForexPoolDataGeneratorClass();
485
+ }
486
+ return _instance;
487
+ }
488
+ };
489
+ }
490
+ });
5
491
  function getConfig() {
6
492
  {
7
493
  throw new Error("ONE SDK not initialized. Call initOneSDK() first.");
@@ -1706,13 +2192,1148 @@ function createUsageService(baseUrl) {
1706
2192
  return new UsageService(baseUrl);
1707
2193
  }
1708
2194
 
2195
+ // src/services/forex/ForexSimulationEngine.ts
2196
+ init_forex();
2197
+ var idCounter = 0;
2198
+ function genId2() {
2199
+ return `fxlog_${Date.now()}_${++idCounter}`;
2200
+ }
2201
+ function tradeId() {
2202
+ return `FXT_${Date.now().toString(36).toUpperCase()}_${(++idCounter).toString(36).toUpperCase()}`;
2203
+ }
2204
+ function rand2(min, max) {
2205
+ return min + Math.random() * (max - min);
2206
+ }
2207
+ function randInt2(min, max) {
2208
+ return Math.floor(rand2(min, max + 1));
2209
+ }
2210
+ function pick2(arr) {
2211
+ return arr[Math.floor(Math.random() * arr.length)];
2212
+ }
2213
+ function formatRate(price, pair) {
2214
+ if (pair.pipSize >= 0.01) return price.toFixed(3);
2215
+ return price.toFixed(5);
2216
+ }
2217
+ var FX_NEWS = [
2218
+ "ECB signals potential rate adjustment, EUR pairs volatile",
2219
+ "BOJ maintains yield curve control, JPY weakens further",
2220
+ "Fed minutes reveal hawkish sentiment, USD strengthens",
2221
+ "UK CPI data beats expectations, GBP rallies",
2222
+ "RBA holds rates steady, AUD consolidates",
2223
+ "SNB intervenes in currency markets, CHF stabilizes",
2224
+ "Bank of Canada rate decision pending, CAD in focus",
2225
+ "Cross-border stablecoin settlement volume hits $2.1B daily",
2226
+ "Circle USDC reserves fully backed, attestation report released",
2227
+ "DeFi forex protocol TVL reaches new high at $890M",
2228
+ "On-chain FX liquidity deepens across major pairs",
2229
+ "Institutional adoption of on-chain forex accelerates"
2230
+ ];
2231
+ var ForexSimulationEngine = class {
2232
+ constructor() {
2233
+ this.listeners = [];
2234
+ this.poolTxListeners = [];
2235
+ this.cycleTimer = null;
2236
+ this.pairStates = /* @__PURE__ */ new Map();
2237
+ this.running = false;
2238
+ this.openPositions = [];
2239
+ this.totalPnl = 0;
2240
+ this.totalTrades = 0;
2241
+ this.totalPips = 0;
2242
+ this.totalLots = 0;
2243
+ for (const pair of FOREX_CURRENCY_PAIRS) {
2244
+ const jitter = pair.basePrice * rand2(-3e-3, 3e-3);
2245
+ const price = pair.basePrice + jitter;
2246
+ const halfSpread = pair.spreadPips * pair.pipSize / 2;
2247
+ this.pairStates.set(pair.id, {
2248
+ pair,
2249
+ currentPrice: price,
2250
+ bidPrice: price - halfSpread,
2251
+ askPrice: price + halfSpread,
2252
+ lastSpread: pair.spreadPips
2253
+ });
2254
+ }
2255
+ }
2256
+ // ── Public API ─────────────────────────────────────────────────────────────
2257
+ start() {
2258
+ this.running = true;
2259
+ this.scheduleCycle();
2260
+ }
2261
+ stop() {
2262
+ this.running = false;
2263
+ if (this.cycleTimer) {
2264
+ clearTimeout(this.cycleTimer);
2265
+ this.cycleTimer = null;
2266
+ }
2267
+ }
2268
+ onLog(callback) {
2269
+ this.listeners.push(callback);
2270
+ return () => {
2271
+ this.listeners = this.listeners.filter((l) => l !== callback);
2272
+ };
2273
+ }
2274
+ onPoolTransaction(callback) {
2275
+ this.poolTxListeners.push(callback);
2276
+ return () => {
2277
+ this.poolTxListeners = this.poolTxListeners.filter((l) => l !== callback);
2278
+ };
2279
+ }
2280
+ isRunning() {
2281
+ return this.running;
2282
+ }
2283
+ getStats() {
2284
+ return {
2285
+ totalPnl: this.totalPnl,
2286
+ totalTrades: this.totalTrades,
2287
+ totalPips: this.totalPips,
2288
+ totalLots: this.totalLots,
2289
+ positions: this.openPositions.length
2290
+ };
2291
+ }
2292
+ getPairStates() {
2293
+ return this.pairStates;
2294
+ }
2295
+ emitBootSequence() {
2296
+ const bootMessages = [
2297
+ { msg: "Initializing StableFX Engine v2.1.0...", delay: 0 },
2298
+ { msg: "Connecting to Circle StableFX RFQ network...", delay: 500 },
2299
+ { msg: "Loading USDC stablecoin pair feeds (6 pairs)...", delay: 1200 },
2300
+ { msg: "Calibrating PvP settlement engine...", delay: 2e3 },
2301
+ { msg: "Initializing clearing pool ($12.5M)...", delay: 2800 },
2302
+ { msg: "Initializing hedging pool ($7.5M)...", delay: 3400 },
2303
+ { msg: "Initializing insurance pool ($5.0M)...", delay: 4e3 },
2304
+ { msg: "Risk management module online (max exposure: 25%)", delay: 4500 },
2305
+ { msg: "=== StableFX Engine ready. Starting RFQ cycles ===", delay: 5e3 }
2306
+ ];
2307
+ for (const { msg, delay } of bootMessages) {
2308
+ setTimeout(() => {
2309
+ this.emit({
2310
+ id: genId2(),
2311
+ timestamp: Date.now(),
2312
+ type: "SYSTEM",
2313
+ message: msg,
2314
+ importance: "medium"
2315
+ });
2316
+ }, delay);
2317
+ }
2318
+ }
2319
+ destroy() {
2320
+ this.stop();
2321
+ this.listeners = [];
2322
+ this.poolTxListeners = [];
2323
+ this.pairStates.clear();
2324
+ this.openPositions = [];
2325
+ }
2326
+ // ── Private Methods ────────────────────────────────────────────────────────
2327
+ emit(entry) {
2328
+ for (const listener of this.listeners) {
2329
+ listener(entry);
2330
+ }
2331
+ }
2332
+ emitPoolTx(tx) {
2333
+ for (const listener of this.poolTxListeners) {
2334
+ listener(tx);
2335
+ }
2336
+ }
2337
+ generatePoolTxFromEvent(type, data) {
2338
+ try {
2339
+ const { ForexPoolDataGenerator: ForexPoolDataGenerator2 } = (init_ForexPoolDataGenerator(), __toCommonJS(ForexPoolDataGenerator_exports));
2340
+ const generator = ForexPoolDataGenerator2.getInstance();
2341
+ if (type === "SETTLE" && data.pnl !== void 0) {
2342
+ const tx = generator.generateLiveTransaction("clearing", "fee_collection", Math.abs(data.pnl) * rand2(1e-3, 3e-3));
2343
+ this.emitPoolTx(tx);
2344
+ } else if (type === "HEDGE") {
2345
+ const tx = generator.generateLiveTransaction("hedging", data.pnl && data.pnl < 0 ? "loss_absorption" : "profit_distribution", Math.abs(data.lots || 1) * rand2(50, 200));
2346
+ this.emitPoolTx(tx);
2347
+ } else if (type === "CLEAR") {
2348
+ const tx = generator.generateLiveTransaction("clearing", "profit_distribution", (data.volume || 1e5) * rand2(1e-4, 5e-4));
2349
+ this.emitPoolTx(tx);
2350
+ }
2351
+ } catch {
2352
+ }
2353
+ }
2354
+ scheduleCycle() {
2355
+ if (!this.running) return;
2356
+ const interval = rand2(8e3, 14e3);
2357
+ this.cycleTimer = setTimeout(() => {
2358
+ if (this.running) {
2359
+ this.runTradeCycle();
2360
+ this.scheduleCycle();
2361
+ }
2362
+ }, interval);
2363
+ }
2364
+ simulatePrice(pairId) {
2365
+ const state = this.pairStates.get(pairId);
2366
+ if (!state) return 0;
2367
+ const volatility = state.pair.id.includes("JPYC") ? 8e-4 : 4e-4;
2368
+ const drift = rand2(-volatility, volatility);
2369
+ const newPrice = state.currentPrice * (1 + drift);
2370
+ const halfSpread = (state.pair.spreadPips + rand2(-0.3, 0.3)) * state.pair.pipSize / 2;
2371
+ state.currentPrice = newPrice;
2372
+ state.bidPrice = newPrice - halfSpread;
2373
+ state.askPrice = newPrice + halfSpread;
2374
+ state.lastSpread = halfSpread * 2 / state.pair.pipSize;
2375
+ return newPrice;
2376
+ }
2377
+ runTradeCycle() {
2378
+ const pairState = pick2(Array.from(this.pairStates.values()));
2379
+ const pair = pairState.pair;
2380
+ const entries = [];
2381
+ let delay = 0;
2382
+ const price = this.simulatePrice(pair.id);
2383
+ const side = Math.random() > 0.5 ? "BUY" : "SELL";
2384
+ const lots = parseFloat(rand2(0.1, 2.5).toFixed(2));
2385
+ const notional = lots * 1e5;
2386
+ const rfqId = tradeId();
2387
+ entries.push({
2388
+ entry: {
2389
+ type: "RFQ",
2390
+ message: `RFQ ${rfqId} | ${pair.symbol} ${side} ${lots.toFixed(2)} lots ($${(notional / 1e3).toFixed(0)}K) | Mid: ${formatRate(price, pair)}`,
2391
+ data: { rfqId, pair: pair.id, side, lots, price },
2392
+ importance: "medium",
2393
+ pairId: pair.id
2394
+ },
2395
+ delay
2396
+ });
2397
+ delay += rand2(400, 800);
2398
+ const quoteSpread = rand2(0.5, 2) * pair.pipSize;
2399
+ const quotePrice = side === "BUY" ? price + quoteSpread : price - quoteSpread;
2400
+ const quotePips = Math.abs(quotePrice - price) / pair.pipSize;
2401
+ entries.push({
2402
+ entry: {
2403
+ type: "QUOTE",
2404
+ message: `QUOTE ${rfqId} | ${pair.symbol} @ ${formatRate(quotePrice, pair)} | Spread: ${quotePips.toFixed(1)} pips | Valid: 3s`,
2405
+ data: { rfqId, quotePrice, spread: quotePips },
2406
+ importance: "medium",
2407
+ pairId: pair.id
2408
+ },
2409
+ delay
2410
+ });
2411
+ delay += rand2(500, 1e3);
2412
+ const matched = Math.random() < 0.85;
2413
+ if (matched) {
2414
+ const matchPrice = quotePrice * (1 + rand2(-5e-5, 5e-5));
2415
+ entries.push({
2416
+ entry: {
2417
+ type: "MATCH",
2418
+ message: `MATCH ${rfqId} | ${pair.symbol} ${side} @ ${formatRate(matchPrice, pair)} | ${lots.toFixed(2)} lots | Counterparty: LP-${randInt2(1, 8)}`,
2419
+ data: { rfqId, matchPrice, counterparty: `LP-${randInt2(1, 8)}` },
2420
+ importance: "high",
2421
+ pairId: pair.id
2422
+ },
2423
+ delay
2424
+ });
2425
+ delay += rand2(1e3, 2500);
2426
+ const settlePrice = matchPrice * (1 + rand2(-2e-5, 2e-5));
2427
+ const pips = (settlePrice - price) / pair.pipSize * (side === "BUY" ? 1 : -1);
2428
+ const pnl = pips * pair.pipSize * lots * 1e5;
2429
+ entries.push({
2430
+ entry: {
2431
+ type: "SETTLE",
2432
+ message: `SETTLE ${rfqId} | PvP confirmed | ${pair.symbol} @ ${formatRate(settlePrice, pair)} | P&L: ${pips >= 0 ? "+" : ""}${pips.toFixed(1)} pips ($${pnl >= 0 ? "+" : ""}${pnl.toFixed(2)})`,
2433
+ data: { rfqId, settlePrice, pips, pnl, pvp: true },
2434
+ importance: "high",
2435
+ pairId: pair.id
2436
+ },
2437
+ delay
2438
+ });
2439
+ delay += rand2(300, 600);
2440
+ entries.push({
2441
+ entry: {
2442
+ type: "PVP",
2443
+ message: `PvP ${rfqId} | Atomic settlement confirmed on-chain | USDC transferred: $${notional.toLocaleString()} | Gas: ~$0.${randInt2(10, 50)}`,
2444
+ data: { rfqId, settled: true, gasWei: randInt2(10, 50) },
2445
+ importance: "medium",
2446
+ pairId: pair.id
2447
+ },
2448
+ delay
2449
+ });
2450
+ this.generatePoolTxFromEvent("SETTLE", { pnl });
2451
+ this.totalTrades++;
2452
+ this.totalPnl += pnl;
2453
+ this.totalPips += pips;
2454
+ this.totalLots += lots;
2455
+ if (Math.random() < 0.4) {
2456
+ this.openPositions.push({
2457
+ id: rfqId,
2458
+ pairId: pair.id,
2459
+ side,
2460
+ lots,
2461
+ pips,
2462
+ entryPrice: matchPrice,
2463
+ currentPrice: settlePrice,
2464
+ pnl,
2465
+ openTime: Date.now()
2466
+ });
2467
+ if (this.openPositions.length > 5) {
2468
+ this.openPositions.shift();
2469
+ }
2470
+ }
2471
+ } else {
2472
+ entries.push({
2473
+ entry: {
2474
+ type: "MATCH",
2475
+ message: `MATCH FAILED ${rfqId} | ${pair.symbol} | No counterparty at requested price | Requoting...`,
2476
+ data: { rfqId, matched: false },
2477
+ importance: "low",
2478
+ pairId: pair.id
2479
+ },
2480
+ delay
2481
+ });
2482
+ }
2483
+ if (Math.random() < 0.2) {
2484
+ delay += rand2(400, 800);
2485
+ const hedgePair = pick2(FOREX_CURRENCY_PAIRS);
2486
+ const hedgeLots = parseFloat(rand2(0.5, 5).toFixed(2));
2487
+ const hedgeDirection = Math.random() > 0.5 ? "LONG" : "SHORT";
2488
+ entries.push({
2489
+ entry: {
2490
+ type: "HEDGE",
2491
+ message: `HEDGE | ${hedgePair.symbol} ${hedgeDirection} ${hedgeLots.toFixed(2)} lots | Pool delta neutralization | Exposure: ${rand2(5, 20).toFixed(1)}%`,
2492
+ data: { pair: hedgePair.id, direction: hedgeDirection, lots: hedgeLots },
2493
+ importance: "medium"
2494
+ },
2495
+ delay
2496
+ });
2497
+ this.generatePoolTxFromEvent("HEDGE", { lots: hedgeLots });
2498
+ }
2499
+ if (Math.random() < 0.15) {
2500
+ delay += rand2(300, 600);
2501
+ const clearAmount = randInt2(5e4, 5e5);
2502
+ entries.push({
2503
+ entry: {
2504
+ type: "CLEAR",
2505
+ message: `CLEAR | Netting cycle complete | Volume: $${(clearAmount / 1e3).toFixed(0)}K | Pairs settled: ${randInt2(2, 6)} | Pool util: ${rand2(60, 85).toFixed(1)}%`,
2506
+ data: { volume: clearAmount, pairsSettled: randInt2(2, 6) },
2507
+ importance: "low"
2508
+ },
2509
+ delay
2510
+ });
2511
+ this.generatePoolTxFromEvent("CLEAR", { volume: clearAmount });
2512
+ }
2513
+ if (this.openPositions.length > 0 && Math.random() < 0.25) {
2514
+ delay += rand2(300, 600);
2515
+ const posUpdates = this.openPositions.slice(0, 3).map((pos) => {
2516
+ const pState = this.pairStates.get(pos.pairId);
2517
+ if (pState) {
2518
+ pos.currentPrice = pState.currentPrice;
2519
+ pos.pips = (pos.currentPrice - pos.entryPrice) / pState.pair.pipSize * (pos.side === "BUY" ? 1 : -1);
2520
+ pos.pnl = pos.pips * pState.pair.pipSize * pos.lots * 1e5;
2521
+ }
2522
+ return `${pState?.pair.symbol || pos.pairId} ${pos.side}: ${pos.pips >= 0 ? "+" : ""}${pos.pips.toFixed(1)} pips`;
2523
+ });
2524
+ entries.push({
2525
+ entry: {
2526
+ type: "POSITION",
2527
+ message: `POSITION | ${posUpdates.join(" | ")} | Open: ${this.openPositions.length}`,
2528
+ data: { positions: this.openPositions.length },
2529
+ importance: "low"
2530
+ },
2531
+ delay
2532
+ });
2533
+ if (this.openPositions.length > 2 && Math.random() < 0.3) {
2534
+ const closed = this.openPositions.shift();
2535
+ this.totalPnl += closed.pnl * rand2(0.01, 0.03);
2536
+ }
2537
+ }
2538
+ if (Math.random() < 0.3) {
2539
+ delay += rand2(300, 600);
2540
+ entries.push({
2541
+ entry: {
2542
+ type: "PNL",
2543
+ 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)}`,
2544
+ data: { totalPnl: this.totalPnl, totalTrades: this.totalTrades, totalPips: this.totalPips },
2545
+ importance: "medium"
2546
+ },
2547
+ delay
2548
+ });
2549
+ }
2550
+ if (Math.random() < 0.1) {
2551
+ delay += rand2(300, 600);
2552
+ entries.push({
2553
+ entry: {
2554
+ type: "SYSTEM",
2555
+ message: `[Market] ${pick2(FX_NEWS)}`,
2556
+ importance: "medium"
2557
+ },
2558
+ delay
2559
+ });
2560
+ }
2561
+ for (const { entry, delay: d } of entries) {
2562
+ setTimeout(() => {
2563
+ if (this.running) {
2564
+ this.emit({
2565
+ ...entry,
2566
+ id: genId2(),
2567
+ timestamp: Date.now()
2568
+ });
2569
+ }
2570
+ }, d);
2571
+ }
2572
+ }
2573
+ };
2574
+ var forexSimulationEngine = new ForexSimulationEngine();
2575
+
2576
+ // src/services/forex/index.ts
2577
+ init_ForexPoolDataGenerator();
2578
+
2579
+ // src/services/forex/BotSimulationEngine.ts
2580
+ var STRATEGY_PERSONALITIES = [
2581
+ {
2582
+ id: "balanced-01",
2583
+ name: "Balanced Alpha",
2584
+ shortName: "BAL",
2585
+ color: "#3B82F6",
2586
+ scanIntervalMin: 25e3,
2587
+ // Slower: 25-40s between cycles
2588
+ scanIntervalMax: 4e4,
2589
+ tradeFrequency: 0.4,
2590
+ positionSizeMin: 15,
2591
+ positionSizeMax: 35,
2592
+ leverageMin: 3,
2593
+ leverageMax: 10,
2594
+ primaryIndicators: ["RSI", "MACD"],
2595
+ riskTolerance: "medium",
2596
+ preferredPairs: ["BTC/USDT", "ETH/USDT", "SOL/USDT"],
2597
+ rsiBias: 50
2598
+ },
2599
+ {
2600
+ id: "conservative-01",
2601
+ name: "Conservative Shield",
2602
+ shortName: "CON",
2603
+ color: "#10B981",
2604
+ scanIntervalMin: 35e3,
2605
+ // Slower: 35-55s between cycles
2606
+ scanIntervalMax: 55e3,
2607
+ tradeFrequency: 0.25,
2608
+ positionSizeMin: 10,
2609
+ positionSizeMax: 20,
2610
+ leverageMin: 2,
2611
+ leverageMax: 5,
2612
+ primaryIndicators: ["Bollinger", "Volume"],
2613
+ riskTolerance: "low",
2614
+ preferredPairs: ["BTC/USDT", "ETH/USDT"],
2615
+ rsiBias: 45
2616
+ },
2617
+ {
2618
+ id: "aggressive-01",
2619
+ name: "Aggressive Momentum",
2620
+ shortName: "AGG",
2621
+ color: "#EF4444",
2622
+ scanIntervalMin: 18e3,
2623
+ // Slower: 18-30s between cycles
2624
+ scanIntervalMax: 3e4,
2625
+ tradeFrequency: 0.5,
2626
+ positionSizeMin: 25,
2627
+ positionSizeMax: 50,
2628
+ leverageMin: 5,
2629
+ leverageMax: 20,
2630
+ primaryIndicators: ["RSI", "MACD", "EMA", "Volume"],
2631
+ riskTolerance: "high",
2632
+ preferredPairs: ["BTC/USDT", "ETH/USDT", "SOL/USDT", "DOGE/USDT", "AVAX/USDT"],
2633
+ rsiBias: 55
2634
+ }
2635
+ ];
2636
+ var PAIR_PRICES = {
2637
+ "BTC/USDT": 67500,
2638
+ "ETH/USDT": 3450,
2639
+ "BNB/USDT": 605,
2640
+ "SOL/USDT": 178,
2641
+ "XRP/USDT": 0.62,
2642
+ "DOGE/USDT": 0.165,
2643
+ "ADA/USDT": 0.45,
2644
+ "AVAX/USDT": 38.5,
2645
+ "ARB/USDT": 1.18,
2646
+ "MATIC/USDT": 0.72,
2647
+ "LINK/USDT": 14.5,
2648
+ "UNI/USDT": 7.8,
2649
+ "AAVE/USDT": 92,
2650
+ "OP/USDT": 2.45,
2651
+ "APT/USDT": 8.9,
2652
+ "INJ/USDT": 24.5,
2653
+ "TIA/USDT": 11.2,
2654
+ "SUI/USDT": 1.65,
2655
+ "DOT/USDT": 7.2,
2656
+ "ATOM/USDT": 9.8,
2657
+ "FIL/USDT": 5.6,
2658
+ "LTC/USDT": 72,
2659
+ "NEAR/USDT": 5.1,
2660
+ "FTM/USDT": 0.42
2661
+ };
2662
+ var CHAIN_INFO = {
2663
+ ethereum: { name: "Ethereum", shortName: "ETH", icon: "\u039E" },
2664
+ arbitrum: { name: "Arbitrum", shortName: "ARB", icon: "\u25C6" },
2665
+ bsc: { name: "BSC", shortName: "BSC", icon: "\u25C6" },
2666
+ base: { name: "Base", shortName: "BASE", icon: "\u25CF" },
2667
+ polygon: { name: "Polygon", shortName: "POLY", icon: "\u2B21" },
2668
+ optimism: { name: "Optimism", shortName: "OP", icon: "\u25C9" },
2669
+ avalanche: { name: "Avalanche", shortName: "AVAX", icon: "\u25B2" },
2670
+ linea: { name: "Linea", shortName: "LINEA", icon: "\u2550" },
2671
+ zksync: { name: "zkSync", shortName: "ZK", icon: "\u2B22" },
2672
+ scroll: { name: "Scroll", shortName: "SCRL", icon: "\u25CE" }
2673
+ };
2674
+ var NEWS_HEADLINES = [
2675
+ "Fed signals potential rate pause, crypto markets react positively",
2676
+ "Major institutional investor increases BTC allocation by 15%",
2677
+ "On-chain data shows whale accumulation pattern forming",
2678
+ "DeFi TVL reaches new monthly high across major protocols",
2679
+ "Exchange outflows surge as holders move to cold storage",
2680
+ "Options market signals increased volatility expected this week",
2681
+ "Mining difficulty adjustment approaching, hash rate stable",
2682
+ "Regulatory clarity in EU boosts market sentiment",
2683
+ "Stablecoin supply expanding, potential bullish indicator",
2684
+ "Social sentiment score shifts to extreme greed zone",
2685
+ "Cross-chain bridge volume hits record daily high",
2686
+ "Layer 2 adoption metrics show 40% MoM growth"
2687
+ ];
2688
+ var idCounter2 = 0;
2689
+ function genId3() {
2690
+ return `log_${Date.now()}_${++idCounter2}`;
2691
+ }
2692
+ function rand3(min, max) {
2693
+ return min + Math.random() * (max - min);
2694
+ }
2695
+ function randInt3(min, max) {
2696
+ return Math.floor(rand3(min, max + 1));
2697
+ }
2698
+ function pick3(arr) {
2699
+ return arr[Math.floor(Math.random() * arr.length)];
2700
+ }
2701
+ function clamp(val, min, max) {
2702
+ return Math.max(min, Math.min(max, val));
2703
+ }
2704
+ function formatPrice(price) {
2705
+ if (price >= 1e3) return price.toFixed(2);
2706
+ if (price >= 1) return price.toFixed(3);
2707
+ return price.toFixed(5);
2708
+ }
2709
+ var BotSimulationEngine = class {
2710
+ constructor() {
2711
+ this.listeners = [];
2712
+ this.botTimers = /* @__PURE__ */ new Map();
2713
+ this.botStates = /* @__PURE__ */ new Map();
2714
+ this.priceState = /* @__PURE__ */ new Map();
2715
+ this.indicatorState = /* @__PURE__ */ new Map();
2716
+ this.running = false;
2717
+ this.userPairs = [];
2718
+ this.userChains = [];
2719
+ for (const [pair, base] of Object.entries(PAIR_PRICES)) {
2720
+ this.priceState.set(pair, base * (1 + rand3(-0.02, 0.02)));
2721
+ }
2722
+ }
2723
+ // ── Public API ─────────────────────────────────────────────────────────────
2724
+ getStrategies() {
2725
+ return STRATEGY_PERSONALITIES;
2726
+ }
2727
+ start(strategyIds, userPairs, userChains) {
2728
+ this.running = true;
2729
+ this.userPairs = (userPairs || []).map((p) => p.includes("/") ? p : `${p}/USDT`).filter((p) => p in PAIR_PRICES);
2730
+ this.userChains = (userChains || []).filter((c) => c in CHAIN_INFO);
2731
+ const strategies = strategyIds ? STRATEGY_PERSONALITIES.filter((s) => strategyIds.includes(s.id)) : STRATEGY_PERSONALITIES;
2732
+ for (const strategy of strategies) {
2733
+ this.initBotState(strategy);
2734
+ this.scheduleCycle(strategy);
2735
+ }
2736
+ }
2737
+ stop(strategyIds) {
2738
+ const ids = strategyIds || Array.from(this.botTimers.keys());
2739
+ for (const id of ids) {
2740
+ const timer = this.botTimers.get(id);
2741
+ if (timer) {
2742
+ clearTimeout(timer);
2743
+ this.botTimers.delete(id);
2744
+ }
2745
+ }
2746
+ if (!strategyIds) {
2747
+ this.running = false;
2748
+ }
2749
+ }
2750
+ onLog(callback) {
2751
+ this.listeners.push(callback);
2752
+ return () => {
2753
+ this.listeners = this.listeners.filter((l) => l !== callback);
2754
+ };
2755
+ }
2756
+ getBotState(strategyId) {
2757
+ return this.botStates.get(strategyId);
2758
+ }
2759
+ getAllBotStates() {
2760
+ return this.botStates;
2761
+ }
2762
+ isRunning() {
2763
+ return this.running;
2764
+ }
2765
+ emitBootSequence() {
2766
+ const bootMessages = [
2767
+ { msg: "Initializing ONE Trading Engine v3.2.1...", delay: 0 },
2768
+ { msg: "Loading market data feeds...", delay: 500 },
2769
+ { msg: "Connecting to exchange WebSocket streams...", delay: 1200 },
2770
+ { msg: "Calibrating indicator engines (RSI, MACD, EMA, Bollinger)...", delay: 2e3 },
2771
+ { msg: "Loading strategy personalities: balanced-01, conservative-01, aggressive-01", delay: 2800 },
2772
+ { msg: "Risk management module initialized (max drawdown: 15%)", delay: 3600 },
2773
+ { msg: "Portfolio allocation engine ready", delay: 4200 },
2774
+ { msg: "=== All systems online. Starting trading cycles ===", delay: 5e3 }
2775
+ ];
2776
+ for (const { msg, delay } of bootMessages) {
2777
+ setTimeout(() => {
2778
+ this.emit({
2779
+ id: genId3(),
2780
+ timestamp: Date.now(),
2781
+ strategyId: "system",
2782
+ strategyName: "SYSTEM",
2783
+ type: "SYSTEM",
2784
+ message: msg,
2785
+ importance: "medium"
2786
+ });
2787
+ }, delay);
2788
+ }
2789
+ }
2790
+ destroy() {
2791
+ this.stop();
2792
+ this.listeners = [];
2793
+ this.botStates.clear();
2794
+ this.priceState.clear();
2795
+ this.indicatorState.clear();
2796
+ this.userPairs = [];
2797
+ this.userChains = [];
2798
+ }
2799
+ // ── Private Methods ────────────────────────────────────────────────────────
2800
+ emit(entry) {
2801
+ for (const listener of this.listeners) {
2802
+ listener(entry);
2803
+ }
2804
+ }
2805
+ getActivePairs(strategy) {
2806
+ return this.userPairs.length > 0 ? this.userPairs : strategy.preferredPairs;
2807
+ }
2808
+ getActiveChain() {
2809
+ const chains = this.userChains.length > 0 ? this.userChains : ["ethereum", "arbitrum", "bsc"];
2810
+ return pick3(chains);
2811
+ }
2812
+ getChainLabel(chainId) {
2813
+ const info = CHAIN_INFO[chainId];
2814
+ return info ? info.shortName : chainId;
2815
+ }
2816
+ initBotState(strategy) {
2817
+ const activePairs = this.getActivePairs(strategy);
2818
+ const pair = pick3(activePairs);
2819
+ const price = this.priceState.get(pair) || PAIR_PRICES[pair] || 5e4;
2820
+ const indicators = this.generateIndicators(strategy, price);
2821
+ this.indicatorState.set(strategy.id, indicators);
2822
+ this.botStates.set(strategy.id, {
2823
+ strategyId: strategy.id,
2824
+ strategyName: strategy.name,
2825
+ isRunning: true,
2826
+ currentPair: pair,
2827
+ currentPrice: price,
2828
+ indicators,
2829
+ openPositions: [],
2830
+ totalPnl: rand3(-50, 200),
2831
+ totalTrades: randInt3(5, 25),
2832
+ winRate: rand3(0.48, 0.68),
2833
+ lastSignal: "HOLD",
2834
+ lastSignalConfidence: 0
2835
+ });
2836
+ }
2837
+ scheduleCycle(strategy) {
2838
+ if (!this.running) return;
2839
+ const interval = rand3(strategy.scanIntervalMin, strategy.scanIntervalMax);
2840
+ const timer = setTimeout(() => {
2841
+ if (this.running) {
2842
+ this.runBotCycle(strategy);
2843
+ this.scheduleCycle(strategy);
2844
+ }
2845
+ }, interval);
2846
+ this.botTimers.set(strategy.id, timer);
2847
+ }
2848
+ async runBotCycle(strategy) {
2849
+ const state = this.botStates.get(strategy.id);
2850
+ if (!state) return;
2851
+ const activePairs = this.getActivePairs(strategy);
2852
+ const pair = pick3(activePairs);
2853
+ const price = this.simulatePrice(pair);
2854
+ const indicators = this.generateIndicators(strategy, price);
2855
+ this.indicatorState.set(strategy.id, indicators);
2856
+ state.currentPair = pair;
2857
+ state.currentPrice = price;
2858
+ state.indicators = indicators;
2859
+ const entries = [];
2860
+ let delay = 0;
2861
+ const chain = this.getActiveChain();
2862
+ const chainLabel = this.getChainLabel(chain);
2863
+ entries.push({
2864
+ entry: {
2865
+ strategyId: strategy.id,
2866
+ strategyName: strategy.shortName,
2867
+ type: "SCAN",
2868
+ message: `Scanning ${pair} on ${chainLabel} | Price: $${formatPrice(price)}`,
2869
+ data: { pair, chain, chainLabel },
2870
+ importance: "low"
2871
+ },
2872
+ delay
2873
+ });
2874
+ delay += rand3(800, 1500);
2875
+ const thinkingMessages = this.generateThinkingProcess(strategy, pair, price);
2876
+ for (const thinking of thinkingMessages) {
2877
+ entries.push({
2878
+ entry: {
2879
+ strategyId: strategy.id,
2880
+ strategyName: strategy.shortName,
2881
+ type: "THINKING",
2882
+ message: thinking,
2883
+ importance: "low"
2884
+ },
2885
+ delay
2886
+ });
2887
+ delay += rand3(600, 1200);
2888
+ }
2889
+ const indicatorParts = [];
2890
+ if (strategy.primaryIndicators.includes("RSI") || strategy.primaryIndicators.includes("MACD")) {
2891
+ indicatorParts.push(`RSI: ${indicators.rsi.toFixed(1)}`);
2892
+ }
2893
+ if (strategy.primaryIndicators.includes("MACD") || strategy.primaryIndicators.includes("RSI")) {
2894
+ indicatorParts.push(`MACD: ${indicators.macd.histogram > 0 ? "+" : ""}${indicators.macd.histogram.toFixed(3)}`);
2895
+ }
2896
+ if (strategy.primaryIndicators.includes("EMA")) {
2897
+ indicatorParts.push(`EMA: ${indicators.ema.short.toFixed(1)}/${indicators.ema.long.toFixed(1)}`);
2898
+ if (indicators.ema.crossover !== "none") {
2899
+ indicatorParts.push(`[${indicators.ema.crossover.toUpperCase()} CROSS]`);
2900
+ }
2901
+ }
2902
+ if (strategy.primaryIndicators.includes("Bollinger")) {
2903
+ indicatorParts.push(`BB: ${indicators.bollinger.position.toFixed(1)}% width=${indicators.bollinger.width.toFixed(2)}`);
2904
+ }
2905
+ if (strategy.primaryIndicators.includes("Volume")) {
2906
+ indicatorParts.push(`Vol: ${indicators.volume.ratio.toFixed(2)}x avg`);
2907
+ }
2908
+ entries.push({
2909
+ entry: {
2910
+ strategyId: strategy.id,
2911
+ strategyName: strategy.shortName,
2912
+ type: "INDICATOR",
2913
+ message: indicatorParts.join(" | "),
2914
+ data: { indicators },
2915
+ importance: "low"
2916
+ },
2917
+ delay
2918
+ });
2919
+ delay += rand3(800, 1500);
2920
+ if (Math.random() < 0.12) {
2921
+ const sentiment = Math.random() > 0.4 ? "Bullish" : "Bearish";
2922
+ entries.push({
2923
+ entry: {
2924
+ strategyId: strategy.id,
2925
+ strategyName: strategy.shortName,
2926
+ type: "NEWS",
2927
+ message: `[${sentiment}] ${pick3(NEWS_HEADLINES)}`,
2928
+ importance: "medium"
2929
+ },
2930
+ delay
2931
+ });
2932
+ delay += rand3(1e3, 1800);
2933
+ }
2934
+ if (Math.random() < 0.4) {
2935
+ const analysis = this.generateAnalysis(strategy, indicators, pair);
2936
+ entries.push({
2937
+ entry: {
2938
+ strategyId: strategy.id,
2939
+ strategyName: strategy.shortName,
2940
+ type: "ANALYSIS",
2941
+ message: analysis,
2942
+ importance: "medium"
2943
+ },
2944
+ delay
2945
+ });
2946
+ delay += rand3(1e3, 2e3);
2947
+ }
2948
+ const signal = this.evaluateSignal(strategy, indicators);
2949
+ state.lastSignal = signal.direction;
2950
+ state.lastSignalConfidence = signal.confidence;
2951
+ if (signal.direction !== "HOLD") {
2952
+ const strategyContext = this.generateStrategyContext(strategy, signal, indicators, pair);
2953
+ entries.push({
2954
+ entry: {
2955
+ strategyId: strategy.id,
2956
+ strategyName: strategy.shortName,
2957
+ type: "STRATEGY",
2958
+ message: strategyContext,
2959
+ data: {
2960
+ strategy: strategy.name,
2961
+ riskTolerance: strategy.riskTolerance,
2962
+ primaryIndicators: strategy.primaryIndicators,
2963
+ signal: signal.direction,
2964
+ confidence: signal.confidence
2965
+ },
2966
+ importance: "high"
2967
+ },
2968
+ delay
2969
+ });
2970
+ delay += rand3(1500, 2500);
2971
+ entries.push({
2972
+ entry: {
2973
+ strategyId: strategy.id,
2974
+ strategyName: strategy.shortName,
2975
+ type: "SIGNAL",
2976
+ message: `${signal.direction} signal detected | Confidence: ${(signal.confidence * 100).toFixed(1)}% | ${signal.reason}`,
2977
+ data: { signal },
2978
+ importance: "high"
2979
+ },
2980
+ delay
2981
+ });
2982
+ delay += rand3(1200, 2e3);
2983
+ const decision = this.makeTradeDecision(strategy, signal, state);
2984
+ if (decision.execute) {
2985
+ entries.push({
2986
+ entry: {
2987
+ strategyId: strategy.id,
2988
+ strategyName: strategy.shortName,
2989
+ type: "DECISION",
2990
+ message: `Execute ${signal.direction} | Size: ${decision.positionSize.toFixed(1)}% | Leverage: ${decision.leverage}x | Risk/Reward: 1:${decision.riskReward.toFixed(1)}`,
2991
+ data: {
2992
+ strategyName: strategy.name,
2993
+ strategyId: strategy.id,
2994
+ riskTolerance: strategy.riskTolerance,
2995
+ signalReason: signal.reason,
2996
+ confidence: signal.confidence
2997
+ },
2998
+ importance: "high"
2999
+ },
3000
+ delay
3001
+ });
3002
+ delay += rand3(1e3, 1800);
3003
+ const orderId = `ORD_${Date.now().toString(36).toUpperCase()}`;
3004
+ const orderPrice = signal.direction === "LONG" ? price * (1 - rand3(1e-4, 5e-4)) : price * (1 + rand3(1e-4, 5e-4));
3005
+ entries.push({
3006
+ entry: {
3007
+ strategyId: strategy.id,
3008
+ strategyName: strategy.shortName,
3009
+ type: "ORDER",
3010
+ message: `Submitting ${signal.direction} order | ${pair} @ $${formatPrice(orderPrice)} on ${chainLabel} | ID: ${orderId}`,
3011
+ data: {
3012
+ orderId,
3013
+ pair,
3014
+ side: signal.direction,
3015
+ price: orderPrice,
3016
+ leverage: decision.leverage,
3017
+ chain,
3018
+ chainLabel,
3019
+ strategyName: strategy.name,
3020
+ strategyContext,
3021
+ signalReason: signal.reason
3022
+ },
3023
+ importance: "high"
3024
+ },
3025
+ delay
3026
+ });
3027
+ delay += rand3(2e3, 4e3);
3028
+ const fillPrice = orderPrice * (1 + rand3(-3e-4, 3e-4));
3029
+ const slippage = Math.abs(fillPrice - orderPrice) / orderPrice * 100;
3030
+ entries.push({
3031
+ entry: {
3032
+ strategyId: strategy.id,
3033
+ strategyName: strategy.shortName,
3034
+ type: "FILLED",
3035
+ message: `Order FILLED | ${pair} ${signal.direction} @ $${formatPrice(fillPrice)} on ${chainLabel} | Slippage: ${slippage.toFixed(4)}% | ID: ${orderId}`,
3036
+ data: {
3037
+ orderId,
3038
+ fillPrice,
3039
+ slippage,
3040
+ chain,
3041
+ chainLabel,
3042
+ strategyName: strategy.name,
3043
+ executedBy: strategy.id
3044
+ },
3045
+ importance: "high"
3046
+ },
3047
+ delay
3048
+ });
3049
+ const position = {
3050
+ id: orderId,
3051
+ pair,
3052
+ side: signal.direction,
3053
+ entryPrice: fillPrice,
3054
+ currentPrice: price,
3055
+ size: decision.positionSize,
3056
+ leverage: decision.leverage,
3057
+ pnl: 0,
3058
+ pnlPercent: 0
3059
+ };
3060
+ state.openPositions = [...state.openPositions.slice(-2), position];
3061
+ state.totalTrades++;
3062
+ } else {
3063
+ entries.push({
3064
+ entry: {
3065
+ strategyId: strategy.id,
3066
+ strategyName: strategy.shortName,
3067
+ type: "DECISION",
3068
+ message: `SKIP - ${decision.reason}`,
3069
+ importance: "medium"
3070
+ },
3071
+ delay
3072
+ });
3073
+ }
3074
+ }
3075
+ if (state.openPositions.length > 0 && Math.random() < 0.5) {
3076
+ delay += rand3(1500, 2500);
3077
+ let totalPositionPnl = 0;
3078
+ const pnlParts = [];
3079
+ for (const pos of state.openPositions) {
3080
+ pos.currentPrice = this.simulatePrice(pos.pair);
3081
+ const priceDiff = pos.side === "LONG" ? (pos.currentPrice - pos.entryPrice) / pos.entryPrice : (pos.entryPrice - pos.currentPrice) / pos.entryPrice;
3082
+ pos.pnlPercent = priceDiff * pos.leverage * 100;
3083
+ pos.pnl = priceDiff * pos.leverage * pos.size;
3084
+ totalPositionPnl += pos.pnl;
3085
+ pnlParts.push(`${pos.pair} ${pos.side}: ${pos.pnlPercent >= 0 ? "+" : ""}${pos.pnlPercent.toFixed(2)}%`);
3086
+ }
3087
+ state.totalPnl += totalPositionPnl * rand3(0.01, 0.05);
3088
+ if (state.openPositions.length > 1 && Math.random() < 0.3) {
3089
+ const closed = state.openPositions.shift();
3090
+ const finalPnl = closed.pnlPercent;
3091
+ if (finalPnl > 0) {
3092
+ state.winRate = state.winRate * 0.95 + 0.05;
3093
+ } else {
3094
+ state.winRate = state.winRate * 0.95;
3095
+ }
3096
+ state.winRate = clamp(state.winRate, 0.35, 0.75);
3097
+ pnlParts.push(`CLOSED ${closed.pair}: ${finalPnl >= 0 ? "+" : ""}${finalPnl.toFixed(2)}%`);
3098
+ }
3099
+ entries.push({
3100
+ entry: {
3101
+ strategyId: strategy.id,
3102
+ strategyName: strategy.shortName,
3103
+ type: "PNL",
3104
+ message: pnlParts.join(" | "),
3105
+ data: { totalPnl: state.totalPnl, positions: state.openPositions.length },
3106
+ importance: "medium"
3107
+ },
3108
+ delay
3109
+ });
3110
+ }
3111
+ if (Math.random() < 0.2) {
3112
+ delay += rand3(1e3, 2e3);
3113
+ const exposure = state.openPositions.reduce((sum, p) => sum + p.size * p.leverage, 0);
3114
+ const maxDrawdown = rand3(2, 12);
3115
+ entries.push({
3116
+ entry: {
3117
+ strategyId: strategy.id,
3118
+ strategyName: strategy.shortName,
3119
+ type: "RISK",
3120
+ message: `Portfolio exposure: ${exposure.toFixed(1)}% | Max drawdown: ${maxDrawdown.toFixed(1)}% | Open positions: ${state.openPositions.length} | Win rate: ${(state.winRate * 100).toFixed(1)}%`,
3121
+ importance: exposure > 80 ? "high" : "low"
3122
+ },
3123
+ delay
3124
+ });
3125
+ }
3126
+ for (const { entry, delay: d } of entries) {
3127
+ setTimeout(() => {
3128
+ if (this.running) {
3129
+ this.emit({
3130
+ ...entry,
3131
+ id: genId3(),
3132
+ timestamp: Date.now()
3133
+ });
3134
+ }
3135
+ }, d);
3136
+ }
3137
+ }
3138
+ simulatePrice(pair) {
3139
+ const current = this.priceState.get(pair) || PAIR_PRICES[pair] || 5e4;
3140
+ const volatility = pair.includes("DOGE") ? 5e-3 : pair.includes("BTC") ? 2e-3 : 3e-3;
3141
+ const drift = rand3(-volatility, volatility);
3142
+ const newPrice = current * (1 + drift);
3143
+ this.priceState.set(pair, newPrice);
3144
+ return newPrice;
3145
+ }
3146
+ generateIndicators(strategy, price) {
3147
+ const prev = this.indicatorState.get(strategy.id);
3148
+ const prevRsi = prev?.rsi ?? strategy.rsiBias;
3149
+ const rsiMean = strategy.rsiBias;
3150
+ const rsiDrift = rand3(-8, 8);
3151
+ const rsiReversion = (rsiMean - prevRsi) * 0.15;
3152
+ const rsi = clamp(prevRsi + rsiDrift + rsiReversion, 8, 95);
3153
+ const macdBias = rsi > 65 ? 0.3 : rsi < 35 ? -0.3 : 0;
3154
+ const prevHist = prev?.macd.histogram ?? 0;
3155
+ const histogram = clamp(prevHist * 0.7 + rand3(-0.5, 0.5) + macdBias, -2, 2);
3156
+ const macdValue = histogram * rand3(0.8, 1.5);
3157
+ const macdSignal = macdValue - histogram;
3158
+ const prevShort = prev?.ema.short ?? price;
3159
+ const prevLong = prev?.ema.long ?? price;
3160
+ const emaShort = prevShort * 0.9 + price * 0.1;
3161
+ const emaLong = prevLong * 0.95 + price * 0.05;
3162
+ let crossover = "none";
3163
+ if (prevShort <= prevLong && emaShort > emaLong) crossover = "golden";
3164
+ else if (prevShort >= prevLong && emaShort < emaLong) crossover = "death";
3165
+ const bbMiddle = price;
3166
+ const bbWidth = price * rand3(0.01, 0.04);
3167
+ const bbUpper = bbMiddle + bbWidth;
3168
+ const bbLower = bbMiddle - bbWidth;
3169
+ const bbPosition = (price - bbLower) / (bbUpper - bbLower) * 100;
3170
+ const volRatio = rand3(0.3, 2.5);
3171
+ const volCurrent = rand3(1e5, 5e6);
3172
+ return {
3173
+ rsi,
3174
+ macd: { value: macdValue, signal: macdSignal, histogram },
3175
+ ema: { short: emaShort, long: emaLong, crossover },
3176
+ bollinger: { upper: bbUpper, middle: bbMiddle, lower: bbLower, width: bbWidth / price, position: bbPosition },
3177
+ volume: { current: volCurrent, average: volCurrent / volRatio, ratio: volRatio }
3178
+ };
3179
+ }
3180
+ generateThinkingProcess(strategy, pair, price) {
3181
+ const thoughts = [];
3182
+ const pairBase = pair.split("/")[0];
3183
+ const thinkingTemplates = [
3184
+ `Analyzing ${pairBase} market structure...`,
3185
+ `Checking ${strategy.primaryIndicators.join(", ")} confluence...`,
3186
+ `Evaluating risk parameters for ${strategy.riskTolerance} tolerance...`,
3187
+ `Scanning order book depth at $${formatPrice(price)}...`,
3188
+ `Cross-referencing with historical patterns...`,
3189
+ `Calculating optimal entry zone...`,
3190
+ `Assessing market sentiment indicators...`,
3191
+ `Monitoring whale activity on ${pairBase}...`,
3192
+ `Comparing momentum across timeframes...`,
3193
+ `Validating support/resistance levels...`
3194
+ ];
3195
+ const numThoughts = randInt3(1, 3);
3196
+ const shuffled = [...thinkingTemplates].sort(() => Math.random() - 0.5);
3197
+ for (let i = 0; i < numThoughts; i++) {
3198
+ thoughts.push(shuffled[i]);
3199
+ }
3200
+ return thoughts;
3201
+ }
3202
+ generateStrategyContext(strategy, signal, indicators, pair) {
3203
+ const contexts = [];
3204
+ contexts.push(`[${strategy.name}]`);
3205
+ const riskLevel = strategy.riskTolerance === "high" ? "aggressive" : strategy.riskTolerance === "low" ? "conservative" : "balanced";
3206
+ contexts.push(`Risk: ${riskLevel}`);
3207
+ if (indicators.rsi < 35 || indicators.rsi > 65) {
3208
+ contexts.push(`RSI ${indicators.rsi < 35 ? "oversold" : "overbought"} (${indicators.rsi.toFixed(1)})`);
3209
+ }
3210
+ if (indicators.ema.crossover !== "none") {
3211
+ contexts.push(`EMA ${indicators.ema.crossover} cross`);
3212
+ }
3213
+ if (Math.abs(indicators.macd.histogram) > 0.3) {
3214
+ contexts.push(`MACD ${indicators.macd.histogram > 0 ? "bullish" : "bearish"} momentum`);
3215
+ }
3216
+ const confLevel = signal.confidence > 0.7 ? "HIGH" : signal.confidence > 0.5 ? "MEDIUM" : "LOW";
3217
+ contexts.push(`Confidence: ${confLevel}`);
3218
+ return contexts.join(" | ");
3219
+ }
3220
+ generateAnalysis(strategy, indicators, pair) {
3221
+ const analyses = [];
3222
+ if (indicators.rsi > 70) {
3223
+ analyses.push(`RSI at ${indicators.rsi.toFixed(1)} - overbought territory, watching for reversal`);
3224
+ } else if (indicators.rsi < 30) {
3225
+ analyses.push(`RSI at ${indicators.rsi.toFixed(1)} - oversold, potential bounce setup`);
3226
+ } else if (indicators.rsi > 55) {
3227
+ analyses.push(`RSI trending bullish at ${indicators.rsi.toFixed(1)}`);
3228
+ } else {
3229
+ analyses.push(`RSI neutral at ${indicators.rsi.toFixed(1)}, no clear direction`);
3230
+ }
3231
+ if (indicators.macd.histogram > 0.5) {
3232
+ analyses.push("MACD histogram expanding positive - momentum building");
3233
+ } else if (indicators.macd.histogram < -0.5) {
3234
+ analyses.push("MACD histogram expanding negative - bearish pressure");
3235
+ }
3236
+ if (indicators.ema.crossover === "golden") {
3237
+ analyses.push("EMA golden cross detected - strong bullish signal");
3238
+ } else if (indicators.ema.crossover === "death") {
3239
+ analyses.push("EMA death cross detected - bearish warning");
3240
+ }
3241
+ if (indicators.bollinger.position > 90) {
3242
+ analyses.push(`Price near upper Bollinger band (${indicators.bollinger.position.toFixed(0)}%) - potential resistance`);
3243
+ } else if (indicators.bollinger.position < 10) {
3244
+ analyses.push(`Price near lower Bollinger band (${indicators.bollinger.position.toFixed(0)}%) - potential support`);
3245
+ }
3246
+ if (indicators.volume.ratio > 1.8) {
3247
+ analyses.push(`Volume spike ${indicators.volume.ratio.toFixed(1)}x average - high activity`);
3248
+ }
3249
+ return analyses.length > 0 ? analyses.join(" | ") : `${pair} consolidating - waiting for clearer setup`;
3250
+ }
3251
+ evaluateSignal(strategy, indicators) {
3252
+ let bullScore = 0;
3253
+ let bearScore = 0;
3254
+ const reasons = [];
3255
+ if (indicators.rsi < 30) {
3256
+ bullScore += 2;
3257
+ reasons.push("RSI oversold");
3258
+ } else if (indicators.rsi < 40) {
3259
+ bullScore += 1;
3260
+ reasons.push("RSI low");
3261
+ } else if (indicators.rsi > 70) {
3262
+ bearScore += 2;
3263
+ reasons.push("RSI overbought");
3264
+ } else if (indicators.rsi > 60) {
3265
+ bearScore += 1;
3266
+ reasons.push("RSI high");
3267
+ }
3268
+ if (indicators.macd.histogram > 0.3) {
3269
+ bullScore += 1.5;
3270
+ reasons.push("MACD bullish");
3271
+ } else if (indicators.macd.histogram < -0.3) {
3272
+ bearScore += 1.5;
3273
+ reasons.push("MACD bearish");
3274
+ }
3275
+ if (indicators.ema.crossover === "golden") {
3276
+ bullScore += 2.5;
3277
+ reasons.push("Golden cross");
3278
+ } else if (indicators.ema.crossover === "death") {
3279
+ bearScore += 2.5;
3280
+ reasons.push("Death cross");
3281
+ } else if (indicators.ema.short > indicators.ema.long) {
3282
+ bullScore += 0.5;
3283
+ } else {
3284
+ bearScore += 0.5;
3285
+ }
3286
+ if (indicators.bollinger.position < 15) {
3287
+ bullScore += 1;
3288
+ reasons.push("BB support");
3289
+ } else if (indicators.bollinger.position > 85) {
3290
+ bearScore += 1;
3291
+ reasons.push("BB resistance");
3292
+ }
3293
+ if (indicators.volume.ratio > 1.5) {
3294
+ if (bullScore > bearScore) bullScore += 1;
3295
+ else bearScore += 1;
3296
+ reasons.push("Volume confirms");
3297
+ }
3298
+ const netScore = bullScore - bearScore;
3299
+ const confidence = Math.min(Math.abs(netScore) / 6, 0.95);
3300
+ const threshold = strategy.riskTolerance === "high" ? 1.5 : strategy.riskTolerance === "medium" ? 2 : 2.5;
3301
+ if (Math.random() > strategy.tradeFrequency) {
3302
+ return { direction: "HOLD", confidence: 0, reason: "Cycle skip" };
3303
+ }
3304
+ if (netScore > threshold) {
3305
+ return { direction: "LONG", confidence, reason: reasons.slice(0, 3).join(", ") };
3306
+ } else if (netScore < -threshold) {
3307
+ return { direction: "SHORT", confidence, reason: reasons.slice(0, 3).join(", ") };
3308
+ }
3309
+ return { direction: "HOLD", confidence: 0, reason: "No clear signal" };
3310
+ }
3311
+ makeTradeDecision(strategy, signal, state) {
3312
+ if (state.openPositions.length >= 3) {
3313
+ return { execute: false, positionSize: 0, leverage: 0, riskReward: 0, reason: "Max positions reached (3)" };
3314
+ }
3315
+ const minConfidence = strategy.riskTolerance === "high" ? 0.3 : strategy.riskTolerance === "medium" ? 0.45 : 0.6;
3316
+ if (signal.confidence < minConfidence) {
3317
+ return { execute: false, positionSize: 0, leverage: 0, riskReward: 0, reason: `Confidence too low (${(signal.confidence * 100).toFixed(0)}% < ${(minConfidence * 100).toFixed(0)}%)` };
3318
+ }
3319
+ const positionSize = rand3(strategy.positionSizeMin, strategy.positionSizeMax);
3320
+ const leverage = randInt3(strategy.leverageMin, strategy.leverageMax);
3321
+ const riskReward = rand3(1.2, 3.5);
3322
+ return { execute: true, positionSize, leverage, riskReward, reason: "" };
3323
+ }
3324
+ };
3325
+ var botSimulationEngine = new BotSimulationEngine();
3326
+
1709
3327
  exports.OneEngineClient = OneEngineClient;
1710
3328
  exports.PriceService = PriceService;
3329
+ exports.STRATEGY_PERSONALITIES = STRATEGY_PERSONALITIES;
1711
3330
  exports.SupabaseService = SupabaseService;
1712
3331
  exports.UsageService = UsageService;
3332
+ exports.botSimulationEngine = botSimulationEngine;
1713
3333
  exports.createOneEngineClient = createOneEngineClient;
1714
3334
  exports.createSupabaseClient = createSupabaseClient;
1715
3335
  exports.createUsageService = createUsageService;
3336
+ exports.forexSimulationEngine = forexSimulationEngine;
1716
3337
  exports.getSupabaseClient = getSupabaseClient;
1717
3338
  exports.getUsageService = getUsageService;
1718
3339
  exports.priceService = priceService;