← Назад
'use strict'; const db = require('./db'); const { getAtmIv, calculateIvRankAndPercentile } = require('../analysis/ivAnalysis'); const logger = require('../utils/logger'); const MIN_HISTORY_POINTS = 10; // need at least this many records before using real rank // Save ATM IV snapshot for each underlying to AtmIvHistory table async function saveAtmIvSnapshots(options, spotPrices) { for (const [underlying, spot] of Object.entries(spotPrices)) { const atm = getAtmIv(options, underlying, spot); if (!atm || atm.iv === 0) continue; try { await db.atmIvHistory.create({ data: { underlying, atmIv: atm.iv, spotPrice: spot, }, }); } catch (err) { logger.error(`ivHistory save error (${underlying}): ${err.message}`); } } } // Return array of atmIv floats for the last N days async function getAtmIvHistory(underlying, days = 30) { const since = new Date(Date.now() - days * 24 * 60 * 60 * 1000); try { const records = await db.atmIvHistory.findMany({ where: { underlying, createdAt: { gte: since } }, orderBy: { createdAt: 'asc' }, select: { atmIv: true }, }); return records.map(r => r.atmIv); } catch (err) { logger.error(`ivHistory query error (${underlying}): ${err.message}`); return []; } } // Full IV context with real historical rank. // Returns null if not enough history — caller should fall back to pseudo-rank. async function getRealIvContext(underlying, currentAtmIv, days = 30) { const history = await getAtmIvHistory(underlying, days); if (history.length < MIN_HISTORY_POINTS) return null; const ranked = calculateIvRankAndPercentile(currentAtmIv, history); return { atmIv: currentAtmIv, ivRank: ranked.ivRank, ivPercentile: ranked.ivPercentile, ivMin: ranked.minIv, ivMax: ranked.maxIv, ivAvg: ranked.avgIv, status: ranked.status, dataPoints: history.length, historyDays: days, source: 'db', }; } // Build real IV contexts for BTC and ETH to pass into strategy analyzer async function buildIvContexts(options, spotPrices) { const contexts = {}; for (const [underlying, spot] of Object.entries(spotPrices)) { const atm = getAtmIv(options, underlying, spot); if (!atm || atm.iv === 0) continue; const ctx = await getRealIvContext(underlying, atm.iv); if (ctx) { contexts[underlying] = { ...ctx, atmSymbol: atm.symbol, atmStrike: atm.strike }; } } return contexts; } module.exports = { saveAtmIvSnapshots, getAtmIvHistory, getRealIvContext, buildIvContexts };