← Back
'use strict';

const prisma = require('./db');
const logger = require('../utils/logger');

// Log all signals from a slow update cycle to SignalLog table.
// Only logs NEW signals (dedup by signalId, won't re-log the same signal within 6h).
const DEDUP_HOURS = 6;

async function logSignals(signals, spotPrices) {
  if (!signals || signals.length === 0) return;

  let logged = 0;

  for (const sig of signals) {
    if (!sig.id || !sig.underlying) continue;

    const spot = spotPrices[sig.underlying] || 0;
    if (spot === 0) continue;

    try {
      // Check if already logged recently (within DEDUP_HOURS)
      const cutoff = new Date(Date.now() - DEDUP_HOURS * 60 * 60 * 1000);
      // Dedup: check for same strategy+underlying+direction within DEDUP_HOURS
      // Use stable key (not signalId which had timestamp suffix bug)
      const dedupKey = `${sig.strategy || 'Unknown'}:${sig.underlying}`;
      const existing = await prisma.signalLog.findFirst({
        where: {
          strategy: sig.strategy || 'Unknown',
          underlying: sig.underlying,
          createdAt: { gte: cutoff },
        },
        orderBy: { createdAt: 'desc' },
      });
      if (existing) continue;

      // Unique signalId: stable id + timestamp (for DB uniqueness constraint)
      const uniqueId = `${sig.id}_${Date.now()}`;

      // Infer direction from strategy/signal if not explicit
      let direction = sig.direction || 'NEUTRAL';
      if (direction === 'NEUTRAL') {
        const s = (sig.signal || '').toUpperCase();
        const st = (sig.strategy || '').toUpperCase();
        if (s.includes('CALL') || s.includes('BULL') || st.includes('CALL')) direction = 'BULLISH';
        else if (s.includes('PUT') || s.includes('BEAR') || st.includes('PUT')) direction = 'BEARISH';
      }

      await prisma.signalLog.create({
        data: {
          signalId: uniqueId,
          strategy: sig.strategy || 'Unknown',
          underlying: sig.underlying,
          direction,
          confidence: sig.confidence || 0,
          severity: sig.severity || 'LOW',
          spotAtSignal: spot,
          parameters: JSON.stringify(sig.parameters || {}),
          description: sig.description || sig.rationale || '',
        },
      });
      logged++;
    } catch (err) {
      // Unique constraint — already exists, skip
      if (err.code === 'P2002') continue;
      logger.error(`signalLogger: error logging ${sig.id}: ${err.message}`);
    }
  }

  if (logged > 0) {
    logger.info(`signalLogger: logged ${logged} new signals`);
  }
}

module.exports = { logSignals };

📜 Git History

1f928d1fix: signal dedup was broken — 5615 duplicates cleaned, sortable backtest tables3 months ago
612398cfeat: signal reliability overhaul — OI data, liquidity gate, realistic PnL tracking3 months ago
e12be00feat: Historical Signals Backtest tracking (Task 2.4)3 months ago
Show last diff
Loading...