Deriv Even/Odd Trading Bot

Automated trading bot that analyzes even/odd patterns and executes trades on Deriv

Size

22.7 KB

Version

1.1.14

Created

Dec 21, 2025

Updated

about 1 month ago

1// ==UserScript==
2// @name		Deriv Even/Odd Trading Bot
3// @description		Automated trading bot that analyzes even/odd patterns and executes trades on Deriv
4// @version		1.1.14
5// @match		https://*.app.deriv.com/*
6// @icon		https://app.deriv.com/favicon.ico
7// @grant		GM.getValue
8// @grant		GM.setValue
9// ==/UserScript==
10(function() {
11    'use strict';
12
13    // Bot configuration
14    let botConfig = {
15        isRunning: false,
16        tradeAmount: 1,
17        patternLength: 15, // Number of ticks to analyze (increased for better accuracy)
18        minConfidence: 70, // Minimum confidence percentage to trade (raised for quality)
19        consecutiveThreshold: 4, // Number of consecutive same results (stronger signals)
20        delayBetweenTrades: 5000, // Delay in ms between trades
21        martingaleEnabled: true, // Enable Martingale recovery
22        martingaleMultiplier: 2, // Multiply stake by this after loss
23        maxMartingaleSteps: 5, // Maximum number of Martingale steps (1->2->4->8->16->32)
24        baseStake: 1 // Base stake amount
25    };
26
27    let digitHistory = [];
28    let lastTradeTime = 0;
29    let lastDigitSnapshot = '';
30    let currentStake = 1;
31    let martingaleStep = 0;
32    let lastResultElement = null;
33    let consecutiveLosses = 0;
34    let botStats = {
35        totalTrades: 0,
36        wins: 0,
37        losses: 0,
38        profit: 0
39    };
40
41    // Utility function to debounce
42    function debounce(func, wait) {
43        let timeout;
44        return function executedFunction(...args) {
45            const later = () => {
46                clearTimeout(timeout);
47                func(...args);
48            };
49            clearTimeout(timeout);
50            timeout = setTimeout(later, wait);
51        };
52    }
53
54    // Analyze pattern and predict next move with improved logic
55    function analyzePattern(digits) {
56        if (digits.length < 10) {
57            return { prediction: null, confidence: 0, reason: 'Insufficient data (need at least 10 ticks)' };
58        }
59
60        const recentDigits = digits.slice(-botConfig.patternLength);
61        let evenCount = 0;
62        let oddCount = 0;
63        
64        recentDigits.forEach(digit => {
65            const num = parseInt(digit);
66            if (num % 2 === 0) evenCount++;
67            else oddCount++;
68        });
69
70        // Check for consecutive patterns (most reliable)
71        const lastFew = digits.slice(-botConfig.consecutiveThreshold);
72        const allEven = lastFew.every(d => parseInt(d) % 2 === 0);
73        const allOdd = lastFew.every(d => parseInt(d) % 2 !== 0);
74
75        let prediction = null;
76        let confidence = 0;
77        let reason = '';
78
79        // TREND FOLLOWING STRATEGY - Trade WITH the trend, not against it
80        
81        // Strategy 1: Strong consecutive pattern continuation (highest confidence)
82        if (allEven) {
83            prediction = 'even';
84            confidence = 78;
85            reason = `${botConfig.consecutiveThreshold} consecutive EVEN digits - following EVEN trend`;
86        } else if (allOdd) {
87            prediction = 'odd';
88            confidence = 78;
89            reason = `${botConfig.consecutiveThreshold} consecutive ODD digits - following ODD trend`;
90        } 
91        // Strategy 2: Very strong statistical dominance (75%+ dominance)
92        else {
93            const total = evenCount + oddCount;
94            const evenPercentage = (evenCount / total) * 100;
95            const oddPercentage = (oddCount / total) * 100;
96
97            if (evenPercentage >= 75) {
98                prediction = 'even';
99                confidence = Math.min(evenPercentage, 85);
100                reason = `Very strong EVEN dominance: ${evenPercentage.toFixed(1)}% - following EVEN trend`;
101            } else if (oddPercentage >= 75) {
102                prediction = 'odd';
103                confidence = Math.min(oddPercentage, 85);
104                reason = `Very strong ODD dominance: ${oddPercentage.toFixed(1)}% - following ODD trend`;
105            } 
106            // Strategy 3: Strong dominance (70-74% dominance)
107            else if (evenPercentage >= 70 && evenPercentage < 75) {
108                prediction = 'even';
109                confidence = 72;
110                reason = `Strong EVEN dominance: ${evenPercentage.toFixed(1)}% - following EVEN trend`;
111            } else if (oddPercentage >= 70 && oddPercentage < 75) {
112                prediction = 'odd';
113                confidence = 72;
114                reason = `Strong ODD dominance: ${oddPercentage.toFixed(1)}% - following ODD trend`;
115            }
116            // Strategy 4: Check last 6 digits for strong mini-trends
117            else {
118                const last6 = digits.slice(-6);
119                let even6 = 0;
120                let odd6 = 0;
121                last6.forEach(d => {
122                    if (parseInt(d) % 2 === 0) even6++;
123                    else odd6++;
124                });
125
126                if (even6 >= 5) {
127                    prediction = 'even';
128                    confidence = 70;
129                    reason = `Last 6 ticks: ${even6} EVEN vs ${odd6} ODD - strong EVEN trend`;
130                } else if (odd6 >= 5) {
131                    prediction = 'odd';
132                    confidence = 70;
133                    reason = `Last 6 ticks: ${odd6} ODD vs ${even6} EVEN - strong ODD trend`;
134                } else {
135                    // No clear strong pattern - skip trade
136                    return { 
137                        prediction: null, 
138                        confidence: 0, 
139                        reason: `No strong pattern detected (E:${evenCount} O:${oddCount}, ${evenPercentage.toFixed(1)}% vs ${oddPercentage.toFixed(1)}%)`,
140                        evenCount,
141                        oddCount 
142                    };
143                }
144            }
145        }
146
147        // Cooling off period: After 2+ losses, require even higher confidence
148        if (consecutiveLosses >= 2 && confidence < 75) {
149            return {
150                prediction: null,
151                confidence: 0,
152                reason: `Cooling off after ${consecutiveLosses} losses - need 75%+ confidence (current: ${confidence}%)`,
153                evenCount,
154                oddCount
155            };
156        }
157
158        return { prediction, confidence, reason, evenCount, oddCount };
159    }
160
161    // Monitor trade results
162    function monitorTradeResults() {
163        const resultOverlay = document.querySelector('.dc-contract-card__result');
164        
165        if (resultOverlay && resultOverlay !== lastResultElement) {
166            lastResultElement = resultOverlay;
167            
168            const isWon = resultOverlay.classList.contains('dc-contract-card__result--won');
169            const isLost = resultOverlay.classList.contains('dc-contract-card__result--lost');
170            
171            if (isWon) {
172                console.log('βœ… Trade WON - Resetting stake to base');
173                botStats.wins++;
174                currentStake = botConfig.baseStake;
175                martingaleStep = 0;
176                consecutiveLosses = 0; // Reset consecutive losses
177                updateBotUI();
178            } else if (isLost) {
179                console.log('❌ Trade LOST - Applying Martingale');
180                botStats.losses++;
181                consecutiveLosses++;
182                
183                if (botConfig.martingaleEnabled && martingaleStep < botConfig.maxMartingaleSteps) {
184                    martingaleStep++;
185                    currentStake = botConfig.baseStake * Math.pow(botConfig.martingaleMultiplier, martingaleStep);
186                    console.log(`πŸ“ˆ Martingale activated: Step ${martingaleStep}, New stake: ${currentStake}`);
187                    
188                    if (consecutiveLosses >= 2) {
189                        console.log(`⚠️ ${consecutiveLosses} consecutive losses - entering cooling off mode`);
190                    }
191                } else if (martingaleStep >= botConfig.maxMartingaleSteps) {
192                    console.log('⚠️ Max Martingale steps reached - Resetting to base stake');
193                    currentStake = botConfig.baseStake;
194                    martingaleStep = 0;
195                }
196                updateBotUI();
197            }
198        }
199    }
200
201    // Execute trade
202    async function executeTrade(type) {
203        const now = Date.now();
204        if (now - lastTradeTime < botConfig.delayBetweenTrades) {
205            console.log('⏳ Waiting for delay between trades...');
206            return false;
207        }
208
209        try {
210            // Set stake amount input
211            const stakeInput = document.getElementById('dt_amount_input');
212            if (stakeInput) {
213                stakeInput.value = currentStake;
214                stakeInput.dispatchEvent(new Event('input', { bubbles: true }));
215                stakeInput.dispatchEvent(new Event('change', { bubbles: true }));
216                console.log(`πŸ’° Stake set to: ${currentStake} (Martingale step: ${martingaleStep})`);
217                
218                // Wait a bit for the input to register
219                await new Promise(resolve => setTimeout(resolve, 300));
220            }
221
222            const buttonId = type === 'even' ? 'dt_purchase_digiteven_button' : 'dt_purchase_digitodd_button';
223            const button = document.getElementById(buttonId);
224            
225            if (!button) {
226                console.error('❌ Trade button not found');
227                return false;
228            }
229
230            // Check if button is disabled
231            if (button.disabled || button.classList.contains('btn-purchase--disabled')) {
232                console.log('⏸️ Trade button is disabled, waiting...');
233                return false;
234            }
235
236            console.log(`🎯 Executing ${type.toUpperCase()} trade...`);
237            button.click();
238            
239            lastTradeTime = now;
240            botStats.totalTrades++;
241            
242            // Save stats
243            await GM.setValue('botStats', JSON.stringify(botStats));
244            
245            updateBotUI();
246            return true;
247        } catch (error) {
248            console.error('❌ Error executing trade:', error);
249            return false;
250        }
251    }
252
253    // Collect digit history
254    function collectDigitHistory() {
255        // Get only the LATEST digit (the one that's actually changing)
256        const latestDigitEl = document.querySelector('.digits__digit--latest .digits__digit-display-value');
257        
258        if (latestDigitEl) {
259            const latestDigit = latestDigitEl.textContent.trim();
260            
261            // Add to history if it's new
262            if (digitHistory.length === 0 || digitHistory[digitHistory.length - 1] !== latestDigit) {
263                digitHistory.push(latestDigit);
264                console.log('πŸ“Š New digit collected:', latestDigit, '| History:', digitHistory.slice(-10).join(', '));
265                
266                // Keep only last 20 digits to prevent memory issues
267                if (digitHistory.length > 20) {
268                    digitHistory = digitHistory.slice(-20);
269                }
270            }
271        }
272    }
273
274    // Main bot logic
275    async function runBotCycle() {
276        if (!botConfig.isRunning) return;
277
278        collectDigitHistory();
279
280        if (digitHistory.length < 10) {
281            console.log('⏳ Waiting for more data (need 10+ ticks)...');
282            setTimeout(runBotCycle, 2000);
283            return;
284        }
285
286        // Check if digits have changed since last trade
287        const currentSnapshot = digitHistory.join(',');
288        if (currentSnapshot === lastDigitSnapshot && lastTradeTime > 0) {
289            console.log('⏸️ Digits unchanged - waiting for new tick...');
290            setTimeout(runBotCycle, 2000);
291            return;
292        }
293
294        const analysis = analyzePattern(digitHistory);
295        console.log('πŸ” Analysis:', analysis);
296
297        if (analysis.prediction && analysis.confidence >= botConfig.minConfidence) {
298            console.log(`βœ… Trading signal: ${analysis.prediction.toUpperCase()} (${analysis.confidence}% confidence)`);
299            console.log(`πŸ“ Reason: ${analysis.reason}`);
300            
301            const success = await executeTrade(analysis.prediction);
302            
303            if (success) {
304                // Save snapshot after successful trade
305                lastDigitSnapshot = currentSnapshot;
306                // Wait for trade to complete before next cycle
307                setTimeout(runBotCycle, botConfig.delayBetweenTrades + 3000);
308            } else {
309                setTimeout(runBotCycle, 2000);
310            }
311        } else {
312            console.log(`⏸️ No confident signal (${analysis.confidence}% < ${botConfig.minConfidence}%)`);
313            console.log(`πŸ“ ${analysis.reason}`);
314            setTimeout(runBotCycle, 3000);
315        }
316    }
317
318    // Create bot UI
319    function createBotUI() {
320        const botPanel = document.createElement('div');
321        botPanel.id = 'trading-bot-panel';
322        botPanel.innerHTML = `
323            <div style="position: fixed; top: 80px; right: 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 12px; box-shadow: 0 8px 32px rgba(0,0,0,0.3); z-index: 10000; min-width: 320px; font-family: Arial, sans-serif;">
324                <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
325                    <h3 style="margin: 0; font-size: 18px; font-weight: bold;">πŸ€– Trading Bot</h3>
326                    <div style="display: flex; gap: 8px;">
327                        <button id="bot-minimize" style="background: rgba(255,255,255,0.2); border: none; color: white; width: 28px; height: 28px; border-radius: 6px; cursor: pointer; font-size: 16px;">βˆ’</button>
328                        <button id="bot-close" style="background: rgba(255,255,255,0.2); border: none; color: white; width: 28px; height: 28px; border-radius: 6px; cursor: pointer; font-size: 16px;">Γ—</button>
329                    </div>
330                </div>
331                
332                <div id="bot-content">
333                    <div style="background: rgba(255,255,255,0.15); padding: 12px; border-radius: 8px; margin-bottom: 12px;">
334                        <div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
335                            <span style="font-size: 13px; opacity: 0.9;">Status:</span>
336                            <span id="bot-status" style="font-weight: bold; font-size: 13px;">⏸️ Stopped</span>
337                        </div>
338                        <div style="display: flex; justify-content: space-between; margin-bottom: 8px;">
339                            <span style="font-size: 13px; opacity: 0.9;">Trades:</span>
340                            <span id="bot-trades" style="font-weight: bold; font-size: 13px;">0</span>
341                        </div>
342                        <div style="display: flex; justify-content: space-between;">
343                            <span style="font-size: 13px; opacity: 0.9;">Win Rate:</span>
344                            <span id="bot-winrate" style="font-weight: bold; font-size: 13px;">0%</span>
345                        </div>
346                    </div>
347
348                    <div style="margin-bottom: 12px;">
349                        <label style="display: block; font-size: 12px; margin-bottom: 6px; opacity: 0.9;">Min Confidence: <span id="confidence-value">${botConfig.minConfidence}%</span></label>
350                        <input type="range" id="confidence-slider" min="50" max="80" value="${botConfig.minConfidence}" style="width: 100%; cursor: pointer;">
351                    </div>
352
353                    <div style="margin-bottom: 12px;">
354                        <label style="display: block; font-size: 12px; margin-bottom: 6px; opacity: 0.9;">Pattern Length: <span id="pattern-value">${botConfig.patternLength}</span></label>
355                        <input type="range" id="pattern-slider" min="5" max="20" value="${botConfig.patternLength}" style="width: 100%; cursor: pointer;">
356                    </div>
357
358                    <div style="margin-bottom: 15px;">
359                        <label style="display: block; font-size: 12px; margin-bottom: 6px; opacity: 0.9;">Consecutive Threshold: <span id="consecutive-value">${botConfig.consecutiveThreshold}</span></label>
360                        <input type="range" id="consecutive-slider" min="2" max="5" value="${botConfig.consecutiveThreshold}" style="width: 100%; cursor: pointer;">
361                    </div>
362
363                    <button id="bot-toggle" style="width: 100%; padding: 12px; background: #48bb78; color: white; border: none; border-radius: 8px; font-size: 15px; font-weight: bold; cursor: pointer; transition: all 0.3s;">
364                        ▢️ Start Bot
365                    </button>
366
367                    <button id="bot-reset" style="width: 100%; padding: 10px; background: rgba(255,255,255,0.2); color: white; border: none; border-radius: 8px; font-size: 13px; cursor: pointer; margin-top: 8px;">
368                        πŸ”„ Reset Stats
369                    </button>
370                </div>
371            </div>
372        `;
373
374        document.body.appendChild(botPanel);
375        attachBotListeners();
376    }
377
378    // Update bot UI
379    function updateBotUI() {
380        const statusEl = document.getElementById('bot-status');
381        const tradesEl = document.getElementById('bot-trades');
382        const winrateEl = document.getElementById('bot-winrate');
383        const toggleBtn = document.getElementById('bot-toggle');
384
385        if (statusEl) {
386            statusEl.textContent = botConfig.isRunning ? 'βœ… Running' : '⏸️ Stopped';
387        }
388
389        if (tradesEl) {
390            tradesEl.textContent = botStats.totalTrades;
391        }
392
393        if (winrateEl) {
394            const winRate = botStats.totalTrades > 0 
395                ? ((botStats.wins / botStats.totalTrades) * 100).toFixed(1)
396                : 0;
397            winrateEl.textContent = `${winRate}%`;
398        }
399
400        if (toggleBtn) {
401            if (botConfig.isRunning) {
402                toggleBtn.textContent = '⏸️ Stop Bot';
403                toggleBtn.style.background = '#f56565';
404            } else {
405                toggleBtn.textContent = '▢️ Start Bot';
406                toggleBtn.style.background = '#48bb78';
407            }
408        }
409    }
410
411    // Attach event listeners
412    function attachBotListeners() {
413        const toggleBtn = document.getElementById('bot-toggle');
414        const resetBtn = document.getElementById('bot-reset');
415        const minimizeBtn = document.getElementById('bot-minimize');
416        const closeBtn = document.getElementById('bot-close');
417        const confidenceSlider = document.getElementById('confidence-slider');
418        const patternSlider = document.getElementById('pattern-slider');
419        const consecutiveSlider = document.getElementById('consecutive-slider');
420
421        toggleBtn.addEventListener('click', async () => {
422            botConfig.isRunning = !botConfig.isRunning;
423            await GM.setValue('botRunning', botConfig.isRunning);
424            
425            if (botConfig.isRunning) {
426                console.log('πŸš€ Bot started!');
427                runBotCycle();
428            } else {
429                console.log('⏸️ Bot stopped!');
430            }
431            
432            updateBotUI();
433        });
434
435        resetBtn.addEventListener('click', async () => {
436            botStats = { totalTrades: 0, wins: 0, losses: 0, profit: 0 };
437            await GM.setValue('botStats', JSON.stringify(botStats));
438            updateBotUI();
439            console.log('πŸ”„ Stats reset!');
440        });
441
442        closeBtn.addEventListener('click', () => {
443            if (botConfig.isRunning) {
444                alert('Please stop the bot before closing.');
445                return;
446            }
447            const panel = document.getElementById('trading-bot-panel');
448            if (panel) {
449                panel.remove();
450                console.log('πŸ”΄ Bot panel closed');
451            }
452        });
453
454        minimizeBtn.addEventListener('click', () => {
455            const content = document.getElementById('bot-content');
456            if (content.style.display === 'none') {
457                content.style.display = 'block';
458                minimizeBtn.textContent = 'βˆ’';
459            } else {
460                content.style.display = 'none';
461                minimizeBtn.textContent = '+';
462            }
463        });
464
465        confidenceSlider.addEventListener('input', (e) => {
466            botConfig.minConfidence = parseInt(e.target.value);
467            document.getElementById('confidence-value').textContent = `${botConfig.minConfidence}%`;
468        });
469
470        patternSlider.addEventListener('input', (e) => {
471            botConfig.patternLength = parseInt(e.target.value);
472            document.getElementById('pattern-value').textContent = botConfig.patternLength;
473        });
474
475        consecutiveSlider.addEventListener('input', (e) => {
476            botConfig.consecutiveThreshold = parseInt(e.target.value);
477            document.getElementById('consecutive-value').textContent = botConfig.consecutiveThreshold;
478        });
479    }
480
481    // Monitor for new digits using MutationObserver
482    function setupDigitMonitor() {
483        const debouncedCollect = debounce(() => {
484            collectDigitHistory();
485        }, 500);
486
487        const observer = new MutationObserver(debouncedCollect);
488        
489        const digitsContainer = document.querySelector('.digits__digit-container');
490        if (digitsContainer) {
491            observer.observe(digitsContainer, {
492                childList: true,
493                subtree: true,
494                characterData: true
495            });
496            console.log('πŸ‘€ Digit monitor active');
497        }
498    }
499
500    // Monitor for trade results
501    function setupResultMonitor() {
502        const observer = new MutationObserver(() => {
503            monitorTradeResults();
504        });
505        
506        // Watch the entire body for result overlays
507        observer.observe(document.body, {
508            childList: true,
509            subtree: true,
510            attributes: true,
511            attributeFilter: ['class']
512        });
513        
514        console.log('πŸ“Š Result monitor active');
515    }
516
517    // Initialize bot
518    async function init() {
519        console.log('πŸ€– Deriv Trading Bot initializing...');
520
521        // Load saved stats
522        const savedStats = await GM.getValue('botStats', null);
523        if (savedStats) {
524            botStats = JSON.parse(savedStats);
525        }
526
527        // Wait for page to load
528        if (document.readyState === 'loading') {
529            document.addEventListener('DOMContentLoaded', () => {
530                setTimeout(() => {
531                    createBotUI();
532                    setupDigitMonitor();
533                    setupResultMonitor();
534                    collectDigitHistory();
535                }, 2000);
536            });
537        } else {
538            setTimeout(() => {
539                createBotUI();
540                setupDigitMonitor();
541                setupResultMonitor();
542                collectDigitHistory();
543            }, 2000);
544        }
545
546        console.log('βœ… Bot ready! Use the panel to start trading.');
547    }
548
549    init();
550})();
Deriv Even/Odd Trading Bot | Robomonkey