← Назад
'use strict'; const { sendMessage } = require('./telegram'); const config = require('../config'); // In-memory dedup: signalId β†’ timestamp of last sent alert const sentAlerts = new Map(); const DEDUP_TTL_MS = 30 * 60 * 1000; // 30 minutes function shouldSend(signalId) { const lastSent = sentAlerts.get(signalId); return !lastSent || Date.now() - lastSent > DEDUP_TTL_MS; } function formatNumber(key, value) { if (typeof value !== 'number') return String(value); // Show more decimals for small values like IV, gamma, delta if (Math.abs(value) < 0.001) return value.toFixed(6); if (Math.abs(value) < 1) return value.toFixed(4); if (Math.abs(value) >= 10000) return value.toLocaleString('en'); return value.toFixed(2); } function formatSignalMessage(signal) { const dirEmoji = { BULLISH: 'πŸ“ˆ', BEARISH: 'πŸ“‰', NEUTRAL: 'βš–οΈ', NEUTRAL_VOLATILE: 'πŸŒ€', NEUTRAL_RANGE: 'πŸ“Š', NEUTRAL_BULLISH: 'πŸ“ˆ', BULLISH_HEDGED: 'πŸ›‘οΈ', }; const sevEmoji = { EXTREME: 'πŸ”΄', HIGH: '🟠', MEDIUM: '🟑', LOW: '🟒' }; const emoji = dirEmoji[signal.direction] || 'πŸ“Œ'; const sev = sevEmoji[signal.severity] || 'βšͺ'; const paramsText = Object.entries(signal.parameters || {}) .slice(0, 7) .map(([k, v]) => ` β€’ <b>${k}</b>: ${formatNumber(k, v)}`) .join('\n'); return [ `${sev} <b>${signal.strategy.toUpperCase()}</b>`, ``, `${emoji} ${signal.signal} β€” <b>${signal.underlying}</b>`, `Confidence: <b>${signal.confidence}%</b> Severity: ${signal.severity}`, ``, `<i>${signal.description}</i>`, ``, signal.rationale, ``, `<b>ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹:</b>`, paramsText, ``, `<code>${new Date().toISOString()}</code>`, ].join('\n'); } // Process a list of signals and send Telegram notifications for new HIGH+ ones async function processSignals(signals) { if (!config.telegram.botToken || !config.telegram.chatId) return; const minConfidence = config.alerts.minConfidence; const toSend = signals.filter(s => s.confidence >= minConfidence && shouldSend(s.id)); for (const signal of toSend) { await sendMessage(formatSignalMessage(signal)); sentAlerts.set(signal.id, Date.now()); // Small delay to respect Telegram rate limits (30 msg/sec global, 1 msg/sec per chat) await new Promise(r => setTimeout(r, 400)); } } // Periodically clean up old dedup entries setInterval(() => { const cutoff = Date.now() - DEDUP_TTL_MS * 2; for (const [id, ts] of sentAlerts.entries()) { if (ts < cutoff) sentAlerts.delete(id); } }, 15 * 60 * 1000); module.exports = { processSignals };