/home/devscfvi/web.devsquantum.com/js/utils.js
// ============================================
// UTILITY FUNCTIONS
// ============================================
const API_URL = 'api.php';
const BINANCE_FEE = 0.001; // 0.1% fee
// ============================================
// TRADE MODE & TERMINOLOGY
// ============================================
function getTradeMode() {
return localStorage.getItem('tradeMode') || 'crypto';
}
function setTradeMode(mode) {
localStorage.setItem('tradeMode', mode);
if (window.state) state.tradeMode = mode;
}
function getTerms() {
const mode = getTradeMode();
if (mode === 'stocks') {
return {
asset: 'Stock',
assets: 'Stocks',
assetSymbol: 'Ticker',
assetList: 'Watchlist',
assetListFull: 'Stock Watchlist',
feeLabel: 'Commission',
modeIcon: '📈',
modeLabel: 'Stocks Mode',
placeholder: 'AAPL',
modeColor: 'blue'
};
}
return {
asset: 'Coin',
assets: 'Coins',
assetSymbol: 'Symbol',
assetList: 'Favorites',
assetListFull: 'Favorite Coins',
feeLabel: 'Trading Fees',
modeIcon: '🪙',
modeLabel: 'Crypto Mode',
placeholder: 'BTC',
modeColor: 'violet'
};
}
// Default stocks watchlist
const DEFAULT_STOCKS = ['AAPL', 'TSLA', 'AMZN', 'GOOGL', 'MSFT', 'META', 'NVDA'];
function getStocksWatchlist() {
try {
const stored = localStorage.getItem('stocksWatchlist');
return stored ? JSON.parse(stored) : DEFAULT_STOCKS;
} catch (e) {
return DEFAULT_STOCKS;
}
}
function saveStocksWatchlist(list) {
localStorage.setItem('stocksWatchlist', JSON.stringify(list));
}
// API Helper Functions
async function apiGet(action, params = {}) {
try {
const queryString = new URLSearchParams({ action, ...params }).toString();
const response = await fetch(`${API_URL}?${queryString}`);
return await response.json();
} catch (error) {
console.error('API GET Error:', error);
return { success: false, error: error.message };
}
}
async function apiPost(action, data = {}) {
try {
const response = await fetch(API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action, ...data })
});
return await response.json();
} catch (error) {
console.error('API POST Error:', error);
return { success: false, error: error.message };
}
}
// Toast Notifications
function showToast(message, type = 'success') {
const toast = document.createElement('div');
toast.className = `toast toast-${type}`;
toast.textContent = message;
document.body.appendChild(toast);
setTimeout(() => toast.remove(), 3000);
}
// Format Numbers
function formatCurrency(amount) {
return new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 2,
maximumFractionDigits: 2
}).format(amount);
}
function formatPercent(value) {
return `${value >= 0 ? '+' : ''}${parseFloat(value).toFixed(2)}%`;
}
function formatNumber(num, decimals = 2) {
return parseFloat(num).toFixed(decimals);
}
// Date Formatting
function formatDate(dateString) {
const date = new Date(dateString);
return date.toLocaleDateString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric'
});
}
function formatDateTime(dateString) {
const date = new Date(dateString);
return date.toLocaleString('en-US', {
year: 'numeric',
month: 'short',
day: 'numeric',
hour: '2-digit',
minute: '2-digit'
});
}
function formatTime(dateString) {
const date = new Date(dateString);
return date.toLocaleTimeString('en-US', {
hour: '2-digit',
minute: '2-digit'
});
}
// Calculate Trade Metrics
function calculateTradeMetrics(positionSize, entryPrice, slPercent, tpPercent) {
const position = parseFloat(positionSize) || 0;
const entry = parseFloat(entryPrice) || 0;
const slPct = parseFloat(slPercent) || 0;
const tpPct = parseFloat(tpPercent) || 0;
if (!position || !entry) {
return null;
}
const buyFee = position * BINANCE_FEE;
const quantity = (position - buyFee) / entry;
const slPrice = entry * (1 - slPct / 100);
const tpPrice = entry * (1 + tpPct / 100);
const slSellValue = quantity * slPrice;
const slSellFee = slSellValue * BINANCE_FEE;
const lossAmount = position - (slSellValue - slSellFee);
const tpSellValue = quantity * tpPrice;
const tpSellFee = tpSellValue * BINANCE_FEE;
const profitAmount = (tpSellValue - tpSellFee) - position;
const totalFees = buyFee + Math.max(tpSellFee, slSellFee);
const rewardRiskRatio = profitAmount / lossAmount;
return {
quantity: quantity.toFixed(8),
slPrice: slPrice.toFixed(2),
tpPrice: tpPrice.toFixed(2),
lossAmount: lossAmount.toFixed(2),
profitAmount: profitAmount.toFixed(2),
rewardRiskRatio: rewardRiskRatio.toFixed(2),
fees: totalFees.toFixed(2)
};
}
// Modal Management
function createModal(content, className = '') {
const modal = document.createElement('div');
modal.className = `fixed inset-0 modal-backdrop flex items-center justify-center z-50 p-4 ${className}`;
modal.onclick = (e) => {
if (e.target === modal) modal.remove();
};
const modalContent = document.createElement('div');
modalContent.className = 'glass rounded-3xl p-6 max-w-2xl w-full max-h-[90vh] overflow-y-auto border border-violet-500/20';
modalContent.innerHTML = content;
modal.appendChild(modalContent);
document.body.appendChild(modal);
return modal;
}
function closeAllModals() {
document.querySelectorAll('.modal-backdrop').forEach(modal => modal.remove());
}
// Loading State
function showLoading(targetId = 'app') {
const target = document.getElementById(targetId);
if (target) {
target.innerHTML = `
<div class="flex items-center justify-center min-h-screen">
<div class="spinner"></div>
</div>
`;
}
}
// Local Storage Helpers
function saveToStorage(key, value) {
try {
localStorage.setItem(key, JSON.stringify(value));
return true;
} catch (error) {
console.error('Storage Error:', error);
return false;
}
}
function getFromStorage(key, defaultValue = null) {
try {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : defaultValue;
} catch (error) {
console.error('Storage Error:', error);
return defaultValue;
}
}
// Validation
function validateEmail(email) {
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return re.test(email);
}
function validateNumber(value, min = null, max = null) {
const num = parseFloat(value);
if (isNaN(num)) return false;
if (min !== null && num < min) return false;
if (max !== null && num > max) return false;
return true;
}
// Array Helpers
function groupBy(array, key) {
return array.reduce((result, item) => {
const group = item[key];
if (!result[group]) {
result[group] = [];
}
result[group].push(item);
return result;
}, {});
}
function sumBy(array, key) {
return array.reduce((sum, item) => sum + (parseFloat(item[key]) || 0), 0);
}
function avgBy(array, key) {
if (array.length === 0) return 0;
return sumBy(array, key) / array.length;
}
// Emotion & Category Data
const EMOTIONS = [
{ value: 'confident', label: 'Confident', color: 'green' },
{ value: 'fearful', label: 'Fearful', color: 'red' },
{ value: 'fomo', label: 'FOMO', color: 'yellow' },
{ value: 'greedy', label: 'Greedy', color: 'orange' },
{ value: 'calm', label: 'Calm', color: 'blue' },
{ value: 'anxious', label: 'Anxious', color: 'purple' }
];
const CATEGORIES = [
{ value: 'scalping', label: 'Scalping' },
{ value: 'swing', label: 'Swing Trade' },
{ value: 'breakout', label: 'Breakout' },
{ value: 'pullback', label: 'Pullback' },
{ value: 'reversal', label: 'Reversal' },
{ value: 'trend', label: 'Trend Following' }
];
const MISTAKE_CATEGORIES = [
'Timing',
'Risk Management',
'Profit Management',
'Psychology',
'Planning',
'Analysis'
];
// Get emotion/category label
function getEmotionLabel(value) {
const emotion = EMOTIONS.find(e => e.value === value);
return emotion ? emotion.label : value;
}
function getCategoryLabel(value) {
const category = CATEGORIES.find(c => c.value === value);
return category ? category.label : value;
}
// Chart Colors
const CHART_COLORS = {
primary: '#8b5cf6',
success: '#10b981',
danger: '#ef4444',
warning: '#f59e0b',
info: '#3b82f6',
purple: '#a855f7',
pink: '#ec4899',
teal: '#14b8a6'
};
// Export to CSV
function exportToCSV(data, filename) {
const csv = data.map(row => row.join(',')).join('\n');
const blob = new Blob([csv], { type: 'text/csv' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `${filename}-${Date.now()}.csv`;
a.click();
window.URL.revokeObjectURL(url);
}
// Debounce function
function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// Copy to clipboard
async function copyToClipboard(text) {
try {
await navigator.clipboard.writeText(text);
showToast('Copied to clipboard!', 'success');
return true;
} catch (error) {
console.error('Copy failed:', error);
showToast('Failed to copy', 'error');
return false;
}
}
// Generate unique ID
function generateId() {
return Date.now().toString(36) + Math.random().toString(36).substr(2);
}
// Sleep function
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Confirm dialog
function confirmAction(message) {
return confirm(message);
}
// Prompt dialog
function promptInput(message, defaultValue = '') {
return prompt(message, defaultValue);
}