Automated trading bot for Deriv with Rise/Fall strategy and martingale money management
Size
36.3 KB
Version
1.2.2
Created
Dec 26, 2025
Updated
about 1 month ago
1// ==UserScript==
2// @name Deriv Rise/Fall Trading Bot with Martingale
3// @description Automated trading bot for Deriv with Rise/Fall strategy and martingale money management
4// @version 1.2.2
5// @match https://*.app.deriv.com/*
6// @icon https://app.deriv.com/favicon.ico
7// ==/UserScript==
8(function() {
9 'use strict';
10
11 // Bot Configuration
12 const CONFIG = {
13 initialStake: 1.00,
14 tickDuration: 1,
15 martingaleMultiplier: 2,
16 maxMartingaleLevel: 5,
17 tradeDelay: 3000, // Delay between trades in milliseconds
18 predictionStrategy: 'advanced', // Changed to 'advanced'
19 analysisWindow: 30, // Increased for better analysis
20 minConfidenceScore: 40, // Lowered from 60 to 40 for more trades
21 rsiPeriod: 14,
22 emaPeriod: 9
23 };
24
25 // Bot State
26 let botState = {
27 isRunning: false,
28 currentStake: CONFIG.initialStake,
29 martingaleLevel: 0,
30 totalTrades: 0,
31 winCount: 0,
32 lossCount: 0,
33 totalProfit: 0,
34 lastTradeResult: null,
35 tradeHistory: [],
36 priceHistory: [] // Store price history for analysis
37 };
38
39 // Utility function to wait
40 function wait(ms) {
41 return new Promise(resolve => setTimeout(resolve, ms));
42 }
43
44 // Debounce function for MutationObserver
45 function debounce(func, wait) {
46 let timeout;
47 return function executedFunction(...args) {
48 const later = () => {
49 clearTimeout(timeout);
50 func(...args);
51 };
52 clearTimeout(timeout);
53 timeout = setTimeout(later, wait);
54 };
55 }
56
57 // Set stake amount
58 async function setStakeAmount(amount) {
59 const stakeInput = document.querySelector('input#dt_amount_input[name="amount"]');
60 if (stakeInput) {
61 stakeInput.value = amount.toFixed(2);
62 stakeInput.dispatchEvent(new Event('input', { bubbles: true }));
63 stakeInput.dispatchEvent(new Event('change', { bubbles: true }));
64 console.log(`Stake set to: $${amount.toFixed(2)}`);
65 await wait(500);
66 return true;
67 }
68 console.error('Stake input not found');
69 return false;
70 }
71
72 // Set duration to 1 tick
73 async function setDuration() {
74 const durationInput = document.querySelector('input#dt_duration_range_input[name="duration"]');
75 if (durationInput) {
76 durationInput.value = '1';
77 durationInput.dispatchEvent(new Event('input', { bubbles: true }));
78 durationInput.dispatchEvent(new Event('change', { bubbles: true }));
79 console.log('Duration set to: 1 tick');
80 await wait(500);
81 return true;
82 }
83 console.error('Duration input not found');
84 return false;
85 }
86
87 // Get current price from chart
88 function getCurrentPrice() {
89 try {
90 const priceElement = document.querySelector('.cq-current-price');
91 if (priceElement) {
92 const price = parseFloat(priceElement.textContent.replace(/,/g, ''));
93 return isNaN(price) ? null : price;
94 }
95 } catch (error) {
96 console.error('Error getting current price:', error);
97 }
98 return null;
99 }
100
101 // Get account balance
102 function getAccountBalance() {
103 try {
104 const balanceElement = document.querySelector('[class*="balance"]');
105 if (balanceElement) {
106 const balanceText = balanceElement.textContent.replace(/[^0-9.]/g, '');
107 const balance = parseFloat(balanceText);
108 return isNaN(balance) ? null : balance;
109 }
110 } catch (error) {
111 console.error('Error getting balance:', error);
112 }
113 return null;
114 }
115
116 // Update price history
117 function updatePriceHistory(price) {
118 if (price !== null) {
119 botState.priceHistory.push(price);
120 // Keep only last analysisWindow + 10 prices
121 if (botState.priceHistory.length > CONFIG.analysisWindow + 10) {
122 botState.priceHistory.shift();
123 }
124 }
125 }
126
127 // Calculate Simple Moving Average
128 function calculateSMA(data, period) {
129 if (data.length < period) return null;
130 const slice = data.slice(-period);
131 const sum = slice.reduce((a, b) => a + b, 0);
132 return sum / period;
133 }
134
135 // Calculate momentum (rate of change)
136 function calculateMomentum(data, period = 5) {
137 if (data.length < period + 1) return 0;
138 const current = data[data.length - 1];
139 const past = data[data.length - period - 1];
140 return ((current - past) / past) * 100;
141 }
142
143 // Calculate volume proxy (price volatility)
144 function calculateVolatility(data, period = 10) {
145 if (data.length < period) return 0;
146 const slice = data.slice(-period);
147 const mean = slice.reduce((a, b) => a + b, 0) / period;
148 const variance = slice.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / period;
149 return Math.sqrt(variance);
150 }
151
152 // Determine trend direction
153 function analyzeTrend(data) {
154 if (data.length < 10) return 'neutral';
155
156 const shortMA = calculateSMA(data, 5);
157 const longMA = calculateSMA(data, 10);
158
159 if (shortMA === null || longMA === null) return 'neutral';
160
161 if (shortMA > longMA) return 'bullish';
162 if (shortMA < longMA) return 'bearish';
163 return 'neutral';
164 }
165
166 // Calculate Exponential Moving Average (more responsive than SMA)
167 function calculateEMA(data, period) {
168 if (data.length < period) return null;
169
170 const multiplier = 2 / (period + 1);
171 let ema = data.slice(0, period).reduce((a, b) => a + b, 0) / period;
172
173 for (let i = period; i < data.length; i++) {
174 ema = (data[i] - ema) * multiplier + ema;
175 }
176
177 return ema;
178 }
179
180 // Calculate RSI (Relative Strength Index)
181 function calculateRSI(data, period = 14) {
182 if (data.length < period + 1) return 50; // Neutral
183
184 let gains = 0;
185 let losses = 0;
186
187 for (let i = data.length - period; i < data.length; i++) {
188 const change = data[i] - data[i - 1];
189 if (change > 0) {
190 gains += change;
191 } else {
192 losses -= change;
193 }
194 }
195
196 const avgGain = gains / period;
197 const avgLoss = losses / period;
198
199 if (avgLoss === 0) return 100;
200
201 const rs = avgGain / avgLoss;
202 const rsi = 100 - (100 / (1 + rs));
203
204 return rsi;
205 }
206
207 // Calculate MACD (Moving Average Convergence Divergence)
208 function calculateMACD(data) {
209 if (data.length < 26) return { macd: 0, signal: 0, histogram: 0 };
210
211 const ema12 = calculateEMA(data, 12);
212 const ema26 = calculateEMA(data, 26);
213
214 if (ema12 === null || ema26 === null) return { macd: 0, signal: 0, histogram: 0 };
215
216 const macd = ema12 - ema26;
217
218 // For simplicity, using a basic signal line
219 const signal = macd * 0.8; // Approximation
220 const histogram = macd - signal;
221
222 return { macd, signal, histogram };
223 }
224
225 // Calculate Bollinger Bands
226 function calculateBollingerBands(data, period = 20, stdDev = 2) {
227 if (data.length < period) return null;
228
229 const sma = calculateSMA(data, period);
230 if (sma === null) return null;
231
232 const slice = data.slice(-period);
233 const variance = slice.reduce((sum, val) => sum + Math.pow(val - sma, 2), 0) / period;
234 const std = Math.sqrt(variance);
235
236 return {
237 upper: sma + (std * stdDev),
238 middle: sma,
239 lower: sma - (std * stdDev),
240 bandwidth: (std * stdDev * 2) / sma
241 };
242 }
243
244 // Detect support and resistance levels
245 function findSupportResistance(data, lookback = 10) {
246 if (data.length < lookback) return { support: null, resistance: null };
247
248 const recent = data.slice(-lookback);
249 const support = Math.min(...recent);
250 const resistance = Math.max(...recent);
251
252 return { support, resistance };
253 }
254
255 // Advanced prediction with multiple indicators
256 function predictNextMove() {
257 const prices = botState.priceHistory;
258
259 // Need at least 30 price points for reliable analysis
260 if (prices.length < 30) {
261 console.log('📊 Collecting more price data... (' + prices.length + '/30)');
262 return Math.random() > 0.5 ? 'rise' : 'fall';
263 }
264
265 const currentPrice = prices[prices.length - 1];
266
267 // Calculate all indicators
268 const rsi = calculateRSI(prices, CONFIG.rsiPeriod);
269 const macd = calculateMACD(prices);
270 const bb = calculateBollingerBands(prices, 20, 2);
271 const ema9 = calculateEMA(prices, 9);
272 const ema21 = calculateEMA(prices, 21);
273 const momentum = calculateMomentum(prices, 5);
274 const volatility = calculateVolatility(prices, 10);
275 const { support, resistance } = findSupportResistance(prices, 15);
276
277 // Scoring system (0-100)
278 let bullishScore = 0;
279 let bearishScore = 0;
280
281 // 1. RSI Analysis (20 points)
282 if (rsi < 30) {
283 bullishScore += 20; // Oversold - likely to rise
284 console.log('📈 RSI Oversold: ' + rsi.toFixed(2) + ' (+20 bullish)');
285 } else if (rsi > 70) {
286 bearishScore += 20; // Overbought - likely to fall
287 console.log('📉 RSI Overbought: ' + rsi.toFixed(2) + ' (+20 bearish)');
288 } else if (rsi > 50 && rsi < 70) {
289 bullishScore += 10; // Bullish momentum
290 } else if (rsi < 50 && rsi > 30) {
291 bearishScore += 10; // Bearish momentum
292 }
293
294 // 2. MACD Analysis (20 points)
295 if (macd.histogram > 0 && macd.macd > macd.signal) {
296 bullishScore += 20;
297 console.log('📈 MACD Bullish Crossover (+20 bullish)');
298 } else if (macd.histogram < 0 && macd.macd < macd.signal) {
299 bearishScore += 20;
300 console.log('📉 MACD Bearish Crossover (+20 bearish)');
301 }
302
303 // 3. Bollinger Bands (20 points)
304 if (bb && currentPrice < bb.lower) {
305 bullishScore += 20; // Price at lower band - likely to bounce up
306 console.log('📈 Price at Lower BB (+20 bullish)');
307 } else if (bb && currentPrice > bb.upper) {
308 bearishScore += 20; // Price at upper band - likely to fall
309 console.log('📉 Price at Upper BB (+20 bearish)');
310 } else if (bb && currentPrice > bb.middle) {
311 bullishScore += 5; // Above middle
312 } else if (bb && currentPrice < bb.middle) {
313 bearishScore += 5; // Below middle
314 }
315
316 // 4. EMA Crossover (20 points)
317 if (ema9 !== null && ema21 !== null) {
318 if (ema9 > ema21 && currentPrice > ema9) {
319 bullishScore += 20; // Strong uptrend
320 console.log('📈 EMA Golden Cross (+20 bullish)');
321 } else if (ema9 < ema21 && currentPrice < ema9) {
322 bearishScore += 20; // Strong downtrend
323 console.log('📉 EMA Death Cross (+20 bearish)');
324 }
325 }
326
327 // 5. Momentum (10 points)
328 if (momentum > 0.1) {
329 bullishScore += 10;
330 } else if (momentum < -0.1) {
331 bearishScore += 10;
332 }
333
334 // 6. Support/Resistance (10 points)
335 if (support && resistance) {
336 const distanceToSupport = ((currentPrice - support) / support) * 100;
337 const distanceToResistance = ((resistance - currentPrice) / currentPrice) * 100;
338
339 if (distanceToSupport < 0.5) {
340 bullishScore += 10; // Near support - likely to bounce
341 console.log('📈 Near Support Level (+10 bullish)');
342 } else if (distanceToResistance < 0.5) {
343 bearishScore += 10; // Near resistance - likely to fall
344 console.log('📉 Near Resistance Level (+10 bearish)');
345 }
346 }
347
348 // Calculate final scores
349 const totalBullish = bullishScore;
350 const totalBearish = bearishScore;
351 const confidence = Math.abs(totalBullish - totalBearish);
352
353 console.log('\n📊 ANALYSIS SUMMARY:');
354 console.log(` RSI: ${rsi.toFixed(2)} | MACD: ${macd.histogram.toFixed(4)}`);
355 console.log(` Price: ${currentPrice.toFixed(2)} | BB: [${bb?.lower.toFixed(2)}, ${bb?.upper.toFixed(2)}]`);
356 console.log(` Momentum: ${momentum.toFixed(4)}% | Volatility: ${volatility.toFixed(2)}`);
357 console.log(` Bullish Score: ${totalBullish} | Bearish Score: ${totalBearish}`);
358 console.log(` Confidence: ${confidence}%\n`);
359
360 // Only trade if confidence is high enough
361 if (confidence < CONFIG.minConfidenceScore) {
362 console.log(`⚠️ Low confidence (${confidence}%), skipping trade...`);
363 return null; // Skip this trade
364 }
365
366 // Make prediction
367 const prediction = totalBullish > totalBearish ? 'rise' : 'fall';
368 console.log(`🎯 PREDICTION: ${prediction.toUpperCase()} (Confidence: ${confidence}%)`);
369
370 return prediction;
371 }
372
373 // Execute trade
374 async function executeTrade(direction) {
375 const buttonId = direction === 'rise' ? 'dt_purchase_call_button' : 'dt_purchase_put_button';
376 const tradeButton = document.querySelector(`button#${buttonId}`);
377
378 if (tradeButton && !tradeButton.disabled) {
379 // Get balance AND drawer state before trade
380 botState.balanceBeforeTrade = getAccountBalance();
381
382 // Get drawer content BEFORE trade to establish baseline
383 const drawerBefore = document.querySelector('.positions-drawer__body');
384 botState.drawerBeforeTrade = drawerBefore ? drawerBefore.textContent : '';
385
386 console.log(`💵 Balance before trade: $${botState.balanceBeforeTrade?.toFixed(2) || 'unknown'}`);
387 console.log(`Executing ${direction.toUpperCase()} trade with stake: $${botState.currentStake.toFixed(2)}`);
388 tradeButton.click();
389 botState.totalTrades++;
390 updateUI();
391 return true;
392 }
393 console.error(`${direction} button not found or disabled`);
394 return false;
395 }
396
397 // Monitor trade result - WATCH FOR NEW CLOSED TRADES
398 function monitorTradeResult() {
399 return new Promise((resolve) => {
400 let checkCount = 0;
401 const maxChecks = 30; // 15 seconds max (1-tick trades are fast)
402 const drawerBaseline = botState.drawerBeforeTrade || '';
403
404 console.log('🔍 Monitoring for NEW trade result...');
405 console.log(`📋 Baseline drawer length: ${drawerBaseline.length} chars`);
406
407 const checkInterval = setInterval(() => {
408 checkCount++;
409
410 const positionsDrawer = document.querySelector('.positions-drawer__body');
411
412 if (!positionsDrawer) {
413 if (checkCount >= maxChecks) {
414 clearInterval(checkInterval);
415 console.error('❌ Drawer not found - LOSS');
416 resolve(false);
417 }
418 return;
419 }
420
421 const drawerContent = positionsDrawer.textContent;
422
423 // Log every 3 checks
424 if (checkCount % 3 === 0) {
425 console.log(`🔍 Check ${checkCount}: Drawer length ${drawerContent.length} chars`);
426 }
427
428 // Check if drawer content changed significantly (new trade result)
429 if (drawerContent.length > drawerBaseline.length + 50) {
430 console.log('📋 NEW content detected! Checking for result...');
431 console.log(`📋 Content: ${drawerContent.substring(0, 200)}`);
432
433 // Look for "Closed+X.XX USD" or "Closed-X.XX USD"
434 const closedMatch = drawerContent.match(/Closed([+-][\d.]+)\s*USD/);
435 if (closedMatch) {
436 const profitLoss = parseFloat(closedMatch[1]);
437 clearInterval(checkInterval);
438 const isWin = profitLoss > 0;
439 console.log(`💵 Profit/Loss: ${profitLoss > 0 ? '+' : ''}${profitLoss.toFixed(2)} USD`);
440 console.log(isWin ? '✅ WIN!' : '❌ LOSS!');
441 resolve(isWin);
442 return;
443 }
444
445 // Look for "Total profit/loss: X.XX"
446 const profitMatch = drawerContent.match(/Total profit\/loss:\s*([+-]?[\d.]+)/i);
447 if (profitMatch) {
448 const profitLoss = parseFloat(profitMatch[1]);
449 clearInterval(checkInterval);
450 const isWin = profitLoss > 0;
451 console.log(`💵 Total P/L: ${profitLoss > 0 ? '+' : ''}${profitLoss.toFixed(2)}`);
452 console.log(isWin ? '✅ WIN!' : '❌ LOSS!');
453 resolve(isWin);
454 return;
455 }
456 }
457
458 // Timeout - check balance as fallback
459 if (checkCount >= maxChecks) {
460 clearInterval(checkInterval);
461 console.log('⏱️ Timeout - checking balance...');
462
463 const currentBalance = getAccountBalance();
464 const initialBalance = botState.balanceBeforeTrade;
465
466 if (currentBalance !== null && initialBalance !== null) {
467 const balanceChange = currentBalance - initialBalance;
468 console.log(`💵 Balance: $${currentBalance.toFixed(2)}, Change: ${balanceChange.toFixed(2)}`);
469
470 if (Math.abs(balanceChange) > 0.01) {
471 const isWin = balanceChange > 0;
472 console.log(isWin ? '✅ WIN (balance)' : '❌ LOSS (balance)');
473 resolve(isWin);
474 } else {
475 console.error('❌ No change detected - LOSS');
476 resolve(false);
477 }
478 } else {
479 console.error('❌ Cannot read balance - LOSS');
480 resolve(false);
481 }
482 }
483 }, 500);
484 });
485 }
486
487 // Handle trade result
488 async function handleTradeResult(isWin, direction) {
489 const previousStake = botState.currentStake;
490
491 if (isWin) {
492 console.log('✅ Trade WON!');
493 botState.winCount++;
494 const profit = previousStake * 0.94; // Approximate 94% payout
495 botState.totalProfit += profit;
496
497 // FIXED: Reset to initial stake after win
498 botState.currentStake = CONFIG.initialStake;
499 botState.martingaleLevel = 0;
500 console.log(`💰 Profit: $${profit.toFixed(2)} | Resetting stake to $${CONFIG.initialStake.toFixed(2)}`);
501 console.log(`✓ Stake is now: $${botState.currentStake.toFixed(2)}, Level: ${botState.martingaleLevel}`);
502 } else {
503 console.log('❌ Trade LOST!');
504 botState.lossCount++;
505 botState.totalProfit -= previousStake;
506
507 // Apply martingale strategy
508 if (botState.martingaleLevel < CONFIG.maxMartingaleLevel) {
509 botState.currentStake = previousStake * CONFIG.martingaleMultiplier;
510 botState.martingaleLevel++;
511 console.log(`📈 Martingale Level ${botState.martingaleLevel}: Next stake $${botState.currentStake.toFixed(2)}`);
512 } else {
513 console.log('⚠️ Max martingale level reached. Resetting to initial stake.');
514 botState.currentStake = CONFIG.initialStake;
515 botState.martingaleLevel = 0;
516 }
517 }
518
519 botState.lastTradeResult = isWin ? 'win' : 'loss';
520 botState.tradeHistory.push({
521 direction,
522 stake: previousStake,
523 result: isWin ? 'win' : 'loss',
524 timestamp: new Date().toISOString()
525 });
526
527 // Keep only last 50 trades in history
528 if (botState.tradeHistory.length > 50) {
529 botState.tradeHistory.shift();
530 }
531
532 updateUI();
533 await GM.setValue('botState', JSON.stringify(botState));
534 }
535
536 // Main trading loop
537 async function tradingLoop() {
538 while (botState.isRunning) {
539 try {
540 // Collect current price
541 const currentPrice = getCurrentPrice();
542 if (currentPrice) {
543 updatePriceHistory(currentPrice);
544 }
545
546 // Set stake amount
547 await setStakeAmount(botState.currentStake);
548
549 // Set duration to 1 tick
550 await setDuration();
551
552 // Predict direction using advanced technical analysis
553 const direction = predictNextMove();
554
555 // Skip trade if confidence is too low
556 if (direction === null) {
557 console.log('⏭️ Skipping trade due to low confidence. Waiting 5 seconds...');
558 await wait(5000);
559 continue;
560 }
561
562 botState.lastPrediction = direction; // Store for result verification
563
564 // Execute trade
565 const tradeExecuted = await executeTrade(direction);
566
567 if (tradeExecuted) {
568 // Wait for trade to complete
569 await wait(2000);
570
571 // Monitor result
572 const isWin = await monitorTradeResult();
573
574 // Handle result
575 await handleTradeResult(isWin, direction);
576
577 // Wait before next trade
578 console.log(`⏳ Waiting ${CONFIG.tradeDelay / 1000} seconds before next trade...`);
579 await wait(CONFIG.tradeDelay);
580 } else {
581 console.error('Failed to execute trade. Retrying in 5 seconds...');
582 await wait(5000);
583 }
584 } catch (error) {
585 console.error('Error in trading loop:', error);
586 await wait(5000);
587 }
588 }
589 }
590
591 // Start bot
592 async function startBot() {
593 if (botState.isRunning) {
594 console.log('Bot is already running');
595 return;
596 }
597
598 console.log('🤖 Starting Trading Bot with Advanced Technical Analysis...');
599 console.log('📊 Strategy: RSI + MACD + Bollinger Bands + EMA + Support/Resistance');
600 console.log(`⚙️ Min Confidence: ${CONFIG.minConfidenceScore}%`);
601 botState.isRunning = true;
602 botState.priceHistory = []; // Reset price history
603 updateUI();
604
605 // Load saved state
606 const savedState = await GM.getValue('botState');
607 if (savedState) {
608 const parsed = JSON.parse(savedState);
609 botState.totalTrades = parsed.totalTrades || 0;
610 botState.winCount = parsed.winCount || 0;
611 botState.lossCount = parsed.lossCount || 0;
612 botState.totalProfit = parsed.totalProfit || 0;
613 botState.tradeHistory = parsed.tradeHistory || [];
614 }
615
616 // Collect initial price data
617 console.log('📊 Collecting initial price data (30 ticks)...');
618 for (let i = 0; i < 30; i++) {
619 const price = getCurrentPrice();
620 if (price) {
621 updatePriceHistory(price);
622 if ((i + 1) % 5 === 0) {
623 console.log(` Collected ${i + 1}/30 price points...`);
624 }
625 }
626 await wait(1000);
627 }
628 console.log('✅ Price data collected. Starting trading with advanced strategy...\n');
629
630 tradingLoop();
631 }
632
633 // Stop bot
634 function stopBot() {
635 console.log('🛑 Stopping Trading Bot...');
636 botState.isRunning = false;
637 updateUI();
638 }
639
640 // Reset bot statistics
641 async function resetBot() {
642 botState = {
643 isRunning: false,
644 currentStake: CONFIG.initialStake,
645 martingaleLevel: 0,
646 totalTrades: 0,
647 winCount: 0,
648 lossCount: 0,
649 totalProfit: 0,
650 lastTradeResult: null,
651 tradeHistory: []
652 };
653 await GM.deleteValue('botState');
654 updateUI();
655 console.log('Bot statistics reset');
656 }
657
658 // Create UI
659 function createUI() {
660 const uiContainer = document.createElement('div');
661 uiContainer.id = 'trading-bot-ui';
662 uiContainer.innerHTML = `
663 <div class="bot-header">
664 <h3>🤖 Trading Bot</h3>
665 <button id="bot-minimize" class="bot-btn-icon">−</button>
666 </div>
667 <div class="bot-content">
668 <div class="bot-status">
669 <span class="status-label">Status:</span>
670 <span id="bot-status" class="status-value">Stopped</span>
671 </div>
672
673 <div class="bot-stats">
674 <div class="stat-row">
675 <span>Total Trades:</span>
676 <span id="stat-total">0</span>
677 </div>
678 <div class="stat-row">
679 <span>Wins:</span>
680 <span id="stat-wins" class="stat-win">0</span>
681 </div>
682 <div class="stat-row">
683 <span>Losses:</span>
684 <span id="stat-losses" class="stat-loss">0</span>
685 </div>
686 <div class="stat-row">
687 <span>Win Rate:</span>
688 <span id="stat-winrate">0%</span>
689 </div>
690 <div class="stat-row">
691 <span>Total Profit:</span>
692 <span id="stat-profit">$0.00</span>
693 </div>
694 <div class="stat-row">
695 <span>Current Stake:</span>
696 <span id="stat-stake">$${CONFIG.initialStake.toFixed(2)}</span>
697 </div>
698 <div class="stat-row">
699 <span>Martingale Level:</span>
700 <span id="stat-martingale">0</span>
701 </div>
702 </div>
703
704 <div class="bot-controls">
705 <button id="bot-start" class="bot-btn bot-btn-start">Start Bot</button>
706 <button id="bot-stop" class="bot-btn bot-btn-stop" disabled>Stop Bot</button>
707 <button id="bot-reset" class="bot-btn bot-btn-reset">Reset Stats</button>
708 </div>
709 </div>
710 `;
711
712 document.body.appendChild(uiContainer);
713
714 // Add styles
715 const styles = `
716 #trading-bot-ui {
717 position: fixed;
718 top: 80px;
719 right: 20px;
720 width: 320px;
721 background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
722 border: 2px solid #0f3460;
723 border-radius: 12px;
724 box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
725 z-index: 999999;
726 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
727 color: #ffffff;
728 }
729
730 .bot-header {
731 display: flex;
732 justify-content: space-between;
733 align-items: center;
734 padding: 15px;
735 background: linear-gradient(135deg, #0f3460 0%, #16213e 100%);
736 border-radius: 10px 10px 0 0;
737 border-bottom: 2px solid #e94560;
738 cursor: move;
739 }
740
741 .bot-header h3 {
742 margin: 0;
743 font-size: 18px;
744 font-weight: 600;
745 color: #ffffff;
746 }
747
748 .bot-btn-icon {
749 background: transparent;
750 border: none;
751 color: #ffffff;
752 font-size: 24px;
753 cursor: pointer;
754 padding: 0;
755 width: 30px;
756 height: 30px;
757 display: flex;
758 align-items: center;
759 justify-content: center;
760 border-radius: 5px;
761 transition: background 0.3s;
762 }
763
764 .bot-btn-icon:hover {
765 background: rgba(255, 255, 255, 0.1);
766 }
767
768 .bot-content {
769 padding: 15px;
770 }
771
772 .bot-status {
773 display: flex;
774 justify-content: space-between;
775 align-items: center;
776 padding: 12px;
777 background: rgba(255, 255, 255, 0.05);
778 border-radius: 8px;
779 margin-bottom: 15px;
780 border: 1px solid rgba(255, 255, 255, 0.1);
781 }
782
783 .status-label {
784 font-weight: 600;
785 color: #a8b2d1;
786 }
787
788 .status-value {
789 font-weight: 700;
790 padding: 4px 12px;
791 border-radius: 5px;
792 background: #e94560;
793 color: #ffffff;
794 }
795
796 .status-value.running {
797 background: #2ecc71;
798 }
799
800 .bot-stats {
801 background: rgba(255, 255, 255, 0.05);
802 border-radius: 8px;
803 padding: 12px;
804 margin-bottom: 15px;
805 border: 1px solid rgba(255, 255, 255, 0.1);
806 }
807
808 .stat-row {
809 display: flex;
810 justify-content: space-between;
811 padding: 8px 0;
812 border-bottom: 1px solid rgba(255, 255, 255, 0.05);
813 font-size: 14px;
814 }
815
816 .stat-row:last-child {
817 border-bottom: none;
818 }
819
820 .stat-row span:first-child {
821 color: #a8b2d1;
822 }
823
824 .stat-row span:last-child {
825 font-weight: 600;
826 color: #ffffff;
827 }
828
829 .stat-win {
830 color: #2ecc71 !important;
831 }
832
833 .stat-loss {
834 color: #e94560 !important;
835 }
836
837 .bot-controls {
838 display: flex;
839 flex-direction: column;
840 gap: 10px;
841 }
842
843 .bot-btn {
844 padding: 12px;
845 border: none;
846 border-radius: 8px;
847 font-size: 14px;
848 font-weight: 600;
849 cursor: pointer;
850 transition: all 0.3s;
851 text-transform: uppercase;
852 letter-spacing: 0.5px;
853 }
854
855 .bot-btn-start {
856 background: linear-gradient(135deg, #2ecc71 0%, #27ae60 100%);
857 color: #ffffff;
858 }
859
860 .bot-btn-start:hover:not(:disabled) {
861 transform: translateY(-2px);
862 box-shadow: 0 5px 15px rgba(46, 204, 113, 0.4);
863 }
864
865 .bot-btn-stop {
866 background: linear-gradient(135deg, #e94560 0%, #c0392b 100%);
867 color: #ffffff;
868 }
869
870 .bot-btn-stop:hover:not(:disabled) {
871 transform: translateY(-2px);
872 box-shadow: 0 5px 15px rgba(233, 69, 96, 0.4);
873 }
874
875 .bot-btn-reset {
876 background: linear-gradient(135deg, #3498db 0%, #2980b9 100%);
877 color: #ffffff;
878 }
879
880 .bot-btn-reset:hover:not(:disabled) {
881 transform: translateY(-2px);
882 box-shadow: 0 5px 15px rgba(52, 152, 219, 0.4);
883 }
884
885 .bot-btn:disabled {
886 opacity: 0.5;
887 cursor: not-allowed;
888 }
889
890 #trading-bot-ui.minimized .bot-content {
891 display: none;
892 }
893 `;
894
895 const styleSheet = document.createElement('style');
896 styleSheet.textContent = styles;
897 document.head.appendChild(styleSheet);
898
899 // Add event listeners
900 document.getElementById('bot-start').addEventListener('click', startBot);
901 document.getElementById('bot-stop').addEventListener('click', stopBot);
902 document.getElementById('bot-reset').addEventListener('click', () => {
903 if (confirm('Are you sure you want to reset all statistics?')) {
904 resetBot();
905 }
906 });
907
908 document.getElementById('bot-minimize').addEventListener('click', () => {
909 uiContainer.classList.toggle('minimized');
910 const btn = document.getElementById('bot-minimize');
911 btn.textContent = uiContainer.classList.contains('minimized') ? '+' : '−';
912 });
913
914 // Make draggable
915 makeDraggable(uiContainer);
916
917 console.log('Trading Bot UI created');
918 }
919
920 // Update UI
921 function updateUI() {
922 const statusElement = document.getElementById('bot-status');
923 if (statusElement) {
924 statusElement.textContent = botState.isRunning ? 'Running' : 'Stopped';
925 statusElement.className = botState.isRunning ? 'status-value running' : 'status-value';
926 }
927
928 document.getElementById('stat-total').textContent = botState.totalTrades;
929 document.getElementById('stat-wins').textContent = botState.winCount;
930 document.getElementById('stat-losses').textContent = botState.lossCount;
931
932 const winRate = botState.totalTrades > 0
933 ? ((botState.winCount / botState.totalTrades) * 100).toFixed(1)
934 : 0;
935 document.getElementById('stat-winrate').textContent = `${winRate}%`;
936
937 const profitElement = document.getElementById('stat-profit');
938 profitElement.textContent = `$${botState.totalProfit.toFixed(2)}`;
939 profitElement.style.color = botState.totalProfit >= 0 ? '#2ecc71' : '#e94560';
940
941 document.getElementById('stat-stake').textContent = `$${botState.currentStake.toFixed(2)}`;
942 document.getElementById('stat-martingale').textContent = botState.martingaleLevel;
943
944 document.getElementById('bot-start').disabled = botState.isRunning;
945 document.getElementById('bot-stop').disabled = !botState.isRunning;
946 }
947
948 // Make element draggable
949 function makeDraggable(element) {
950 let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
951 const header = element.querySelector('.bot-header');
952
953 header.onmousedown = dragMouseDown;
954
955 function dragMouseDown(e) {
956 e.preventDefault();
957 pos3 = e.clientX;
958 pos4 = e.clientY;
959 document.onmouseup = closeDragElement;
960 document.onmousemove = elementDrag;
961 }
962
963 function elementDrag(e) {
964 e.preventDefault();
965 pos1 = pos3 - e.clientX;
966 pos2 = pos4 - e.clientY;
967 pos3 = e.clientX;
968 pos4 = e.clientY;
969 element.style.top = (element.offsetTop - pos2) + 'px';
970 element.style.left = (element.offsetLeft - pos1) + 'px';
971 element.style.right = 'auto';
972 }
973
974 function closeDragElement() {
975 document.onmouseup = null;
976 document.onmousemove = null;
977 }
978 }
979
980 // Initialize
981 function init() {
982 console.log('Deriv Trading Bot initializing...');
983
984 // Wait for page to load
985 if (document.readyState === 'loading') {
986 document.addEventListener('DOMContentLoaded', () => {
987 setTimeout(createUI, 2000);
988 });
989 } else {
990 setTimeout(createUI, 2000);
991 }
992 }
993
994 init();
995})();