// Qoutex Trading Bot Simulator - Frontend Logic
class TradingBot {
constructor() {
this.balance = 10000;
this.equity = 10000;
this.positions = [];
this.trades = [];
this.wins = 0;
this.losses = 0;
this.isRunning = false;
this.interval = null;
this.currentPrice = 1.1000;
this.chartData = [];
this.chartLabels = [];
this.initChart();
this.loadEventListeners();
this.startPriceSimulation();
}
initChart() {
const ctx = document.getElementById('priceChart').getContext('2d');
this.chart = new Chart(ctx, {
type: 'line',
data: {
labels: [],
datasets: [{
label: 'Price',
data: [],
borderColor: 'rgb(102, 126, 234)',
backgroundColor: 'rgba(102, 126, 234, 0.1)',
tension: 0.1,
fill: true
}]
},
options: {
responsive: true,
maintainAspectRatio: true,
plugins: {
legend: {
display: true,
position: 'top'
}
},
scales: {
y: {
ticks: {
callback: function(value) {
return '$' + value.toFixed(4);
}
}
}
}
}
});
}
loadEventListeners() {
document.getElementById('startBot').addEventListener('click', () => this.startBot());
document.getElementById('stopBot').addEventListener('click', () => this.stopBot());
document.getElementById('pair').addEventListener('change', (e) => this.changePair(e.target.value));
}
startPriceSimulation() {
setInterval(() => {
if (!this.isRunning) return;
// Simulate price movement with random walk + trend
const change = (Math.random() - 0.5) * 0.002;
this.currentPrice += change;
// Update chart
this.chartLabels.push(new Date().toLocaleTimeString());
this.chartData.push(this.currentPrice);
if (this.chartData.length > 50) {
this.chartData.shift();
this.chartLabels.shift();
}
this.chart.data.labels = this.chartLabels;
this.chart.data.datasets[0].data = this.chartData;
this.chart.update();
// Update equity display
this.updateEquity();
// Execute trading signals
this.executeStrategy();
}, 1000);
}
executeStrategy() {
const strategy = document.getElementById('strategy').value;
let signal = null;
switch(strategy) {
case 'rsi':
signal = this.rsiStrategy();
break;
case 'macd':
signal = this.macdStrategy();
break;
case 'bollinger':
signal = this.bollingerStrategy();
break;
}
if (signal && this.positions.length === 0) {
this.openPosition(signal);
}
// Check for take profit / stop loss
this.checkPositionExit();
}
rsiStrategy() {
// Simplified RSI calculation using price changes
const period = 14;
if (this.chartData.length < period) return null;
let gains = 0;
let losses = 0;
for (let i = this.chartData.length - period; i < this.chartData.length - 1; i++) {
const change = this.chartData[i + 1] - this.chartData[i];
if (change > 0) gains += change;
else losses -= change;
}
const avgGain = gains / period;
const avgLoss = losses / period;
const rs = avgGain / avgLoss;
const rsi = 100 - (100 / (1 + rs));
// RSI signals
if (rsi < 30) return 'BUY';
if (rsi > 70) return 'SELL';
return null;
}
macdStrategy() {
// Simplified MACD strategy
if (this.chartData.length < 26) return null;
const ema12 = this.calculateEMA(12);
const ema26 = this.calculateEMA(26);
const macd = ema12 - ema26;
const signal = this.calculateSignal(macd);
if (macd > signal && this.previousMACD <= this.previousSignal) return 'BUY';
if (macd < signal && this.previousMACD >= this.previousSignal) return 'SELL';
this.previousMACD = macd;
this.previousSignal = signal;
return null;
}
bollingerStrategy() {
if (this.chartData.length < 20) return null;
const sma = this.calculateSMA(20);
const stdDev = this.calculateStdDev(20);
const upperBand = sma + (stdDev * 2);
const lowerBand = sma - (stdDev * 2);
const currentPrice = this.currentPrice;
if (currentPrice < lowerBand) return 'BUY';
if (currentPrice > upperBand) return 'SELL';
return null;
}
calculateEMA(period) {
const multiplier = 2 / (period + 1);
let ema = this.chartData[this.chartData.length - period];
for (let i = this.chartData.length - period + 1; i < this.chartData.length; i++) {
ema = (this.chartData[i] - ema) * multiplier + ema;
}
return ema;
}
calculateSMA(period) {
const slice = this.chartData.slice(-period);
return slice.reduce((a, b) => a + b, 0) / period;
}
calculateStdDev(period) {
const sma = this.calculateSMA(period);
const slice = this.chartData.slice(-period);
const variance = slice.reduce((acc, price) => acc + Math.pow(price - sma, 2), 0) / period;
return Math.sqrt(variance);
}
calculateSignal(macd) {
// Simplified signal line (9-period EMA of MACD)
return macd * 0.9;
}
openPosition(signal) {
const lotSize = parseFloat(document.getElementById('lotSize').value);
const stopLoss = parseFloat(document.getElementById('stopLoss').value);
const takeProfit = parseFloat(document.getElementById('takeProfit').value);
const position = {
id: Date.now(),
type: signal,
entryPrice: this.currentPrice,
lotSize: lotSize,
stopLoss: stopLoss,
takeProfit: takeProfit,
openTime: new Date()
};
this.positions.push(position);
this.addTradeLog(`OPEN ${signal}: ${lotSize} lots at ${this.currentPrice.toFixed(4)}`);
}
checkPositionExit() {
for (let i = 0; i < this.positions.length; i++) {
const pos = this.positions[i];
let exitPrice = null;
let reason = '';
if (pos.type === 'BUY') {
const profitTarget = pos.entryPrice + (pos.takeProfit * 0.0001);
const stopLossPrice = pos.entryPrice - (pos.stopLoss * 0.0001);
if (this.currentPrice >= profitTarget) {
exitPrice = profitTarget;
reason = 'Take Profit';
this.wins++;
} else if (this.currentPrice <= stopLossPrice) {
exitPrice = stopLossPrice;
reason = 'Stop Loss';
this.losses++;
}
} else if (pos.type === 'SELL') {
const profitTarget = pos.entryPrice - (pos.takeProfit * 0.0001);
const stopLossPrice = pos.entryPrice + (pos.stopLoss * 0.0001);
if (this.currentPrice <= profitTarget) {
exitPrice = profitTarget;
reason = 'Take Profit';
this.wins++;
} else if (this.currentPrice >= stopLossPrice) {
exitPrice = stopLossPrice;
reason = 'Stop Loss';
this.losses++;
}
}
if (exitPrice) {
const profit = this.calculateProfit(pos, exitPrice);
this.balance += profit;
this.trades.push({ ...pos, exitPrice, profit, reason });
this.positions.splice(i, 1);
this.addTradeLog(`CLOSE ${pos.type}: ${reason} - Profit: $${profit.toFixed(2)}`);
i--;
}
}
this.updateStats();
}
calculateProfit(position, exitPrice) {
const pipDifference = Math.abs(exitPrice - position.entryPrice) / 0.0001;
const profit = pipDifference * position.lotSize * 10;
return position.type === 'BUY' ? profit : -profit;
}
updateEquity() {
let floatingPL = 0;
for (const pos of this.positions) {
if (pos.type === 'BUY') {
floatingPL += (this.currentPrice - pos.entryPrice) / 0.0001 * pos.lotSize * 10;
} else {
floatingPL += (pos.entryPrice - this.currentPrice) / 0.0001 * pos.lotSize * 10;
}
}
this.equity = this.balance + floatingPL;
document.getElementById('equity').textContent = `$${this.equity.toFixed(2)}`;
}
updateStats() {
document.getElementById('balance').textContent = `$${this.balance.toFixed(2)}`;
const totalPnL = this.balance - 10000;
document.getElementById('pnl').textContent = `${totalPnL >= 0 ? '+' : ''}$${totalPnL.toFixed(2)}`;
document.getElementById('pnl').className = totalPnL >= 0 ? 'stat-value profit' : 'stat-value loss';
const totalTrades = this.wins + this.losses;
const winRate = totalTrades > 0 ? (this.wins / totalTrades * 100).toFixed(1) : 0;
document.getElementById('winRate').textContent = `${winRate}%`;
document.getElementById('totalTrades').textContent = totalTrades;
}
addTradeLog(message) {
const logDiv = document.getElementById('tradeLog');
const entry = document.createElement('div');
entry.className = `trade-entry trade-${message.includes('BUY') ? 'buy' : 'sell'}`;
entry.innerHTML = `[${new Date().toLocaleTimeString()}] ${message}`;
logDiv.insertBefore(entry, logDiv.firstChild);
if (logDiv.children.length > 50) {
logDiv.removeChild(logDiv.lastChild);
}
}
changePair(pair) {
this.addTradeLog(`Changed trading pair to ${pair}`);
// Reset price based on pair
switch(pair) {
case 'EURUSD':
this.currentPrice = 1.1000;
break;
case 'GBPUSD':
this.currentPrice = 1.3000;
break;
case 'BTCUSD':
this.currentPrice = 50000;
break;
}
}
startBot() {
if (!this.isRunning) {
this.isRunning = true;
document.getElementById('botStatus').className = 'status status-active';
document.getElementById('botStatusText').textContent = 'Running';
this.addTradeLog('🤖 Bot started');
}
}
stopBot() {
if (this.isRunning) {
this.isRunning = false;
document.getElementById('botStatus').className = 'status status-inactive';
document.getElementById('botStatusText').textContent = 'Stopped';
this.addTradeLog('🛑 Bot stopped');
}
}
}
// Initialize the bot
const tradingBot = new TradingBot();