Your Name
feat: UI improvements and error suppression - Enhanced dashboard and market pages with improved header buttons, logo, and currency symbol display - Stopped animated ticker - Removed pie chart legends - Added error suppressor for external service errors (SSE, Permissions-Policy warnings) - Improved header button prominence and icon appearance - Enhanced logo with glow effects and better design - Fixed currency symbol visibility in market tables
8b7b267
| /** | |
| * Market Monitoring Agent | |
| * Continuously monitors market and generates signals | |
| */ | |
| export class MarketMonitorAgent { | |
| constructor(config = {}) { | |
| this.symbol = config.symbol || 'BTC'; | |
| this.strategy = config.strategy || 'trend-rsi-macd'; | |
| this.interval = config.interval || 60000; // 1 minute | |
| this.isRunning = false; | |
| this.intervalId = null; | |
| this.lastSignal = null; | |
| this.onSignalCallback = null; | |
| this.onErrorCallback = null; | |
| } | |
| /** | |
| * Starts the monitoring agent | |
| */ | |
| start() { | |
| if (this.isRunning) { | |
| console.warn('[MonitorAgent] Already running'); | |
| return; | |
| } | |
| console.log(`[MonitorAgent] Starting for ${this.symbol} with ${this.strategy}`); | |
| this.isRunning = true; | |
| this.checkMarket(); | |
| this.intervalId = setInterval(() => { | |
| this.checkMarket(); | |
| }, this.interval); | |
| } | |
| /** | |
| * Stops the monitoring agent | |
| */ | |
| stop() { | |
| if (!this.isRunning) return; | |
| console.log('[MonitorAgent] Stopping...'); | |
| this.isRunning = false; | |
| if (this.intervalId) { | |
| clearInterval(this.intervalId); | |
| this.intervalId = null; | |
| } | |
| } | |
| /** | |
| * Checks market conditions and generates signals | |
| */ | |
| async checkMarket() { | |
| try { | |
| const marketData = await this.fetchMarketData(); | |
| const analysis = await this.analyzeMarket(marketData); | |
| if (this.shouldNotify(analysis)) { | |
| this.emitSignal(analysis); | |
| } | |
| } catch (error) { | |
| console.error('[MonitorAgent] Error checking market:', error); | |
| if (this.onErrorCallback) { | |
| this.onErrorCallback(error); | |
| } | |
| } | |
| } | |
| /** | |
| * Fetches current market data with fallback and retry logic | |
| */ | |
| async fetchMarketData(retries = 2) { | |
| const baseUrl = window.location.origin; // Use relative URL for Hugging Face compatibility | |
| const apiUrl = `${baseUrl}/api/market?limit=1&symbol=${this.symbol}`; | |
| for (let attempt = 0; attempt <= retries; attempt++) { | |
| try { | |
| if (attempt > 0) { | |
| const delay = Math.min(1000 * Math.pow(2, attempt - 1), 5000); | |
| await new Promise(resolve => setTimeout(resolve, delay)); | |
| } | |
| const response = await fetch(apiUrl, { | |
| signal: AbortSignal.timeout(10000) | |
| }); | |
| if (!response.ok) { | |
| if (attempt < retries && response.status >= 500) { | |
| continue; // Retry on server errors | |
| } | |
| throw new Error(`Market API returned ${response.status}`); | |
| } | |
| const contentType = response.headers.get('content-type'); | |
| if (!contentType || !contentType.includes('application/json')) { | |
| throw new Error('Invalid response type'); | |
| } | |
| const data = await response.json(); | |
| if (!data || typeof data !== 'object') { | |
| throw new Error('Invalid response format'); | |
| } | |
| if (data.success && Array.isArray(data.items) && data.items.length > 0) { | |
| const item = data.items[0]; | |
| if (!item || typeof item !== 'object') { | |
| throw new Error('Invalid item data'); | |
| } | |
| const price = parseFloat(item.price); | |
| if (isNaN(price) || price <= 0) { | |
| throw new Error('Invalid price data'); | |
| } | |
| return { | |
| symbol: this.symbol, | |
| price: price, | |
| volume: parseFloat(item.volume_24h || 0) || 0, | |
| high24h: parseFloat(item.high_24h || price * 1.05) || price * 1.05, | |
| low24h: parseFloat(item.low_24h || price * 0.95) || price * 0.95, | |
| change24h: parseFloat(item.change_24h || 0) || 0, | |
| }; | |
| } | |
| throw new Error('No market data available'); | |
| } catch (error) { | |
| if (attempt < retries && (error.name === 'AbortError' || error.message.includes('timeout') || error.message.includes('network'))) { | |
| continue; // Retry on network errors | |
| } | |
| console.warn('[MonitorAgent] Fetch error, using fallback:', error.message); | |
| return this.getFallbackMarketData(); | |
| } | |
| } | |
| // If all retries failed, return fallback | |
| return this.getFallbackMarketData(); | |
| } | |
| /** | |
| * Gets fallback market data | |
| */ | |
| getFallbackMarketData() { | |
| const defaultPrices = { | |
| 'BTC': 50000, | |
| 'ETH': 3000, | |
| 'SOL': 100, | |
| 'BNB': 600, | |
| 'XRP': 0.5, | |
| 'ADA': 0.5, | |
| }; | |
| const price = defaultPrices[this.symbol] || 1000; | |
| return { | |
| symbol: this.symbol, | |
| price, | |
| volume: 1000000, | |
| high24h: price * 1.05, | |
| low24h: price * 0.95, | |
| change24h: 0, | |
| }; | |
| } | |
| /** | |
| * Analyzes market using selected strategy | |
| */ | |
| async analyzeMarket(marketData) { | |
| const { analyzeWithStrategy } = await import('./trading-strategies.js'); | |
| return analyzeWithStrategy(this.symbol, this.strategy, marketData); | |
| } | |
| /** | |
| * Determines if a notification should be sent | |
| */ | |
| shouldNotify(analysis) { | |
| if (!this.lastSignal) { | |
| this.lastSignal = analysis; | |
| return true; | |
| } | |
| if (this.lastSignal.signal !== analysis.signal) { | |
| this.lastSignal = analysis; | |
| return true; | |
| } | |
| if (analysis.strength === 'strong' && analysis.confidence >= 80) { | |
| return true; | |
| } | |
| return false; | |
| } | |
| /** | |
| * Emits signal to callback | |
| */ | |
| emitSignal(analysis) { | |
| console.log('[MonitorAgent] New signal:', analysis); | |
| if (this.onSignalCallback) { | |
| this.onSignalCallback(analysis); | |
| } | |
| } | |
| /** | |
| * Sets the signal callback | |
| */ | |
| onSignal(callback) { | |
| this.onSignalCallback = callback; | |
| } | |
| /** | |
| * Sets the error callback | |
| */ | |
| onError(callback) { | |
| this.onErrorCallback = callback; | |
| } | |
| /** | |
| * Updates agent configuration | |
| */ | |
| updateConfig(config) { | |
| if (config.symbol) this.symbol = config.symbol; | |
| if (config.strategy) this.strategy = config.strategy; | |
| if (config.interval) this.interval = config.interval; | |
| if (this.isRunning) { | |
| this.stop(); | |
| this.start(); | |
| } | |
| } | |
| /** | |
| * Gets agent status | |
| */ | |
| getStatus() { | |
| return { | |
| isRunning: this.isRunning, | |
| symbol: this.symbol, | |
| strategy: this.strategy, | |
| interval: this.interval, | |
| lastSignal: this.lastSignal, | |
| }; | |
| } | |
| } | |