← Назад
const { Router } = require('express'); const { checkApiKey } = require('../middleware/auth'); const { cache } = require('../services/cache'); const { fetchSpotPrices } = require('../services/binance'); const { findUnusualVolume } = require('../analysis/unusualVolume'); const { findTopMovers } = require('../analysis/topMovers'); const { calculateAllMaxPain } = require('../analysis/maxPain'); const { getAtmIv, calculateIvRankAndPercentile } = require('../analysis/ivAnalysis'); const { analyzeAllPCRatios } = require('../analysis/putCallRatio'); const { analyzeSkew } = require('../analysis/ivSkew'); const { findGammaPlays } = require('../analysis/gammaPlay'); const { analyzeOiConcentration } = require('../analysis/oiConcentration'); const { getAtmIvHistory } = require('../services/ivHistory'); const { mergeGreeksIntoOptions } = require('../utils/mergeGreeks'); const router = Router(); function mergeGreeks(optionsData) { return mergeGreeksIntoOptions(optionsData, cache.greeks); } router.get('/api/signals/unusual-volume', checkApiKey, async (req, res) => { if (!cache.options) { return res.status(503).json({ error: 'Data not ready' }); } const spotPrices = await fetchSpotPrices(); const data = mergeGreeks(cache.options); const result = findUnusualVolume(data, spotPrices, { underlying: req.query.underlying || null, limit: parseInt(req.query.limit) || 30, }); res.json({ success: true, lastUpdate: cache.lastUpdate, ...result }); }); router.get('/api/signals/iv-analysis', checkApiKey, async (req, res) => { if (!cache.options) { return res.status(503).json({ error: 'Data not ready' }); } const days = parseInt(req.query.days) || 30; const spotPrices = await fetchSpotPrices(); const data = mergeGreeks(cache.options); const results = {}; for (const [asset, spot] of Object.entries(spotPrices)) { const atm = getAtmIv(data, asset, spot); if (!atm) continue; const history = await getAtmIvHistory(asset, days); const ranked = calculateIvRankAndPercentile(atm.iv, history); results[asset] = { ...atm, spotPrice: spot, ...ranked, historyDays: days, historyPoints: history.length, rankSource: history.length >= 10 ? 'db' : 'insufficient_history', }; } res.json({ success: true, lastUpdate: cache.lastUpdate, data: results }); }); router.get('/api/signals/max-pain', checkApiKey, async (req, res) => { if (!cache.options) { return res.status(503).json({ error: 'Data not ready' }); } const spotPrices = await fetchSpotPrices(); const data = mergeGreeks(cache.options); const result = calculateAllMaxPain(data, spotPrices); res.json({ success: true, lastUpdate: cache.lastUpdate, count: result.length, data: result }); }); router.get('/api/signals/oi-concentration', checkApiKey, async (req, res) => { if (!cache.options) { return res.status(503).json({ error: 'Data not ready' }); } const data = mergeGreeks(cache.options); const underlying = req.query.underlying ? req.query.underlying.toUpperCase() : null; const result = analyzeOiConcentration(data, { underlying, limit: parseInt(req.query.limit) || 20, }); res.json({ success: true, lastUpdate: cache.lastUpdate, underlying: underlying || 'ALL', count: result.length, data: result, }); }); router.get('/api/signals/put-call-ratio', checkApiKey, (req, res) => { if (!cache.options) { return res.status(503).json({ error: 'Data not ready' }); } const data = mergeGreeks(cache.options); const underlying = req.query.underlying ? req.query.underlying.toUpperCase() : null; const result = analyzeAllPCRatios(data, underlying); res.json({ success: true, lastUpdate: cache.lastUpdate, ...result }); }); router.get('/api/signals/iv-skew', checkApiKey, async (req, res) => { if (!cache.options) { return res.status(503).json({ error: 'Data not ready' }); } const spotPrices = await fetchSpotPrices(); const data = mergeGreeks(cache.options); const results = {}; for (const [asset, spot] of Object.entries(spotPrices)) { results[asset] = analyzeSkew(data, asset, spot); } res.json({ success: true, lastUpdate: cache.lastUpdate, data: results }); }); router.get('/api/signals/gamma-play', checkApiKey, async (req, res) => { if (!cache.options) { return res.status(503).json({ error: 'Data not ready' }); } const spotPrices = await fetchSpotPrices(); const data = mergeGreeks(cache.options); const result = findGammaPlays(data, spotPrices, { limit: parseInt(req.query.limit) || 20, }); res.json({ success: true, lastUpdate: cache.lastUpdate, count: result.length, data: result }); }); module.exports = router;