-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathindex.html
More file actions
355 lines (335 loc) · 27.7 KB
/
index.html
File metadata and controls
355 lines (335 loc) · 27.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
<!DOCTYPE html>
<html lang="en" data-theme="dark">
<head>
<title>AlgoArena ⚔️ Trading Strategy Game</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, interactive-widget=resizes-content">
<meta name="description" content="Test your trading skills in AlgoArena — the game where bots like S/R Hunter, Trend Trader, and Pattern Sniper battle real-time markets. Can you beat them on the leaderboard?">
<meta name="author" content="Michael Schwartz">
<meta name="mobile-web-app-capable" content="yes">
<meta name="application-name" content="AlgoArena ⚔️ Trading Strategy Game">
<meta name="theme-color" content="#0f172b">
<meta name="apple-mobile-web-app-title" content="AlgoArena ⚔️ Trading Strategy Game">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="msapplication-starturl" content="./index.html">
<meta name="msapplication-navbutton-color" content="#0f172b">
<meta property="og:url" content="https://michaelsboost.com/AlgoArena" />
<meta property="og:type" content="website" />
<meta property="og:title" content="AlgoArena ⚔️ Trading Strategy Game" />
<meta property="og:description" content="Test your trading skills in AlgoArena — the game where bots like S/R Hunter, Trend Trader, and Pattern Sniper battle real-time markets. Can you beat them on the leaderboard?" />
<link rel="manifest" href="manifest.json">
<link rel="shortcut icon" type="image/x-icon" href="imgs/logo.svg">
<link rel="icon" type="image/svg+xml" href="imgs/logo.svg" />
<link rel="apple-touch-icon" href="imgs/logo.svg">
<link rel="stylesheet" href="dist/bundle.css">
<script src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.1/dist/cdn.min.js" defer></script>
</head>
<body>
<div class="bg-slate-900 text-white min-h-screen" x-data="algoArena()" x-init="init()">
<div class="container mx-auto p-4 flex flex-col gap-6 h-full">
<!-- Header -->
<div class="flex flex-col md:flex-row justify-between items-start md:items-center gap-4">
<div class="w-full md:w-auto flex justify-between items-start md:items-center">
<a class="no-underline" href="https://github.com/michaelsboost/AlgoArena/" target="_blank">
<h1 class="text-3xl font-bold flex items-center gap-2">
<svg class="h-12 text-[#8b5cf6]" viewBox="0 0 575.85834 567.30548" xml:space="preserve" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
<g transform="translate(-224.07123,-228.69207)">
<path d="m 302.93728,228.80806 a 12.819,12.819 0 0 0 -6.12109,2.56446 12.819,12.819 0 0 0 -2.29492,17.98242 l 25.96484,33.56055 -18.35742,14.20117 c -5.52598,4.27506 -6.5329,12.16543 -2.25781,17.6914 l 106.05859,137.08985 c 4.2751,5.52596 12.16542,6.53293 17.69141,2.25781 l 18.35547,-14.20117 46.91015,60.63476 16.20508,-20.94922 -42.83789,-55.37304 19.92383,-15.41406 c 5.52602,-4.27513 6.5329,-12.16546 2.25781,-17.69141 L 378.37869,254.07174 c -4.27513,-5.52601 -12.16543,-6.53289 -17.69141,-2.25782 l -19.92578,15.41407 -25.96289,-33.5586 a 12.819,12.819 0 0 0 -11.86133,-4.86133 z m 421.37891,0 a 12.819,12.819 0 0 0 -11.86133,4.86133 l -25.96289,33.5586 -19.92578,-15.41407 c -5.52598,-4.2751 -13.41628,-3.2682 -17.69141,2.25782 L 542.81814,391.16158 c -4.27509,5.52598 -3.26821,13.41627 2.25782,17.69141 l 19.92382,15.41406 -112.71289,145.69336 a 12.819,12.819 0 0 0 2.29493,17.98242 12.819,12.819 0 0 0 17.98242,-2.29492 l 112.71289,-145.69336 18.35547,14.20117 c 5.52599,4.27513 13.4163,3.26819 17.6914,-2.25781 L 727.3826,314.80806 c 4.2751,-5.526 3.26819,-13.41631 -2.25782,-17.6914 l -18.35742,-14.20117 25.96485,-33.56055 a 12.819,12.819 0 0 0 -2.29493,-17.98242 12.819,12.819 0 0 0 -6.12109,-2.56446 z m -357.91406,41.32618 c 1.37667,-0.0897 2.76841,0.48809 3.67969,1.66601 l 95.11328,122.94141 c 1.45803,1.88466 1.11318,4.57515 -0.77149,6.0332 l -44.16406,34.16602 c -1.88466,1.45802 -4.57517,1.11513 -6.0332,-0.76954 l -95.11133,-122.9414 c -1.45804,-1.88467 -1.11513,-4.57517 0.76953,-6.0332 l 44.16406,-34.16797 c 0.70674,-0.54677 1.52752,-0.8407 2.35352,-0.89453 z m 294.45117,0.002 c 0.826,0.0538 1.64481,0.34581 2.35156,0.89258 l 44.16406,34.16797 c 1.88467,1.45802 2.22953,4.14853 0.77149,6.0332 l -95.11328,122.9414 c -1.45805,1.88467 -4.14854,2.22756 -6.03321,0.76954 l -44.16406,-34.16602 c -1.88466,-1.45805 -2.22758,-4.14854 -0.76953,-6.0332 L 657.17166,271.8003 c 0.91128,-1.17791 2.30497,-1.75376 3.68164,-1.66406 z m 48.43945,151.86133 c -6.66983,0 -10.90554,10.60841 -6.47656,16.2207 1.18098,1.4965 6.30623,5.16978 11.39063,8.16211 30.39269,17.88706 44.65625,35.627 44.65625,55.54101 0,26.65317 -30.38574,53.3053 -83.22852,73.00196 -137.13216,51.11471 -368.90982,20.15053 -405.50977,-54.73047 -3.65744,-7.48289 -3.76171,-8.00168 -3.76171,-18.74805 0,-10.79497 0.0901,-11.23156 3.82812,-18.79492 6.35158,-12.85155 19.47253,-24.73625 40.46875,-36.6543 12.20904,-6.93019 14.89681,-12.07003 10.27344,-19.65234 -3.463,-5.67926 -6.61347,-5.45579 -20.47461,1.46094 -51.39663,25.64694 -74.51394,50.86174 -76.27539,83.19336 -1.23684,22.70222 7.72369,42.23762 28.53711,62.21484 44.64685,42.85314 130.7584,70.39161 235.14258,75.19727 15.45027,0.71131 65.35049,-0.47549 80.63867,-1.91797 71.79409,-6.77399 130.29309,-24.09406 174.90234,-51.78321 23.08596,-14.32953 41.31126,-32.42592 49.9082,-49.55664 6.2242,-12.40262 8.42654,-32.47245 5.01368,-45.69336 -5.73957,-22.23409 -22.44209,-41.34448 -51.63477,-59.07617 -12.35421,-7.50398 -34.48874,-18.38476 -37.39844,-18.38476 z m -170.92578,100.65429 -16.20703,20.94922 32.5293,42.04688 a 12.819,12.819 0 0 0 17.98242,2.29492 12.819,12.819 0 0 0 2.29492,-17.98242 z m 260.38477,44.64649 c -0.0543,-0.02 -0.11176,0.0205 -0.17188,0.11523 -3.99471,6.29332 -14.52237,18.09326 -21.78906,24.42188 -17.28448,15.05311 -47.24085,32.80006 -73.42773,43.5 -37.80794,15.44826 -84.39442,25.9351 -137,30.83984 -18.62428,1.73649 -84.35223,1.75284 -103,0.0254 -43.98805,-4.07487 -73.57198,-9.31539 -108.5,-19.2207 -57.57045,-16.3265 -108.45103,-47.44873 -129.08594,-78.95508 -1.45992,-2.22906 -1.59596,2.10082 -1.68946,54.02539 -0.0559,31.04603 0.32293,59.59727 0.8418,63.44727 1.64405,12.19898 10.14955,25.88641 23.4336,37.71093 4.47918,3.98707 18.43336,13.78907 19.63085,13.78907 0.42615,0 0.90886,-16.08754 1.07227,-35.75 l 0.29688,-35.75 2.88671,-5.20899 c 4.27684,-7.71768 9.13306,-10.677 18.27539,-11.13867 6.37205,-0.32178 8.0932,-0.0178 12.72852,2.25 6.95408,3.40233 13.93217,10.94271 17.92578,19.37305 l 3.1836,6.72461 0.29882,44.70703 0.29688,44.70898 15.20312,4.97461 c 12.29337,4.02251 37.86935,11.10938 40.09375,11.10938 0.27966,0 0.64358,-14.96254 0.8086,-33.25 l 0.29883,-33.25 3.10546,-5.5 c 4.05428,-7.18431 9.24102,-10.81395 17.45704,-12.21094 5.33502,-0.90714 7.39111,-0.81624 12.00195,0.53125 9.98367,2.91767 18.29464,11.11032 20.94336,20.64453 0.55538,1.99914 0.98528,18.63043 0.98828,38.28516 0.003,19.11246 0.34141,34.78683 0.75391,34.83203 0.41248,0.0452 6.6,0.66204 13.75,1.37109 7.14998,0.70904 16.0375,1.34717 19.75,1.41797 l 6.75,0.12891 v -31.68555 c 0,-35.46192 0.51563,-39.2212 6.50195,-47.46875 7.24069,-9.97578 16.74296,-14.23976 30.48242,-13.68164 13.49027,0.548 22.71596,6.26097 29.08594,18.00976 l 3.42969,6.32618 0.31054,34.25 0.31055,34.25 5.68945,-0.004 c 5.97255,-0.004 26.37894,-1.63326 31.93946,-2.55078 l 3.25,-0.53711 v -34.77148 c 0,-40.08484 0.26954,-41.88402 7.48046,-49.9043 10.86765,-12.08744 29.43213,-13.37450 40.03125,-2.77539 7.06506,7.06505 7.48829,9.68679 7.48829,46.22461 0,17.22514 0.25141,31.31836 0.55859,31.31836 2.26731,0 27.71538,-7.04244 40.14453,-11.10938 l 15.20313,-4.97461 0.29687,-44.70898 0.29688,-44.70703 3.18554,-6.72461 c 3.98268,-8.4072 10.9681,-15.97029 17.86719,-19.34571 6.74237,-3.29873 15.41278,-3.50946 21.27734,-0.51757 4.98878,2.54507 10.50847,8.92993 11.98828,13.86914 0.74739,2.49456 1.16199,15.53496 1.20899,38.00781 0.0393,18.81552 0.33571,34.21094 0.66016,34.21094 0.32442,0 4.39259,-2.52944 9.03906,-5.6211 14.77575,-9.83145 27.14265,-23.98605 32.45703,-37.14453 l 2.31641,-5.73437 0.21679,-61.5 c 0.16058,-45.57967 -0.0132,-59.39861 -0.82812,-59.69922 z"></path>
</g>
</svg>
<span class="gradient-text">AlgoArena</span>
</h1>
<p class="text-sm text-slate-400 mt-1">Strategy Showdown - Prove your trading edge</p>
</a>
</div>
<!-- Arena Controls -->
<div class="w-full md:w-auto flex items-center gap-4">
<div class="flex gap-2">
<button @click="toggleArena()" class="border-0 bg-transparent shadow-none">
<svg class="h-12 transition-all duration-300" :class="arenaActive ?
'text-green-400 drop-shadow-[0_0_10px_rgba(74,222,128,0.8)]' :
'text-[#8b5cf6] drop-shadow-[0_0_6px_rgba(139,92,246,0.5)]'" viewBox="0 0 24 24">
<path fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 2v10m6.4-5.4a9 9 0 1 1-12.77.04"></path>
</svg>
</button>
</div>
</div>
</div>
<!-- Strategy Selection -->
<details class="hidden trading-card rounded-xl p-5">
<summary class="font-bold">🤖 Select Combatants</summary>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<!-- Strategy Cards -->
<template x-for="strategy in allStrategies" :key="strategy.id">
<div class="strategy-card p-4 rounded-lg border border-solid border-slate-600" :class="{ 'bg-purple-900/20': strategy.id === 'human' }">
<div class="flex items-center gap-3 mb-2">
<input type="checkbox" x-model="selectedStrategies" :value="strategy.id" :disabled="strategy.id === 'human'" class="strategy-checkbox">
<div class="relative group flex-1">
<h3 class="font-bold" x-text="strategy.name"></h3>
<div class="absolute hidden group-hover:block z-10 bg-slate-800 p-2 rounded-lg border border-slate-600 text-xs w-64 mt-1">
<div x-text="getStrategyDescription(strategy.id)"></div>
</div>
</div>
</div>
<p class="text-sm text-slate-400" x-text="strategy.description"></p>
<div class="mt-2 text-xs text-slate-500">
Win Rate: <span x-text="getWinRate(strategy.id) + '%'">-</span>
</div>
</div>
</template>
</div>
</details>
<!-- Market Regime Indicator -->
<div class="trading-card rounded-xl p-4">
<div class="flex items-center justify-between overflow-auto">
<div class="flex items-center gap-3">
<span class="text-sm text-slate-400">Market Regime:</span>
<span class="font-bold" :class="marketRegime.className" x-text="marketRegime.text"></span>
</div>
<div class="flex items-center gap-4 text-sm text-slate-400">
<span>Volatility: <span x-text="currentVolatility.toFixed(2)"></span></span>
<span>Trend: <span x-text="(trendSlope(20) * 100).toFixed(1)"></span></span>
<span>ATR(14): <span x-text="atr(14).toFixed(2)"></span></span>
</div>
</div>
</div>
<!-- Main Arena -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Chart Column -->
<div class="lg:col-span-2 trading-card rounded-xl p-5">
<div class="flex justify-between items-center mb-4">
<h2 class="font-bold text-lg">Arena</h2>
<div class="flex items-center gap-2">
<span class="inline-block font-mono px-3 py-1 text-sm">
P&L: <span :class="(humanStats.balance - 150000) > 0 ? 'text-green-400' : (humanStats.balance - 150000) < 0 ? 'text-red-400' : 'text-current'" x-text="'$' + profitLoss">
</span>
</span>
<span class="inline-block font-mono px-3 py-1 text-sm">
Open: <span :class="openPnl > 0 ? 'text-green-400' : openPnl < 0 ? 'text-red-400' : 'text-current'" x-text="'$' + formattedOpenPnl">
</span>
</span>
<span class="inline-block font-mono px-3 py-1 text-sm">Lots: <span x-text="Number(totalOpenLots)"></span></span>
</div>
</div>
<!-- Chart Canvas -->
<div class="relative">
<canvas id="chart" class="w-full h-[400px]" x-ref="chartCanvas" @mousedown="handleChartDown($event)" @touchstart="handleChartDown($event)" @mousemove="handleChartMove($event)" @touchmove="handleChartMove($event)" @mouseup="handleChartUpLeave()" @touchend="handleChartUpLeave()" @mouseleave="handleChartUpLeave()" @touchcancel="handleChartUpLeave()" @wheel="handleChartWheel($event)">
</canvas>
<div x-show="hasOpenPositions" class="bg-amber-900/30 border border-amber-500/50 rounded-lg px-4 py-2 my-4">
<div class="flex items-center gap-2 text-amber-300">
<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd"></path>
</svg>
<span class="text-sm">Close all positions to switch contracts</span>
</div>
</div>
</div>
<!-- Trading Controls -->
<div class="mt-6 grid grid-cols-3 gap-3">
<button @click="placeTrade('buy')" class="bg-green-600 hover:bg-green-700 text-white font-bold py-3 rounded-lg flex items-center justify-center gap-2 border-0">
<span>BUY</span>
<span class="text-xs opacity-80">(B)</span>
</button>
<button @click="placeTrade('sell')" class="bg-red-600 hover:bg-red-700 text-white font-bold py-3 rounded-lg flex items-center justify-center gap-2 border-0">
<span>SELL</span>
<span class="text-xs opacity-80">(S)</span>
</button>
<button @click="closeAll()" class="bg-amber-500 hover:bg-amber-600 text-white font-bold py-3 rounded-lg flex items-center justify-center gap-2 border-0">
<span>Close All</span>
<span class="text-xs opacity-80">(X)</span>
</button>
</div>
<!-- Trade Message -->
<div class="grid grid-cols-1 gap-4 my-4">
<div class="bg-amber-900/30 border border-amber-500/50 rounded-lg px-4 py-2" x-show="tradeMessage" x-text="tradeMessage"></div>
</div>
<!-- Contract Selection -->
<div class="mt-6 grid grid-cols-2 gap-4">
<div>
<label class="block text-sm text-slate-400 mb-1">Contract</label>
<div class="flex gap-2">
<template x-for="contract in contracts" :key="contract.id">
<label class="flex-1">
<input type="radio" x-model="currentContract" :value="contract.id" :disabled="hasOpenPositions" name="contract" class="peer hidden">
<div class="w-full h-full border border-solid border-blue-500/30
py-2 rounded-lg text-center
text-slate-300 peer-checked:text-blue-400
transition-all duration-200" :class="hasOpenPositions
? 'bg-slate-900 cursor-not-allowed opacity-50'
: 'bg-slate-800 hover:bg-slate-700 cursor-pointer'" x-text="contract.name">
</div>
</label>
</template>
</div>
</div>
<div>
<nav>
<label class="block text-sm text-slate-400 mb-1">Position Size</label>
<span class="text-sm text-slate-400" x-text="lotSize"></span>
</nav>
<!-- Lot Size Selection -->
<div class="lot-option w-full bg-slate-800 border border-slate-700 rounded-lg px-3 py-2 flex gap-2 flex-wrap justify-center text-sm">
<button @click="adjustLotSize(-1)" class="px-3 py-1 bg-gray-700 text-white rounded border-0">−</button>
<div class="flex flex-row items-center gap-1">
<template x-for="size in lotSizes" :key="size">
<label class="flex flex-col items-center gap-1">
<input type="radio" x-model="lotSize" :value="size" name="lot" class="form-radio">
<div x-text="size"></div>
</label>
</template>
</div>
<button @click="adjustLotSize(1)" class="px-3 py-1 bg-gray-700 text-white rounded border-0">+</button>
</div>
</div>
</div>
<!-- Risk Management -->
<div class="mt-6 grid grid-cols-2 gap-4">
<div>
<label class="block text-sm text-slate-400 mb-1">Stop Loss ($)</label>
<input x-model="stopLoss" type="number" class="w-full bg-slate-800 border border-slate-700 rounded-lg px-3 py-2">
</div>
<div>
<label class="block text-sm text-slate-400 mb-1">Take Profit ($)</label>
<input x-model="takeProfit" type="number" class="w-full bg-slate-800 border border-slate-700 rounded-lg px-3 py-2">
</div>
</div>
</div>
<!-- Leaderboard -->
<div class="trading-card rounded-xl p-5">
<h2 class="font-bold text-lg mb-4">🏆 Arena Leaderboard</h2>
<div class="space-y-3">
<template x-if="!arenaActive">
<div class="text-center py-8 text-slate-500">Start the arena to see results</div>
</template>
<template x-for="(participant, index) in leaderboard" :key="participant.id">
<div class="flex items-center justify-between p-3 rounded-lg bg-slate-800 border-l-4 relative" :style="`border-color: ${participant.color}`">
<!-- Open Position Indicator -->
<div x-show="participant.hasOpenPosition" class="absolute -left-1 top-1/2 transform -translate-y-1/2 w-2 h-2 rounded-full bg-green-400 animate-pulse"></div>
<div class="flex items-center gap-3">
<span class="text-lg font-bold" x-text="index + 1"></span>
<div>
<div class="font-bold" x-text="participant.name"></div>
<div class="text-xs text-slate-400" x-text="`${participant.trades} trades • ${participant.winRate}% win rate`"></div>
</div>
</div>
<div class="text-right">
<div class="font-mono text-sm" :class="participant.pnl >= 0 ? 'text-green-400' : 'text-red-400'" x-text="`${participant.pnl >= 0 ? '+' : ''}$${participant.pnl.toFixed(2)}`">
</div>
<!-- Show Open P&L if they have a position -->
<div x-show="participant.hasOpenPosition" class="font-mono text-xs" :class="participant.openPnl >= 0 ? 'text-green-300' : 'text-red-300'" x-text="`Open: ${participant.openPnl >= 0 ? '+' : ''}$${participant.openPnl.toFixed(2)}`">
</div>
<div class="font-mono text-xs text-slate-400" x-text="`$${participant.balance.toFixed(2)}`"></div>
</div>
</div>
</template>
</div>
<!-- Strategy Efficiency -->
<div class="mt-6 pt-4 border-t border-slate-700">
<h3 class="font-bold text-sm mb-3">📈 Strategy Efficiency</h3>
<div class="space-y-2 text-xs">
<template x-for="participant in strategyEfficiency" :key="participant.id">
<div class="flex justify-between items-center">
<span x-text="participant.name" :style="`color: ${participant.color}`"></span>
<div class="text-right">
<div x-text="`$${participant.efficiency} avg/trade`"></div>
<div class="text-slate-400" x-text="`${participant.frequency} trades/hr`"></div>
</div>
</div>
</template>
</div>
</div>
</div>
</div>
<!-- Strategy Performance Details -->
<details class="trading-card rounded-xl p-5">
<summary class="font-bold">📊 Strategy Performance</summary>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<template x-for="participant in performanceDetails" :key="participant.id">
<div class="p-4 rounded-lg bg-slate-800 border-l-4" :style="`border-color: ${participant.color}`">
<h3 class="font-bold mb-2" x-text="participant.name"></h3>
<div class="grid grid-cols-2 gap-2 text-sm">
<div class="text-slate-400">Trades:</div>
<div x-text="participant.trades"></div>
<div class="text-slate-400">Win Rate:</div>
<div x-text="`${participant.winRate}%`"></div>
<div class="text-slate-400">W/L:</div>
<div x-text="`${participant.wins}/${participant.losses}`"></div>
<div class="text-slate-400" x-show="participant.openPnl">Open PnL:</div>
<div class="font-mono" :class="participant.openPnl >= 0 ? 'text-green-400' : 'text-red-400'" x-text="`${participant.openPnl >= 0 ? '+' : ''}$${participant.openPnl.toFixed(2)}`" x-show="participant.openPnl">
</div>
<div class="text-slate-400">Total PnL:</div>
<div :class="participant.totalPnL >= 0 ? 'text-green-400' : 'text-red-400'" x-text="`$${participant.totalPnL.toFixed(2)}`"></div>
<div class="text-slate-400">Avg Win:</div>
<div class="text-green-400" x-text="`$${participant.avgWin.toFixed(2)}`"></div>
<div class="text-slate-400">Avg Loss:</div>
<div class="text-red-400" x-text="`$${participant.avgLoss.toFixed(2)}`"></div>
</div>
</div>
</template>
</div>
</details>
<!-- Trade History -->
<details class="trading-card rounded-xl p-5">
<summary class="font-bold">📋 Trade History</summary>
<div class="overflow-x-auto">
<table class="w-full text-sm">
<thead>
<tr class="text-left border-b border-slate-700">
<th class="pb-2 text-slate-400">Time</th>
<th class="pb-2 text-slate-400">Type</th>
<th class="pb-2 text-slate-400">Size</th>
<th class="pb-2 text-slate-400">Entry</th>
<th class="pb-2 text-slate-400">Exit</th>
<th class="pb-2 text-slate-400">P&L</th>
<th class="pb-2 text-slate-400">Duration</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-700">
<template x-if="humanStats.trades.length === 0">
<tr>
<td colspan="7" class="py-8 text-center text-slate-500">No trades yet</td>
</tr>
</template>
<template x-for="trade in humanStats.trades.slice().reverse()" :key="trade.timestamp">
<tr>
<td class="py-2" x-text="new Date(trade.timestamp).toLocaleTimeString()"></td>
<td class="py-2" :class="trade.type === 'buy' ? 'text-green-400' : 'text-red-400'" x-text="trade.type"></td>
<td class="py-2" x-text="trade.qty"></td>
<td class="py-2" x-text="trade.entry.toFixed(2)"></td>
<td class="py-2" x-text="trade.exit?.toFixed(2) || '-'"></td>
<td class="py-2" :class="trade.pnl >= 0 ? 'text-green-400' : 'text-red-400'" x-text="trade.pnl.toFixed(2)"></td>
<td class="py-2" x-text="trade.duration ? (trade.duration / 1000).toFixed(1) + 's' : '-'"></td>
</tr>
</template>
</tbody>
</table>
</div>
</details>
</div>
</div>
<script src="dist/script.js" ></script>
<script src="https://storage.googleapis.com/workbox-cdn/releases/6.4.1/workbox-sw.js"></script>
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('./sw.js').then(reg => {
reg.addEventListener('updatefound', () => {
const newSW = reg.installing;
newSW.addEventListener('statechange', () => {
if (newSW.state === 'installed' && navigator.serviceWorker.controller) {
// Notify the user and reload if they confirm
if (confirm('A new version is available. Reload now?')) {
window.location.reload();
}
}
});
});
});
// Ensure immediate activation of a new service worker
navigator.serviceWorker.ready.then(registration => {
registration.active.postMessage({ type: 'SKIP_WAITING' });
});
}
</script>
</body>
</html>