Deriv Rise/Fall Trading Bot with Martingale

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})();
Deriv Rise/Fall Trading Bot with Martingale | Robomonkey