fx / index.html
Abel222's picture
Use https://twelvedata.com API key cc9af226f2dd41b9af948da524333bd5 for real time data - Initial Deployment
c1b01fe verified
<!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">
<!-- Auth Modal -->
<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>
<!-- Main App -->
<div id="appContainer" class="blurred">
<!-- Header -->
<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 Content -->
<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">
<!-- Left Column - Signals -->
<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">
<!-- Signal cards will be added here by JavaScript -->
</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">
<!-- History cards will be added here by JavaScript -->
</div>
</div>
</div>
<!-- Right Column - Chart and Details -->
<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>
<!-- Admin Panel (hidden by default) -->
<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">
<!-- Admin signal list will be populated here -->
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<script>
// Sample data
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'
}
];
// DOM Elements
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');
// Chart variables
let tvWidget = null;
// Current user state
let currentUser = null;
let isAdmin = false;
// Initialize the app
function initApp() {
// Check if user is logged in (in a real app, this would check localStorage or cookies)
const loggedIn = localStorage.getItem('forexUserLoggedIn');
if (loggedIn) {
// Simulate getting user data
currentUser = {
name: 'John Doe',
email: 'john@example.com',
isAdmin: localStorage.getItem('forexUserIsAdmin') === 'true'
};
isAdmin = currentUser.isAdmin;
// Hide auth modal and show app
authModal.classList.add('hidden');
appContainer.classList.remove('blurred');
// Load data
loadSignals();
initChart();
} else {
// Show auth modal
authModal.classList.remove('hidden');
appContainer.classList.add('blurred');
}
// Setup event listeners
setupEventListeners();
}
// Setup all event listeners
function setupEventListeners() {
// Auth modal tabs
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');
});
// Login button
loginBtn.addEventListener('click', (e) => {
e.preventDefault();
const email = document.getElementById('loginEmail').value;
const password = document.getElementById('loginPassword').value;
// Simple validation
if (email && password) {
// In a real app, this would call your authentication API
currentUser = {
name: 'John Doe',
email: email,
isAdmin: email.includes('admin')
};
isAdmin = currentUser.isAdmin;
// Store login state
localStorage.setItem('forexUserLoggedIn', 'true');
localStorage.setItem('forexUserIsAdmin', isAdmin.toString());
// Hide auth modal and show app
authModal.classList.add('hidden');
appContainer.classList.remove('blurred');
// Load data
loadSignals();
initChart();
// Show welcome notification
showNotification('Welcome back! Signals loaded successfully.');
} else {
alert('Please enter both email and password');
}
});
// Signup button
signupBtn.addEventListener('click', (e) => {
e.preventDefault();
const name = document.getElementById('signupName').value;
const email = document.getElementById('signupEmail').value;
const password = document.getElementById('signupPassword').value;
// Simple validation
if (name && email && password) {
// In a real app, this would call your registration API
currentUser = {
name: name,
email: email,
isAdmin: false
};
isAdmin = false;
// Store login state
localStorage.setItem('forexUserLoggedIn', 'true');
localStorage.setItem('forexUserIsAdmin', 'false');
// Hide auth modal and show app
authModal.classList.add('hidden');
appContainer.classList.remove('blurred');
// Load data
loadSignals();
initChart();
// Show welcome notification
showNotification('Welcome to Forex Signals! Your account has been created.');
} else {
alert('Please fill in all fields');
}
});
// Close auth modal
closeAuthModal.addEventListener('click', () => {
// In a real app, you might not want to allow closing if not logged in
if (!localStorage.getItem('forexUserLoggedIn')) {
alert('Please login or sign up to continue');
} else {
authModal.classList.add('hidden');
}
});
// User menu
userMenuBtn.addEventListener('click', () => {
userMenu.classList.toggle('hidden');
// Close when clicking outside
document.addEventListener('click', (e) => {
if (!userMenu.contains(e.target) && e.target !== userMenuBtn) {
userMenu.classList.add('hidden');
}
}, { once: true });
});
// Logout
logoutBtn.addEventListener('click', () => {
localStorage.removeItem('forexUserLoggedIn');
localStorage.removeItem('forexUserIsAdmin');
currentUser = null;
isAdmin = false;
// Show auth modal and blur app
authModal.classList.remove('hidden');
appContainer.classList.add('blurred');
// Reset forms
document.getElementById('loginEmail').value = '';
document.getElementById('loginPassword').value = '';
document.getElementById('signupName').value = '';
document.getElementById('signupEmail').value = '';
document.getElementById('signupPassword').value = '';
// Switch to login tab
loginTab.click();
});
// Notification button
document.getElementById('notificationBtn').addEventListener('click', () => {
showNotification('You have no new notifications');
});
// Pair and timeframe select changes
pairSelect.addEventListener('change', reloadChart);
timeframeSelect.addEventListener('change', reloadChart);
// Signal form
signalForm.addEventListener('submit', (e) => {
e.preventDefault();
createNewSignal();
});
document.getElementById('cancelSignal').addEventListener('click', () => {
signalForm.reset();
});
// Close admin panel
closeAdminPanel.addEventListener('click', () => {
adminPanel.classList.add('hidden');
});
// Check if user is admin (for demo purposes)
if (isAdmin) {
// Add admin button to header
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);
}
}
// Load signals into the UI
function loadSignals() {
// Clear existing signals
activeSignalsContainer.innerHTML = '';
signalHistoryContainer.innerHTML = '';
// Add active signals
activeSignals.forEach(signal => {
const signalCard = createSignalCard(signal, false);
activeSignalsContainer.appendChild(signalCard);
});
// Add historical signals
signalHistory.forEach(signal => {
const historyCard = createSignalCard(signal, true);
signalHistoryContainer.appendChild(historyCard);
});
// If there are active signals, show the first one's details
if (activeSignals.length > 0) {
showSignalDetails(activeSignals[0]);
}
}
// Create a signal card element
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>
`;
// Add click event to show details
card.addEventListener('click', () => {
showSignalDetails(signal);
// Highlight selected card
document.querySelectorAll('.signal-card').forEach(c => {
c.classList.remove('ring-2', 'ring-blue-500');
});
card.classList.add('ring-2', 'ring-blue-500');
});
return card;
}
// Show signal details in the right panel
function showSignalDetails(signal) {
detailEntry.textContent = signal.entry;
detailSL.textContent = signal.sl;
detailTP1.textContent = signal.tp1;
detailTP2.textContent = signal.tp2 || 'N/A';
// Update chart with this pair
pairSelect.value = signal.pair.replace('/', '');
reloadChart();
}
// Format date for display
function formatDate(date) {
return new Date(date).toLocaleString('en-US', {
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
}
// Initialize TradingView chart
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!');
});
}
// Reload chart with new symbol/interval
function reloadChart() {
initChart();
}
// Show notification
function showNotification(message) {
alert(message); // In a real app, you'd use a more elegant notification system
}
// Load signals for admin panel
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);
});
// Add event listeners to edit/delete buttons
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);
}
});
});
}
// Edit signal
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;
// Scroll to form
document.getElementById('signalForm').scrollIntoView();
}
}
// Delete signal
function deleteSignal(signalId) {
// In a real app, this would call your API to delete the signal
console.log(`Signal ${signalId} deleted`);
showNotification('Signal deleted successfully');
loadAdminSignals();
}
// Create new signal
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;
// Simple validation
if (!pair || !direction || isNaN(entry) || isNaN(sl) || isNaN(tp1)) {
alert('Please fill in all required fields');
return;
}
// Create new signal object
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
};
// Add to active signals (in a real app, this would call your API)
activeSignals.push(newSignal);
// Reset form
signalForm.reset();
// Show success message
showNotification('New signal published successfully!');
// Reload signals
loadSignals();
loadAdminSignals();
}
// Initialize the app when DOM is loaded
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>