| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <title>Forex Signal Dashboard</title> |
| <script src="https://cdn.tailwindcss.com"></script> |
| <script src="https://s3.tradingview.com/tv.js"></script> |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> |
| <style> |
| .tradingview-widget-container { |
| height: 500px; |
| } |
| .signal-card.buy { |
| border-left: 4px solid #10B981; |
| } |
| .signal-card.sell { |
| border-left: 4px solid #EF4444; |
| } |
| .chart-container { |
| height: 500px; |
| position: relative; |
| } |
| .auth-container { |
| background: linear-gradient(135deg, #1e3a8a 0%, #1e40af 100%); |
| } |
| .blurred { |
| filter: blur(5px); |
| pointer-events: none; |
| } |
| </style> |
| </head> |
| <body class="bg-gray-100"> |
| |
| <div id="authModal" class="fixed inset-0 z-50 flex items-center justify-center auth-container"> |
| <div class="bg-white rounded-lg shadow-xl p-8 w-full max-w-md"> |
| <div class="flex justify-between items-center mb-6"> |
| <h2 class="text-2xl font-bold text-gray-800">Welcome to Forex Signals</h2> |
| <button id="closeAuthModal" class="text-gray-500 hover:text-gray-700"> |
| <i class="fas fa-times"></i> |
| </button> |
| </div> |
| |
| <div class="tabs flex mb-6 border-b"> |
| <button id="loginTab" class="tab-btn active px-4 py-2 font-medium text-blue-600 border-b-2 border-blue-600">Login</button> |
| <button id="signupTab" class="tab-btn px-4 py-2 font-medium text-gray-500 hover:text-gray-700">Sign Up</button> |
| </div> |
| |
| <div id="loginForm" class="auth-form"> |
| <div class="mb-4"> |
| <label class="block text-gray-700 mb-2" for="loginEmail">Email</label> |
| <input type="email" id="loginEmail" class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"> |
| </div> |
| <div class="mb-6"> |
| <label class="block text-gray-700 mb-2" for="loginPassword">Password</label> |
| <input type="password" id="loginPassword" class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"> |
| </div> |
| <button id="loginBtn" class="w-full bg-blue-600 text-white py-2 px-4 rounded-lg hover:bg-blue-700 transition duration-200">Login</button> |
| |
| <div class="mt-4 text-center"> |
| <p class="text-gray-600">Or login with</p> |
| <div class="flex justify-center mt-2 space-x-4"> |
| <button class="p-2 bg-red-100 rounded-full text-red-600 hover:bg-red-200"> |
| <i class="fab fa-google"></i> |
| </button> |
| <button class="p-2 bg-gray-100 rounded-full text-gray-800 hover:bg-gray-200"> |
| <i class="fab fa-apple"></i> |
| </button> |
| </div> |
| </div> |
| </div> |
| |
| <div id="signupForm" class="auth-form hidden"> |
| <div class="mb-4"> |
| <label class="block text-gray-700 mb-2" for="signupName">Full Name</label> |
| <input type="text" id="signupName" class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"> |
| </div> |
| <div class="mb-4"> |
| <label class="block text-gray-700 mb-2" for="signupEmail">Email</label> |
| <input type="email" id="signupEmail" class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"> |
| </div> |
| <div class="mb-6"> |
| <label class="block text-gray-700 mb-2" for="signupPassword">Password</label> |
| <input type="password" id="signupPassword" class="w-full px-3 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"> |
| </div> |
| <div class="mb-6"> |
| <label class="block text-gray-700 mb-2">Preferred Currency Pairs</label> |
| <div class="flex flex-wrap gap-2"> |
| <label class="inline-flex items-center"> |
| <input type="checkbox" class="form-checkbox text-blue-600" value="EUR/USD"> |
| <span class="ml-2">EUR/USD</span> |
| </label> |
| <label class="inline-flex items-center"> |
| <input type="checkbox" class="form-checkbox text-blue-600" value="GBP/USD"> |
| <span class="ml-2">GBP/USD</span> |
| </label> |
| <label class="inline-flex items-center"> |
| <input type="checkbox" class="form-checkbox text-blue-600" value="USD/JPY"> |
| <span class="ml-2">USD/JPY</span> |
| </label> |
| <label class="inline-flex items-center"> |
| <input type="checkbox" class="form-checkbox text-blue-600" value="AUD/USD"> |
| <span class="ml-2">AUD/USD</span> |
| </label> |
| <label class="inline-flex items-center"> |
| <input type="checkbox" class="form-checkbox text-blue-600" value="XAU/USD"> |
| <span class="ml-2">XAU/USD</span> |
| </label> |
| </div> |
| </div> |
| <button id="signupBtn" class="w-full bg-blue-600 text-white py-2 px-4 rounded-lg hover:bg-blue-700 transition duration-200">Sign Up</button> |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div id="appContainer" class="blurred"> |
| |
| <header class="bg-white shadow-sm"> |
| <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"> |
| <div class="flex justify-between items-center py-4"> |
| <div class="flex items-center"> |
| <div class="w-10 h-10 bg-blue-600 rounded-full flex items-center justify-center text-white font-bold">FS</div> |
| <h1 class="ml-3 text-xl font-semibold text-gray-900">Forex Signals</h1> |
| </div> |
| <div class="flex items-center space-x-4"> |
| <button id="notificationBtn" class="relative p-2 text-gray-500 hover:text-gray-700"> |
| <i class="fas fa-bell"></i> |
| <span class="absolute top-0 right-0 w-2 h-2 bg-red-500 rounded-full"></span> |
| </button> |
| <div class="relative"> |
| <button id="userMenuBtn" class="flex items-center space-x-2 focus:outline-none"> |
| <div class="w-8 h-8 bg-blue-100 rounded-full flex items-center justify-center text-blue-600"> |
| <i class="fas fa-user"></i> |
| </div> |
| <span class="hidden md:inline text-gray-700">User</span> |
| </button> |
| <div id="userMenu" class="hidden absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg py-1 z-50"> |
| <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Profile</a> |
| <a href="#" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Settings</a> |
| <a href="#" id="logoutBtn" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">Logout</a> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </header> |
|
|
| |
| <main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6"> |
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-6"> |
| |
| <div class="lg:col-span-1 space-y-4"> |
| <div class="bg-white rounded-lg shadow p-4"> |
| <div class="flex justify-between items-center mb-4"> |
| <h2 class="text-lg font-semibold">Active Signals</h2> |
| <button class="text-blue-600 hover:text-blue-800"> |
| <i class="fas fa-sync-alt"></i> |
| </button> |
| </div> |
| <div id="activeSignals" class="space-y-3"> |
| |
| </div> |
| </div> |
|
|
| <div class="bg-white rounded-lg shadow p-4"> |
| <h2 class="text-lg font-semibold mb-4">Signal History</h2> |
| <div id="signalHistory" class="space-y-3"> |
| |
| </div> |
| </div> |
| </div> |
|
|
| |
| <div class="lg:col-span-2 space-y-4"> |
| <div class="bg-white rounded-lg shadow p-4"> |
| <div class="flex justify-between items-center mb-4"> |
| <h2 class="text-lg font-semibold">Market Analysis</h2> |
| <div class="flex space-x-2"> |
| <select id="timeframeSelect" class="border rounded px-2 py-1 text-sm"> |
| <option value="1">1m</option> |
| <option value="5">5m</option> |
| <option value="15">15m</option> |
| <option value="60">1h</option> |
| <option value="240" selected>4h</option> |
| <option value="1D">1D</option> |
| </select> |
| <select id="pairSelect" class="border rounded px-2 py-1 text-sm"> |
| <option value="XAUUSDT">XAU/USDT</option> |
| <option value="EURUSD">EUR/USD</option> |
| <option value="GBPUSD">GBP/USD</option> |
| <option value="USDJPY">USD/JPY</option> |
| <option value="AUDUSD">AUD/USD</option> |
| <option value="USDCAD">USD/CAD</option> |
| <option value="XAUUSD">XAU/USD</option> |
| </select> |
| </div> |
| </div> |
| <div class="chart-container"> |
| <div id="tradingview-chart"></div> |
| </div> |
| </div> |
|
|
| <div class="bg-white rounded-lg shadow p-4"> |
| <h2 class="text-lg font-semibold mb-4">Signal Details</h2> |
| <div id="signalDetails" class="grid grid-cols-1 md:grid-cols-2 gap-4"> |
| <div> |
| <h3 class="font-medium text-gray-700 mb-2">ICT Analysis</h3> |
| <p class="text-gray-600">This signal is based on ICT concepts including FVG, liquidity grabs, and market structure shifts.</p> |
| </div> |
| <div> |
| <h3 class="font-medium text-gray-700 mb-2">Key Levels</h3> |
| <div class="space-y-2"> |
| <div class="flex justify-between"> |
| <span class="text-gray-600">Entry:</span> |
| <span class="font-medium" id="detailEntry">1.0850</span> |
| </div> |
| <div class="flex justify-between"> |
| <span class="text-gray-600">Stop Loss:</span> |
| <span class="font-medium text-red-500" id="detailSL">1.0820</span> |
| </div> |
| <div class="flex justify-between"> |
| <span class="text-gray-600">Take Profit 1:</span> |
| <span class="font-medium text-green-500" id="detailTP1">1.0880</span> |
| </div> |
| <div class="flex justify-between"> |
| <span class="text-gray-600">Take Profit 2:</span> |
| <span class="font-medium text-green-500" id="detailTP2">1.0920</span> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| </main> |
|
|
| |
| <div id="adminPanel" class="hidden fixed inset-0 bg-black bg-opacity-50 z-50 flex items-center justify-center"> |
| <div class="bg-white rounded-lg shadow-xl p-6 w-full max-w-4xl max-h-[90vh] overflow-y-auto"> |
| <div class="flex justify-between items-center mb-6"> |
| <h2 class="text-2xl font-bold">Admin Panel</h2> |
| <button id="closeAdminPanel" class="text-gray-500 hover:text-gray-700"> |
| <i class="fas fa-times"></i> |
| </button> |
| </div> |
| |
| <div class="mb-6"> |
| <h3 class="text-lg font-semibold mb-3">Create New Signal</h3> |
| <form id="signalForm" class="grid grid-cols-1 md:grid-cols-2 gap-4"> |
| <div> |
| <label class="block text-gray-700 mb-1">Currency Pair</label> |
| <select id="signalPair" class="w-full border rounded px-3 py-2"> |
| <option value="EUR/USD">EUR/USD</option> |
| <option value="GBP/USD">GBP/USD</option> |
| <option value="USD/JPY">USD/JPY</option> |
| <option value="AUD/USD">AUD/USD</option> |
| <option value="XAU/USD">XAU/USD</option> |
| </select> |
| </div> |
| <div> |
| <label class="block text-gray-700 mb-1">Direction</label> |
| <select id="signalDirection" class="w-full border rounded px-3 py-2"> |
| <option value="buy">Buy</option> |
| <option value="sell">Sell</option> |
| </select> |
| </div> |
| <div> |
| <label class="block text-gray-700 mb-1">Entry Price</label> |
| <input type="number" step="0.0001" id="signalEntry" class="w-full border rounded px-3 py-2"> |
| </div> |
| <div> |
| <label class="block text-gray-700 mb-1">Stop Loss</label> |
| <input type="number" step="0.0001" id="signalSL" class="w-full border rounded px-3 py-2"> |
| </div> |
| <div> |
| <label class="block text-gray-700 mb-1">Take Profit 1</label> |
| <input type="number" step="0.0001" id="signalTP1" class="w-full border rounded px-3 py-2"> |
| </div> |
| <div> |
| <label class="block text-gray-700 mb-1">Take Profit 2</label> |
| <input type="number" step="0.0001" id="signalTP2" class="w-full border rounded px-3 py-2"> |
| </div> |
| <div class="md:col-span-2"> |
| <label class="block text-gray-700 mb-1">Analysis Notes</label> |
| <textarea id="signalNotes" rows="3" class="w-full border rounded px-3 py-2"></textarea> |
| </div> |
| <div class="md:col-span-2 flex justify-end space-x-3"> |
| <button type="button" id="cancelSignal" class="px-4 py-2 border rounded-lg text-gray-700 hover:bg-gray-100">Cancel</button> |
| <button type="submit" class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">Publish Signal</button> |
| </div> |
| </form> |
| </div> |
| |
| <div> |
| <h3 class="text-lg font-semibold mb-3">Manage Signals</h3> |
| <div class="overflow-x-auto"> |
| <table class="min-w-full divide-y divide-gray-200"> |
| <thead class="bg-gray-50"> |
| <tr> |
| <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Pair</th> |
| <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Direction</th> |
| <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Entry</th> |
| <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Status</th> |
| <th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th> |
| </tr> |
| </thead> |
| <tbody id="adminSignalList" class="bg-white divide-y divide-gray-200"> |
| |
| </tbody> |
| </table> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
|
|
| <script> |
| |
| const activeSignals = [ |
| { |
| id: 1, |
| pair: 'XAU/USDT', |
| direction: 'buy', |
| entry: 2035.50, |
| sl: 2020.00, |
| tp1: 2050.00, |
| tp2: 2075.00, |
| timestamp: new Date(), |
| notes: 'Bullish engulfing pattern at key support level with RSI divergence' |
| }, |
| { |
| id: 2, |
| pair: 'EUR/USD', |
| direction: 'buy', |
| entry: 1.0850, |
| sl: 1.0820, |
| tp1: 1.0880, |
| tp2: 1.0920, |
| timestamp: new Date(), |
| notes: 'ICT FVG with liquidity grab below previous low' |
| }, |
| { |
| id: 3, |
| pair: 'GBP/USD', |
| direction: 'sell', |
| entry: 1.2650, |
| sl: 1.2685, |
| tp1: 1.2600, |
| tp2: 1.2550, |
| timestamp: new Date(Date.now() - 3600000), |
| notes: 'Bearish order block with premium array' |
| } |
| ]; |
| |
| const signalHistory = [ |
| { |
| id: 3, |
| pair: 'USD/JPY', |
| direction: 'buy', |
| entry: 150.80, |
| sl: 150.50, |
| tp1: 151.20, |
| tp2: 151.80, |
| timestamp: new Date(Date.now() - 86400000), |
| closedAt: new Date(Date.now() - 82800000), |
| outcome: 'win', |
| closedPrice: 151.25, |
| notes: 'Liquidity sweep of previous low' |
| }, |
| { |
| id: 4, |
| pair: 'AUD/USD', |
| direction: 'sell', |
| entry: 0.6580, |
| sl: 0.6610, |
| tp1: 0.6550, |
| tp2: 0.6520, |
| timestamp: new Date(Date.now() - 172800000), |
| closedAt: new Date(Date.now() - 169200000), |
| outcome: 'loss', |
| closedPrice: 0.6615, |
| notes: 'Failed breakdown of support' |
| } |
| ]; |
| |
| |
| const authModal = document.getElementById('authModal'); |
| const appContainer = document.getElementById('appContainer'); |
| const loginTab = document.getElementById('loginTab'); |
| const signupTab = document.getElementById('signupTab'); |
| const loginForm = document.getElementById('loginForm'); |
| const signupForm = document.getElementById('signupForm'); |
| const loginBtn = document.getElementById('loginBtn'); |
| const signupBtn = document.getElementById('signupBtn'); |
| const closeAuthModal = document.getElementById('closeAuthModal'); |
| const logoutBtn = document.getElementById('logoutBtn'); |
| const userMenuBtn = document.getElementById('userMenuBtn'); |
| const userMenu = document.getElementById('userMenu'); |
| const adminPanel = document.getElementById('adminPanel'); |
| const closeAdminPanel = document.getElementById('closeAdminPanel'); |
| const activeSignalsContainer = document.getElementById('activeSignals'); |
| const signalHistoryContainer = document.getElementById('signalHistory'); |
| const pairSelect = document.getElementById('pairSelect'); |
| const timeframeSelect = document.getElementById('timeframeSelect'); |
| const signalForm = document.getElementById('signalForm'); |
| const adminSignalList = document.getElementById('adminSignalList'); |
| const detailEntry = document.getElementById('detailEntry'); |
| const detailSL = document.getElementById('detailSL'); |
| const detailTP1 = document.getElementById('detailTP1'); |
| const detailTP2 = document.getElementById('detailTP2'); |
| |
| |
| let tvWidget = null; |
| |
| |
| let currentUser = null; |
| let isAdmin = false; |
| |
| |
| function initApp() { |
| |
| const loggedIn = localStorage.getItem('forexUserLoggedIn'); |
| |
| if (loggedIn) { |
| |
| currentUser = { |
| name: 'John Doe', |
| email: 'john@example.com', |
| isAdmin: localStorage.getItem('forexUserIsAdmin') === 'true' |
| }; |
| isAdmin = currentUser.isAdmin; |
| |
| |
| authModal.classList.add('hidden'); |
| appContainer.classList.remove('blurred'); |
| |
| |
| loadSignals(); |
| initChart(); |
| } else { |
| |
| authModal.classList.remove('hidden'); |
| appContainer.classList.add('blurred'); |
| } |
| |
| |
| setupEventListeners(); |
| } |
| |
| |
| function setupEventListeners() { |
| |
| loginTab.addEventListener('click', () => { |
| loginTab.classList.add('active', 'text-blue-600', 'border-blue-600'); |
| loginTab.classList.remove('text-gray-500'); |
| signupTab.classList.add('text-gray-500'); |
| signupTab.classList.remove('active', 'text-blue-600', 'border-blue-600'); |
| loginForm.classList.remove('hidden'); |
| signupForm.classList.add('hidden'); |
| }); |
| |
| signupTab.addEventListener('click', () => { |
| signupTab.classList.add('active', 'text-blue-600', 'border-blue-600'); |
| signupTab.classList.remove('text-gray-500'); |
| loginTab.classList.add('text-gray-500'); |
| loginTab.classList.remove('active', 'text-blue-600', 'border-blue-600'); |
| signupForm.classList.remove('hidden'); |
| loginForm.classList.add('hidden'); |
| }); |
| |
| |
| loginBtn.addEventListener('click', (e) => { |
| e.preventDefault(); |
| const email = document.getElementById('loginEmail').value; |
| const password = document.getElementById('loginPassword').value; |
| |
| |
| if (email && password) { |
| |
| currentUser = { |
| name: 'John Doe', |
| email: email, |
| isAdmin: email.includes('admin') |
| }; |
| isAdmin = currentUser.isAdmin; |
| |
| |
| localStorage.setItem('forexUserLoggedIn', 'true'); |
| localStorage.setItem('forexUserIsAdmin', isAdmin.toString()); |
| |
| |
| authModal.classList.add('hidden'); |
| appContainer.classList.remove('blurred'); |
| |
| |
| loadSignals(); |
| initChart(); |
| |
| |
| showNotification('Welcome back! Signals loaded successfully.'); |
| } else { |
| alert('Please enter both email and password'); |
| } |
| }); |
| |
| |
| signupBtn.addEventListener('click', (e) => { |
| e.preventDefault(); |
| const name = document.getElementById('signupName').value; |
| const email = document.getElementById('signupEmail').value; |
| const password = document.getElementById('signupPassword').value; |
| |
| |
| if (name && email && password) { |
| |
| currentUser = { |
| name: name, |
| email: email, |
| isAdmin: false |
| }; |
| isAdmin = false; |
| |
| |
| localStorage.setItem('forexUserLoggedIn', 'true'); |
| localStorage.setItem('forexUserIsAdmin', 'false'); |
| |
| |
| authModal.classList.add('hidden'); |
| appContainer.classList.remove('blurred'); |
| |
| |
| loadSignals(); |
| initChart(); |
| |
| |
| showNotification('Welcome to Forex Signals! Your account has been created.'); |
| } else { |
| alert('Please fill in all fields'); |
| } |
| }); |
| |
| |
| closeAuthModal.addEventListener('click', () => { |
| |
| if (!localStorage.getItem('forexUserLoggedIn')) { |
| alert('Please login or sign up to continue'); |
| } else { |
| authModal.classList.add('hidden'); |
| } |
| }); |
| |
| |
| userMenuBtn.addEventListener('click', () => { |
| userMenu.classList.toggle('hidden'); |
| |
| |
| document.addEventListener('click', (e) => { |
| if (!userMenu.contains(e.target) && e.target !== userMenuBtn) { |
| userMenu.classList.add('hidden'); |
| } |
| }, { once: true }); |
| }); |
| |
| |
| logoutBtn.addEventListener('click', () => { |
| localStorage.removeItem('forexUserLoggedIn'); |
| localStorage.removeItem('forexUserIsAdmin'); |
| currentUser = null; |
| isAdmin = false; |
| |
| |
| authModal.classList.remove('hidden'); |
| appContainer.classList.add('blurred'); |
| |
| |
| document.getElementById('loginEmail').value = ''; |
| document.getElementById('loginPassword').value = ''; |
| document.getElementById('signupName').value = ''; |
| document.getElementById('signupEmail').value = ''; |
| document.getElementById('signupPassword').value = ''; |
| |
| |
| loginTab.click(); |
| }); |
| |
| |
| document.getElementById('notificationBtn').addEventListener('click', () => { |
| showNotification('You have no new notifications'); |
| }); |
| |
| |
| pairSelect.addEventListener('change', reloadChart); |
| timeframeSelect.addEventListener('change', reloadChart); |
| |
| |
| signalForm.addEventListener('submit', (e) => { |
| e.preventDefault(); |
| createNewSignal(); |
| }); |
| |
| document.getElementById('cancelSignal').addEventListener('click', () => { |
| signalForm.reset(); |
| }); |
| |
| |
| closeAdminPanel.addEventListener('click', () => { |
| adminPanel.classList.add('hidden'); |
| }); |
| |
| |
| if (isAdmin) { |
| |
| const header = document.querySelector('header .flex.items-center.space-x-4'); |
| const adminBtn = document.createElement('button'); |
| adminBtn.className = 'p-2 text-gray-500 hover:text-gray-700'; |
| adminBtn.innerHTML = '<i class="fas fa-cog"></i>'; |
| adminBtn.addEventListener('click', () => { |
| adminPanel.classList.remove('hidden'); |
| loadAdminSignals(); |
| }); |
| header.insertBefore(adminBtn, header.firstChild); |
| } |
| } |
| |
| |
| function loadSignals() { |
| |
| activeSignalsContainer.innerHTML = ''; |
| signalHistoryContainer.innerHTML = ''; |
| |
| |
| activeSignals.forEach(signal => { |
| const signalCard = createSignalCard(signal, false); |
| activeSignalsContainer.appendChild(signalCard); |
| }); |
| |
| |
| signalHistory.forEach(signal => { |
| const historyCard = createSignalCard(signal, true); |
| signalHistoryContainer.appendChild(historyCard); |
| }); |
| |
| |
| if (activeSignals.length > 0) { |
| showSignalDetails(activeSignals[0]); |
| } |
| } |
| |
| |
| function createSignalCard(signal, isHistory) { |
| const card = document.createElement('div'); |
| card.className = `signal-card ${signal.direction} bg-white rounded shadow p-3 cursor-pointer hover:shadow-md transition duration-200`; |
| card.dataset.id = signal.id; |
| |
| const directionClass = signal.direction === 'buy' ? 'text-green-500' : 'text-red-500'; |
| const directionIcon = signal.direction === 'buy' ? 'fa-arrow-up' : 'fa-arrow-down'; |
| |
| let outcomeBadge = ''; |
| if (isHistory) { |
| const outcomeClass = signal.outcome === 'win' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'; |
| outcomeBadge = `<span class="text-xs px-2 py-1 rounded-full ${outcomeClass} ml-2">${signal.outcome}</span>`; |
| } |
| |
| card.innerHTML = ` |
| <div class="flex justify-between items-start"> |
| <div> |
| <h3 class="font-semibold">${signal.pair}</h3> |
| <p class="text-sm text-gray-500">${formatDate(signal.timestamp)}</p> |
| </div> |
| <div class="flex items-center"> |
| <i class="fas ${directionIcon} ${directionClass}"></i> |
| ${outcomeBadge} |
| </div> |
| </div> |
| <div class="mt-2 grid grid-cols-3 gap-2 text-sm"> |
| <div> |
| <p class="text-gray-500">Entry</p> |
| <p>${signal.entry}</p> |
| </div> |
| <div> |
| <p class="text-gray-500">SL</p> |
| <p class="text-red-500">${signal.sl}</p> |
| </div> |
| <div> |
| <p class="text-gray-500">TP</p> |
| <p class="text-green-500">${signal.tp1}</p> |
| </div> |
| </div> |
| `; |
| |
| |
| card.addEventListener('click', () => { |
| showSignalDetails(signal); |
| |
| |
| document.querySelectorAll('.signal-card').forEach(c => { |
| c.classList.remove('ring-2', 'ring-blue-500'); |
| }); |
| card.classList.add('ring-2', 'ring-blue-500'); |
| }); |
| |
| return card; |
| } |
| |
| |
| function showSignalDetails(signal) { |
| detailEntry.textContent = signal.entry; |
| detailSL.textContent = signal.sl; |
| detailTP1.textContent = signal.tp1; |
| detailTP2.textContent = signal.tp2 || 'N/A'; |
| |
| |
| pairSelect.value = signal.pair.replace('/', ''); |
| reloadChart(); |
| } |
| |
| |
| function formatDate(date) { |
| return new Date(date).toLocaleString('en-US', { |
| month: 'short', |
| day: 'numeric', |
| hour: '2-digit', |
| minute: '2-digit' |
| }); |
| } |
| |
| |
| function initChart() { |
| if (tvWidget !== null) { |
| tvWidget.remove(); |
| tvWidget = null; |
| } |
| |
| const widgetOptions = { |
| symbol: pairSelect.value, |
| interval: timeframeSelect.value, |
| theme: 'light', |
| container_id: 'tradingview-chart', |
| datafeed: new Datafeeds.UDFCompatibleDatafeed(`https://api.twelvedata.com/time_series?symbol=${pairSelect.value}&interval=${timeframeSelect.value}&apikey=cc9af226f2dd41b9af948da524333bd5`), |
| library_path: 'https://s3.tradingview.com/tv.js', |
| locale: 'en', |
| disabled_features: ['header_widget', 'header_compare', 'header_screenshot', 'header_undo_redo', 'header_interval_dialog_button'], |
| enabled_features: ['study_templates'], |
| charts_storage_url: 'https://saveload.tradingview.com', |
| charts_storage_api_version: '1.1', |
| client_id: 'tradingview.com', |
| user_id: 'public_user_id', |
| fullscreen: false, |
| autosize: true, |
| studies_overrides: {}, |
| overrides: { |
| 'paneProperties.background': '#ffffff', |
| 'paneProperties.vertGridProperties.color': '#f0f0f0', |
| 'paneProperties.horzGridProperties.color': '#f0f0f0', |
| 'mainSeriesProperties.candleStyle.upColor': '#388e3c', |
| 'mainSeriesProperties.candleStyle.downColor': '#d32f2f', |
| 'mainSeriesProperties.candleStyle.borderUpColor': '#388e3c', |
| 'mainSeriesProperties.candleStyle.borderDownColor': '#d32f2f', |
| 'mainSeriesProperties.candleStyle.wickUpColor': '#388e3c', |
| 'mainSeriesProperties.candleStyle.wickDownColor': '#d32f2f', |
| 'mainSeriesProperties.priceAxisProperties.autoScale': false, |
| 'mainSeriesProperties.priceAxisProperties.percentage': false, |
| 'mainSeriesProperties.priceAxisProperties.log': false |
| } |
| }; |
| |
| tvWidget = new TradingView.widget(widgetOptions); |
| |
| tvWidget.onChartReady(() => { |
| console.log('Chart has loaded!'); |
| }); |
| } |
| |
| |
| function reloadChart() { |
| initChart(); |
| } |
| |
| |
| function showNotification(message) { |
| alert(message); |
| } |
| |
| |
| function loadAdminSignals() { |
| adminSignalList.innerHTML = ''; |
| |
| const allSignals = [...activeSignals, ...signalHistory]; |
| |
| allSignals.forEach(signal => { |
| const row = document.createElement('tr'); |
| |
| const directionClass = signal.direction === 'buy' ? 'text-green-500' : 'text-red-500'; |
| const directionText = signal.direction === 'buy' ? 'BUY' : 'SELL'; |
| |
| let statusBadge = ''; |
| if (signalHistory.find(s => s.id === signal.id)) { |
| statusBadge = `<span class="px-2 py-1 text-xs rounded-full bg-gray-100 text-gray-800">Closed</span>`; |
| } else { |
| statusBadge = `<span class="px-2 py-1 text-xs rounded-full bg-blue-100 text-blue-800">Active</span>`; |
| } |
| |
| row.innerHTML = ` |
| <td class="px-6 py-4 whitespace-nowrap">${signal.pair}</td> |
| <td class="px-6 py-4 whitespace-nowrap"><span class="${directionClass}">${directionText}</span></td> |
| <td class="px-6 py-4 whitespace-nowrap">${signal.entry}</td> |
| <td class="px-6 py-4 whitespace-nowrap">${statusBadge}</td> |
| <td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium"> |
| <button class="text-blue-600 hover:text-blue-900 mr-2 edit-signal" data-id="${signal.id}">Edit</button> |
| <button class="text-red-600 hover:text-red-900 delete-signal" data-id="${signal.id}">Delete</button> |
| </td> |
| `; |
| |
| adminSignalList.appendChild(row); |
| }); |
| |
| |
| document.querySelectorAll('.edit-signal').forEach(btn => { |
| btn.addEventListener('click', (e) => { |
| const signalId = parseInt(e.target.dataset.id); |
| editSignal(signalId); |
| }); |
| }); |
| |
| document.querySelectorAll('.delete-signal').forEach(btn => { |
| btn.addEventListener('click', (e) => { |
| const signalId = parseInt(e.target.dataset.id); |
| if (confirm('Are you sure you want to delete this signal?')) { |
| deleteSignal(signalId); |
| } |
| }); |
| }); |
| } |
| |
| |
| function editSignal(signalId) { |
| const allSignals = [...activeSignals, ...signalHistory]; |
| const signal = allSignals.find(s => s.id === signalId); |
| |
| if (signal) { |
| document.getElementById('signalPair').value = signal.pair; |
| document.getElementById('signalDirection').value = signal.direction; |
| document.getElementById('signalEntry').value = signal.entry; |
| document.getElementById('signalSL').value = signal.sl; |
| document.getElementById('signalTP1').value = signal.tp1; |
| document.getElementById('signalTP2').value = signal.tp2 || ''; |
| document.getElementById('signalNotes').value = signal.notes; |
| |
| |
| document.getElementById('signalForm').scrollIntoView(); |
| } |
| } |
| |
| |
| function deleteSignal(signalId) { |
| |
| console.log(`Signal ${signalId} deleted`); |
| showNotification('Signal deleted successfully'); |
| loadAdminSignals(); |
| } |
| |
| |
| function createNewSignal() { |
| const pair = document.getElementById('signalPair').value; |
| const direction = document.getElementById('signalDirection').value; |
| const entry = parseFloat(document.getElementById('signalEntry').value); |
| const sl = parseFloat(document.getElementById('signalSL').value); |
| const tp1 = parseFloat(document.getElementById('signalTP1').value); |
| const tp2 = parseFloat(document.getElementById('signalTP2').value) || null; |
| const notes = document.getElementById('signalNotes').value; |
| |
| |
| if (!pair || !direction || isNaN(entry) || isNaN(sl) || isNaN(tp1)) { |
| alert('Please fill in all required fields'); |
| return; |
| } |
| |
| |
| const newSignal = { |
| id: Math.max(...activeSignals.map(s => s.id), ...signalHistory.map(s => s.id)) + 1, |
| pair, |
| direction, |
| entry, |
| sl, |
| tp1, |
| tp2, |
| timestamp: new Date(), |
| notes |
| }; |
| |
| |
| activeSignals.push(newSignal); |
| |
| |
| signalForm.reset(); |
| |
| |
| showNotification('New signal published successfully!'); |
| |
| |
| loadSignals(); |
| loadAdminSignals(); |
| } |
| |
| |
| document.addEventListener('DOMContentLoaded', initApp); |
| </script> |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Abel222/fx" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> |
| </html> |