Automated trading bot for Rise and Fall on Deriv with Martingale strategy and intelligent analysis
Size
31.6 KB
Version
1.2.8
Created
Dec 20, 2025
Updated
about 2 months ago
1// ==UserScript==
2// @name Deriv Rise/Fall Trading Bot
3// @description Automated trading bot for Rise and Fall on Deriv with Martingale strategy and intelligent analysis
4// @version 1.2.8
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 and state
12 const botState = {
13 isRunning: false,
14 strategy: 'martingale',
15 baseStake: 1,
16 currentStake: 1,
17 tradeType: 'rise', // 'rise' or 'fall'
18 stats: {
19 totalTrades: 0,
20 wins: 0,
21 losses: 0,
22 profit: 0,
23 winStreak: 0,
24 lossStreak: 0
25 },
26 lastTradeResult: null,
27 martingaleMultiplier: 2,
28 maxStake: 1000,
29 delayBetweenTrades: 5000,
30 balanceBeforeTrade: 0,
31 useAnalysis: true,
32 useTrendAnalysis: true,
33 trendHistory: [] // Store last 10 results
34 };
35
36 const wait = (ms) => new Promise(resolve => setTimeout(resolve, ms));
37
38 // Create bot UI
39 function createBotUI() {
40 console.log('Creating Even/Odd bot UI...');
41
42 const existingUI = document.getElementById('deriv-bot-panel');
43 if (existingUI) existingUI.remove();
44
45 const botPanel = document.createElement('div');
46 botPanel.id = 'deriv-bot-panel';
47 botPanel.innerHTML = `
48 <div class="bot-header">
49 <h3>Rise/Fall Bot</h3>
50 <button id="bot-minimize" class="bot-btn-icon">−</button>
51 </div>
52 <div class="bot-content">
53 <div class="bot-section">
54 <label>Strategy:</label>
55 <select id="bot-strategy" class="bot-select">
56 <option value="martingale">Martingale</option>
57 <option value="anti-martingale">Anti-Martingale</option>
58 <option value="fixed">Fixed Stake</option>
59 </select>
60 </div>
61
62 <div class="bot-section">
63 <label>Trade Type:</label>
64 <select id="bot-trade-type" class="bot-select">
65 <option value="rise">Rise</option>
66 <option value="fall">Fall</option>
67 <option value="alternate">Alternate</option>
68 </select>
69 </div>
70
71 <div class="bot-section">
72 <label>Base Stake (USD):</label>
73 <input type="number" id="bot-stake" class="bot-input" value="1" min="1" step="1">
74 </div>
75
76 <div class="bot-section">
77 <label>Max Stake (USD):</label>
78 <input type="number" id="bot-max-stake" class="bot-input" value="1000" min="1" step="10">
79 </div>
80
81 <div class="bot-section">
82 <label>Delay (ms):</label>
83 <input type="number" id="bot-delay" class="bot-input" value="5000" min="1000" step="500">
84 </div>
85
86 <div class="bot-controls">
87 <button id="bot-start" class="bot-btn bot-btn-start">Start Bot</button>
88 <button id="bot-stop" class="bot-btn bot-btn-stop" disabled>Stop Bot</button>
89 <button id="bot-reset" class="bot-btn bot-btn-reset">Reset Stats</button>
90 </div>
91
92 <div class="bot-stats">
93 <h4>Statistics</h4>
94 <div class="stats-grid">
95 <div class="stat-item">
96 <span class="stat-label">Total Trades:</span>
97 <span id="stat-total" class="stat-value">0</span>
98 </div>
99 <div class="stat-item">
100 <span class="stat-label">Wins:</span>
101 <span id="stat-wins" class="stat-value stat-win">0</span>
102 </div>
103 <div class="stat-item">
104 <span class="stat-label">Losses:</span>
105 <span id="stat-losses" class="stat-value stat-loss">0</span>
106 </div>
107 <div class="stat-item">
108 <span class="stat-label">Win Rate:</span>
109 <span id="stat-winrate" class="stat-value">0%</span>
110 </div>
111 <div class="stat-item">
112 <span class="stat-label">Profit/Loss:</span>
113 <span id="stat-profit" class="stat-value">$0.00</span>
114 </div>
115 <div class="stat-item">
116 <span class="stat-label">Current Stake:</span>
117 <span id="stat-current-stake" class="stat-value">$1.00</span>
118 </div>
119 </div>
120 </div>
121
122 <div class="bot-status">
123 <span id="bot-status-text">Bot is idle</span>
124 </div>
125
126 <div id="bot-notifications" class="bot-notifications"></div>
127 </div>
128 `;
129
130 const styles = `
131 #deriv-bot-panel {
132 position: fixed;
133 top: 80px;
134 right: 20px;
135 width: 340px;
136 background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
137 border: 2px solid #0f3460;
138 border-radius: 12px;
139 box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
140 z-index: 999999;
141 font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
142 color: #ffffff;
143 }
144
145 .bot-header {
146 background: linear-gradient(135deg, #0f3460 0%, #16213e 100%);
147 padding: 14px 18px;
148 border-radius: 10px 10px 0 0;
149 display: flex;
150 justify-content: space-between;
151 align-items: center;
152 cursor: move;
153 border-bottom: 2px solid #e94560;
154 }
155
156 .bot-header h3 {
157 margin: 0;
158 font-size: 17px;
159 font-weight: 600;
160 color: #ffffff;
161 }
162
163 .bot-btn-icon {
164 background: transparent;
165 border: none;
166 color: #ffffff;
167 font-size: 24px;
168 cursor: pointer;
169 padding: 0;
170 width: 24px;
171 height: 24px;
172 }
173
174 .bot-btn-icon:hover {
175 color: #e94560;
176 }
177
178 .bot-content {
179 padding: 18px;
180 max-height: 650px;
181 overflow-y: auto;
182 }
183
184 .bot-content::-webkit-scrollbar {
185 width: 6px;
186 }
187
188 .bot-content::-webkit-scrollbar-track {
189 background: #1a1a2e;
190 }
191
192 .bot-content::-webkit-scrollbar-thumb {
193 background: #0f3460;
194 border-radius: 3px;
195 }
196
197 .bot-section {
198 margin-bottom: 16px;
199 }
200
201 .bot-section label {
202 display: block;
203 margin-bottom: 8px;
204 font-size: 13px;
205 font-weight: 600;
206 color: #b8c1ec;
207 }
208
209 .bot-select, .bot-input {
210 width: 100%;
211 padding: 10px 14px;
212 background: #0f3460;
213 border: 1px solid #16213e;
214 border-radius: 8px;
215 color: #ffffff;
216 font-size: 14px;
217 transition: all 0.3s ease;
218 }
219
220 .bot-select:focus, .bot-input:focus {
221 outline: none;
222 border-color: #e94560;
223 box-shadow: 0 0 0 3px rgba(233, 69, 96, 0.2);
224 }
225
226 .bot-controls {
227 display: flex;
228 gap: 10px;
229 margin: 18px 0;
230 flex-wrap: wrap;
231 }
232
233 .bot-btn {
234 flex: 1;
235 min-width: 95px;
236 padding: 12px 18px;
237 border: none;
238 border-radius: 8px;
239 font-size: 13px;
240 font-weight: 700;
241 cursor: pointer;
242 transition: all 0.3s ease;
243 text-transform: uppercase;
244 letter-spacing: 0.5px;
245 }
246
247 .bot-btn-start {
248 background: linear-gradient(135deg, #00d4ff 0%, #0099cc 100%);
249 color: #ffffff;
250 }
251
252 .bot-btn-start:hover:not(:disabled) {
253 background: linear-gradient(135deg, #00bbff 0%, #0088bb 100%);
254 transform: translateY(-2px);
255 box-shadow: 0 6px 16px rgba(0, 212, 255, 0.5);
256 }
257
258 .bot-btn-stop {
259 background: linear-gradient(135deg, #e94560 0%, #cc3850 100%);
260 color: #ffffff;
261 }
262
263 .bot-btn-stop:hover:not(:disabled) {
264 background: linear-gradient(135deg, #d63850 0%, #bb2840 100%);
265 transform: translateY(-2px);
266 box-shadow: 0 6px 16px rgba(233, 69, 96, 0.5);
267 }
268
269 .bot-btn-reset {
270 background: linear-gradient(135deg, #533483 0%, #3d2563 100%);
271 color: #ffffff;
272 }
273
274 .bot-btn-reset:hover:not(:disabled) {
275 background: linear-gradient(135deg, #432873 0%, #2d1553 100%);
276 transform: translateY(-2px);
277 box-shadow: 0 6px 16px rgba(83, 52, 131, 0.5);
278 }
279
280 .bot-btn:disabled {
281 opacity: 0.5;
282 cursor: not-allowed;
283 }
284
285 .bot-stats {
286 background: rgba(15, 52, 96, 0.5);
287 padding: 16px;
288 border-radius: 10px;
289 margin-top: 18px;
290 }
291
292 .bot-stats h4 {
293 margin: 0 0 14px 0;
294 font-size: 14px;
295 color: #b8c1ec;
296 text-transform: uppercase;
297 letter-spacing: 1px;
298 }
299
300 .stats-grid {
301 display: grid;
302 grid-template-columns: 1fr 1fr;
303 gap: 12px;
304 }
305
306 .stat-item {
307 display: flex;
308 flex-direction: column;
309 gap: 6px;
310 }
311
312 .stat-label {
313 font-size: 11px;
314 color: #b8c1ec;
315 text-transform: uppercase;
316 letter-spacing: 0.5px;
317 }
318
319 .stat-value {
320 font-size: 18px;
321 font-weight: 700;
322 color: #ffffff;
323 }
324
325 .stat-win {
326 color: #00ff88;
327 }
328
329 .stat-loss {
330 color: #ff4444;
331 }
332
333 .bot-status {
334 margin-top: 14px;
335 padding: 12px;
336 background: rgba(15, 52, 96, 0.3);
337 border-radius: 8px;
338 text-align: center;
339 font-size: 13px;
340 font-weight: 500;
341 color: #b8c1ec;
342 border-left: 4px solid #e94560;
343 }
344
345 .bot-status.active {
346 border-left-color: #00ff88;
347 animation: pulse 2s infinite;
348 }
349
350 .bot-notifications {
351 margin-top: 14px;
352 max-height: 200px;
353 overflow-y: auto;
354 }
355
356 .bot-notification {
357 padding: 10px 12px;
358 margin-bottom: 8px;
359 border-radius: 8px;
360 font-size: 12px;
361 font-weight: 500;
362 animation: slideIn 0.3s ease;
363 }
364
365 .bot-notification.win {
366 background: rgba(0, 255, 136, 0.15);
367 border-left: 4px solid #00ff88;
368 color: #00ff88;
369 }
370
371 .bot-notification.loss {
372 background: rgba(255, 68, 68, 0.15);
373 border-left: 4px solid #ff4444;
374 color: #ff4444;
375 }
376
377 .bot-notification.info {
378 background: rgba(0, 212, 255, 0.15);
379 border-left: 4px solid #00d4ff;
380 color: #00d4ff;
381 }
382
383 @keyframes slideIn {
384 from {
385 opacity: 0;
386 transform: translateX(20px);
387 }
388 to {
389 opacity: 1;
390 transform: translateX(0);
391 }
392 }
393
394 @keyframes pulse {
395 0%, 100% { opacity: 1; }
396 50% { opacity: 0.7; }
397 }
398 `;
399
400 const styleSheet = document.createElement('style');
401 styleSheet.textContent = styles;
402 document.head.appendChild(styleSheet);
403
404 document.body.appendChild(botPanel);
405 console.log('Bot UI created');
406
407 makeDraggable(botPanel);
408 attachEventListeners();
409 }
410
411 function makeDraggable(element) {
412 const header = element.querySelector('.bot-header');
413 let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
414
415 header.onmousedown = (e) => {
416 e.preventDefault();
417 pos3 = e.clientX;
418 pos4 = e.clientY;
419 document.onmouseup = () => {
420 document.onmouseup = null;
421 document.onmousemove = null;
422 };
423 document.onmousemove = (e) => {
424 e.preventDefault();
425 pos1 = pos3 - e.clientX;
426 pos2 = pos4 - e.clientY;
427 pos3 = e.clientX;
428 pos4 = e.clientY;
429 element.style.top = (element.offsetTop - pos2) + 'px';
430 element.style.left = (element.offsetLeft - pos1) + 'px';
431 element.style.right = 'auto';
432 };
433 };
434 }
435
436 function attachEventListeners() {
437 document.getElementById('bot-start').addEventListener('click', startBot);
438 document.getElementById('bot-stop').addEventListener('click', stopBot);
439 document.getElementById('bot-reset').addEventListener('click', resetStats);
440 document.getElementById('bot-minimize').addEventListener('click', toggleMinimize);
441
442 document.getElementById('bot-strategy').addEventListener('change', (e) => {
443 botState.strategy = e.target.value;
444 });
445
446 document.getElementById('bot-trade-type').addEventListener('change', (e) => {
447 botState.tradeType = e.target.value;
448 });
449
450 document.getElementById('bot-stake').addEventListener('change', (e) => {
451 botState.baseStake = parseFloat(e.target.value) || 1;
452 botState.currentStake = botState.baseStake;
453 updateStats();
454 });
455
456 document.getElementById('bot-max-stake').addEventListener('change', (e) => {
457 botState.maxStake = parseFloat(e.target.value) || 1000;
458 });
459
460 document.getElementById('bot-delay').addEventListener('change', (e) => {
461 botState.delayBetweenTrades = parseInt(e.target.value) || 5000;
462 });
463 }
464
465 function toggleMinimize() {
466 const content = document.querySelector('.bot-content');
467 const btn = document.getElementById('bot-minimize');
468
469 if (content.style.display === 'none') {
470 content.style.display = 'block';
471 btn.textContent = '−';
472 } else {
473 content.style.display = 'none';
474 btn.textContent = '+';
475 }
476 }
477
478 function addNotification(message, type) {
479 const container = document.getElementById('bot-notifications');
480 const notification = document.createElement('div');
481 notification.className = `bot-notification ${type}`;
482 notification.textContent = message;
483 container.insertBefore(notification, container.firstChild);
484
485 // Keep only last 5 notifications
486 while (container.children.length > 5) {
487 container.removeChild(container.lastChild);
488 }
489 }
490
491 async function startBot() {
492 console.log('Starting bot...');
493 botState.isRunning = true;
494
495 document.getElementById('bot-start').disabled = true;
496 document.getElementById('bot-stop').disabled = false;
497 document.getElementById('bot-strategy').disabled = true;
498 document.getElementById('bot-trade-type').disabled = true;
499 document.getElementById('bot-stake').disabled = true;
500 document.getElementById('bot-max-stake').disabled = true;
501
502 updateStatusText('Bot is running...', true);
503 addNotification('Bot started successfully', 'info');
504
505 runTradingLoop();
506 }
507
508 function stopBot() {
509 console.log('Stopping bot...');
510 botState.isRunning = false;
511
512 document.getElementById('bot-start').disabled = false;
513 document.getElementById('bot-stop').disabled = true;
514 document.getElementById('bot-strategy').disabled = false;
515 document.getElementById('bot-trade-type').disabled = false;
516 document.getElementById('bot-stake').disabled = false;
517 document.getElementById('bot-max-stake').disabled = false;
518
519 updateStatusText('Bot stopped', false);
520 addNotification('Bot stopped', 'info');
521 }
522
523 function resetStats() {
524 botState.stats = {
525 totalTrades: 0,
526 wins: 0,
527 losses: 0,
528 profit: 0,
529 winStreak: 0,
530 lossStreak: 0
531 };
532 botState.currentStake = botState.baseStake;
533 updateStats();
534 addNotification('Statistics reset', 'info');
535 }
536
537 function updateStatusText(text, isActive = false) {
538 const statusElement = document.getElementById('bot-status-text');
539 if (statusElement) {
540 statusElement.textContent = text;
541 const statusContainer = statusElement.parentElement;
542 if (isActive) {
543 statusContainer.classList.add('active');
544 } else {
545 statusContainer.classList.remove('active');
546 }
547 }
548 }
549
550 function updateStats() {
551 const stats = botState.stats;
552 const winRate = stats.totalTrades > 0 ? ((stats.wins / stats.totalTrades) * 100).toFixed(2) : 0;
553
554 document.getElementById('stat-total').textContent = stats.totalTrades;
555 document.getElementById('stat-wins').textContent = stats.wins;
556 document.getElementById('stat-losses').textContent = stats.losses;
557 document.getElementById('stat-winrate').textContent = winRate + '%';
558
559 const profitElement = document.getElementById('stat-profit');
560 profitElement.textContent = '$' + stats.profit.toFixed(2);
561 profitElement.style.color = stats.profit >= 0 ? '#00ff88' : '#ff4444';
562
563 document.getElementById('stat-current-stake').textContent = '$' + botState.currentStake.toFixed(2);
564 }
565
566 function getCurrentBalance() {
567 const balanceElement = document.querySelector('[data-testid="dt_balance"]');
568 if (balanceElement) {
569 const balanceText = balanceElement.textContent.trim();
570 const balanceMatch = balanceText.match(/[\d,]+\.?\d*/);
571 if (balanceMatch) {
572 return parseFloat(balanceMatch[0].replace(/,/g, ''));
573 }
574 }
575 return null;
576 }
577
578 function setStakeAmount(amount) {
579 const stakeInput = document.querySelector('input[name="amount"]#dt_amount_input');
580 if (stakeInput) {
581 stakeInput.value = amount;
582 stakeInput.dispatchEvent(new Event('input', { bubbles: true }));
583 stakeInput.dispatchEvent(new Event('change', { bubbles: true }));
584 return true;
585 }
586 return false;
587 }
588
589 function getPayoutInfo() {
590 const riseButton = document.getElementById('dt_purchase_call_button');
591 const fallButton = document.getElementById('dt_purchase_put_button');
592
593 if (!riseButton || !fallButton) return null;
594
595 const risePercentText = riseButton.querySelector('.btn-purchase__info--right .dc-text');
596 const fallPercentText = fallButton.querySelector('.btn-purchase__info--right .dc-text');
597
598 if (!risePercentText || !fallPercentText) return null;
599
600 return {
601 rise: parseFloat(risePercentText.textContent.replace('%', '')),
602 fall: parseFloat(fallPercentText.textContent.replace('%', ''))
603 };
604 }
605
606 function analyzeBestTrade() {
607 const payouts = getPayoutInfo();
608 if (!payouts) return botState.tradeType;
609
610 if (payouts.rise > payouts.fall) {
611 console.log('Analysis: Rise better (' + payouts.rise + '% vs ' + payouts.fall + '%)');
612 return 'rise';
613 } else {
614 console.log('Analysis: Fall better (' + payouts.fall + '% vs ' + payouts.rise + '%)');
615 return 'fall';
616 }
617 }
618
619 function analyzeTrend() {
620 // If not enough history, use the selected trade type
621 if (botState.trendHistory.length < 1) {
622 console.log('Trend: No data yet, using selected type:', botState.tradeType);
623 return botState.tradeType;
624 }
625
626 // Get the last tick result
627 const lastTick = botState.trendHistory[botState.trendHistory.length - 1];
628
629 console.log('Trend History:', botState.trendHistory.join(', '));
630 console.log('Last Tick:', lastTick);
631
632 // Bet OPPOSITE of the last tick (reversal strategy)
633 if (lastTick === 'rise') {
634 console.log('Trend: Last tick was RISE → Betting FALL (reversal)');
635 return 'fall';
636 } else {
637 console.log('Trend: Last tick was FALL → Betting RISE (reversal)');
638 return 'rise';
639 }
640 }
641
642 function getNextTradeType() {
643 if (botState.tradeType === 'alternate') {
644 return botState.lastTradeResult === 'rise' ? 'fall' : 'rise';
645 }
646
647 // ALWAYS use trend analysis if we have any history
648 if (botState.trendHistory.length > 0) {
649 return analyzeTrend();
650 }
651
652 // If no history yet, use the selected trade type to start building history
653 return botState.tradeType;
654 }
655
656 function calculateNextStake(won) {
657 let nextStake = botState.currentStake;
658
659 if (botState.strategy === 'martingale') {
660 nextStake = won ? botState.baseStake : botState.currentStake * 2;
661 console.log(won ? 'WIN - Reset to base: ' + nextStake : 'LOSS - Double to: ' + nextStake);
662 } else if (botState.strategy === 'anti-martingale') {
663 nextStake = won ? botState.currentStake * 2 : botState.baseStake;
664 } else {
665 nextStake = botState.baseStake;
666 }
667
668 if (nextStake > botState.maxStake) nextStake = botState.maxStake;
669 if (nextStake < 1) nextStake = 1;
670
671 return Math.round(nextStake * 100) / 100;
672 }
673
674 async function executeTrade(tradeType) {
675 botState.balanceBeforeTrade = getCurrentBalance();
676 if (!botState.balanceBeforeTrade) return false;
677
678 if (!setStakeAmount(botState.currentStake)) return false;
679 await wait(500);
680
681 const buttonId = tradeType === 'rise' ? 'dt_purchase_call_button' : 'dt_purchase_put_button';
682 const tradeButton = document.getElementById(buttonId);
683
684 if (tradeButton && !tradeButton.disabled) {
685 tradeButton.click();
686 console.log('Trade placed:', tradeType, '$' + botState.currentStake);
687 updateStatusText(`Placed ${tradeType} trade: $${botState.currentStake.toFixed(2)}`, true);
688 return true;
689 }
690 return false;
691 }
692
693 async function waitForTradeCompletion() {
694 // Wait for buttons to be disabled (trade starts)
695 for (let i = 0; i < 20; i++) {
696 const riseBtn = document.getElementById('dt_purchase_call_button');
697 const fallBtn = document.getElementById('dt_purchase_put_button');
698 if (riseBtn?.disabled && fallBtn?.disabled) {
699 console.log('Trade started');
700 break;
701 }
702 await wait(500);
703 }
704
705 // Wait for buttons to be enabled (trade completes)
706 for (let i = 0; i < 120; i++) {
707 const riseBtn = document.getElementById('dt_purchase_call_button');
708 const fallBtn = document.getElementById('dt_purchase_put_button');
709 if (riseBtn && !riseBtn.disabled && fallBtn && !fallBtn.disabled) {
710 console.log('Trade completed');
711 return true;
712 }
713 await wait(500);
714 }
715
716 return false;
717 }
718
719 async function getTradeResult() {
720 try {
721 console.log('getTradeResult() START - waiting 3 seconds...');
722 await wait(3000);
723 console.log('getTradeResult() - 3 second wait completed');
724
725 let newBalance = null;
726 console.log('getTradeResult() - starting balance check loop...');
727 for (let i = 0; i < 5; i++) {
728 console.log('Balance check attempt', i + 1, 'of 5');
729 newBalance = getCurrentBalance();
730 console.log('Got balance:', newBalance, 'Previous:', botState.balanceBeforeTrade);
731 if (newBalance) {
732 console.log('Balance retrieved successfully');
733 break;
734 }
735 console.log('Balance is null, waiting 1 second...');
736 await wait(1000);
737 }
738
739 console.log('Balance check loop completed. New:', newBalance, 'Old:', botState.balanceBeforeTrade);
740
741 if (!newBalance || !botState.balanceBeforeTrade) {
742 console.error('Could not get balance. New:', newBalance, 'Old:', botState.balanceBeforeTrade);
743 return null;
744 }
745
746 const profit = newBalance - botState.balanceBeforeTrade;
747 const won = profit > 0;
748
749 console.log('=== RESULT ===');
750 console.log('Before: $' + botState.balanceBeforeTrade.toFixed(2));
751 console.log('After: $' + newBalance.toFixed(2));
752 console.log('Change: $' + profit.toFixed(2));
753 console.log('Result:', won ? 'WIN ✓' : 'LOSS ✗');
754 console.log('==============');
755
756 console.log('getTradeResult() - returning result object');
757 return { won, profit };
758 } catch (error) {
759 console.error('ERROR in getTradeResult():', error);
760 console.error('Error stack:', error.stack);
761 return null;
762 }
763 }
764
765 async function runTradingLoop() {
766 while (botState.isRunning) {
767 try {
768 console.log('--- Trade Cycle | Stake: $' + botState.currentStake + ' ---');
769
770 // Wait for buttons to be ready
771 const riseBtn = document.getElementById('dt_purchase_call_button');
772 const fallBtn = document.getElementById('dt_purchase_put_button');
773
774 if (!riseBtn || !fallBtn || riseBtn.disabled || fallBtn.disabled) {
775 console.log('Buttons not ready, waiting...');
776 await wait(3000);
777 continue;
778 }
779
780 await wait(2000);
781
782 const tradeType = getNextTradeType();
783 const executed = await executeTrade(tradeType);
784
785 if (!executed) {
786 console.log('Trade failed, waiting...');
787 await wait(5000);
788 continue;
789 }
790
791 botState.lastTradeResult = tradeType;
792
793 // Wait for trade to complete
794 console.log('Calling waitForTradeCompletion()...');
795 const completed = await waitForTradeCompletion();
796 console.log('waitForTradeCompletion() returned:', completed);
797
798 if (!completed) {
799 console.error('Trade timeout');
800 stopBot();
801 break;
802 }
803
804 // Get result
805 console.log('Calling getTradeResult()...');
806 const result = await getTradeResult();
807 console.log('getTradeResult() returned:', result);
808
809 if (!result) {
810 console.error('Could not get result');
811 stopBot();
812 break;
813 }
814
815 // Record the actual market result for trend analysis
816 // If we bet rise and won, market went rise. If we bet rise and lost, market went fall.
817 const actualMarketResult = (tradeType === 'rise' && result.won) || (tradeType === 'fall' && !result.won) ? 'rise' : 'fall';
818 botState.trendHistory.push(actualMarketResult);
819
820 // Keep only last 10 results
821 if (botState.trendHistory.length > 10) {
822 botState.trendHistory.shift();
823 }
824
825 console.log('Market result:', actualMarketResult, '| Trend history:', botState.trendHistory.join(', '));
826
827 // Update stats
828 botState.stats.totalTrades++;
829
830 if (result.won) {
831 botState.stats.wins++;
832 botState.stats.winStreak++;
833 botState.stats.lossStreak = 0;
834 botState.stats.profit += result.profit;
835 updateStatusText(`WIN! +$${result.profit.toFixed(2)}`, true);
836 addNotification(`WIN! +$${result.profit.toFixed(2)} | Stake: $${botState.currentStake}`, 'win');
837 } else {
838 botState.stats.losses++;
839 botState.stats.lossStreak++;
840 botState.stats.winStreak = 0;
841 botState.stats.profit += result.profit;
842 updateStatusText(`LOSS! ${result.profit.toFixed(2)}`, true);
843 addNotification(`LOSS! ${result.profit.toFixed(2)} | Stake: $${botState.currentStake}`, 'loss');
844 }
845
846 // Calculate next stake
847 botState.currentStake = calculateNextStake(result.won);
848 console.log('Next stake:', botState.currentStake);
849
850 updateStats();
851
852 // Wait before next trade
853 await wait(botState.delayBetweenTrades);
854
855 } catch (error) {
856 console.error('Error:', error);
857 await wait(5000);
858 }
859 }
860 }
861
862 function init() {
863 console.log('Deriv Even/Odd Bot initializing...');
864
865 if (document.readyState === 'loading') {
866 document.addEventListener('DOMContentLoaded', () => {
867 setTimeout(createBotUI, 2000);
868 });
869 } else {
870 setTimeout(createBotUI, 2000);
871 }
872 }
873
874 init();
875
876})();