import type { APIRoute } from 'astro'; import { db } from '../../db/index'; import { priceHistory, skus } from '../../db/schema'; import { eq, inArray } from 'drizzle-orm'; export const prerender = false; export const GET: APIRoute = async ({ url }) => { const cardId = Number(url.searchParams.get('cardId')) || 0; const cardSkus = await db .select() .from(skus) .where(eq(skus.cardId, cardId)); if (!cardSkus.length) { return new Response(JSON.stringify([]), { headers: { 'Content-Type': 'application/json' } }); } const skuIds = cardSkus.map(s => s.skuId); const historyRows = await db .select({ skuId: priceHistory.skuId, calculatedAt: priceHistory.calculatedAt, marketPrice: priceHistory.marketPrice, condition: skus.condition, }) .from(priceHistory) .innerJoin(skus, eq(priceHistory.skuId, skus.skuId)) .where(inArray(priceHistory.skuId, skuIds)) .orderBy(priceHistory.calculatedAt); // Rolling 30-day cutoff for volatility const thirtyDaysAgo = new Date(Date.now() - 30 * 86_400_000); const byCondition: Record = {}; for (const row of historyRows) { if (row.marketPrice == null) continue; if (!row.calculatedAt) continue; if (new Date(row.calculatedAt) < thirtyDaysAgo) continue; const price = Number(row.marketPrice); if (price <= 0) continue; if (!byCondition[row.condition]) byCondition[row.condition] = []; byCondition[row.condition].push(price); } function computeVolatility(prices: number[]): { label: string; monthlyVol: number } { if (prices.length < 2) return { label: '—', monthlyVol: 0 }; const returns: number[] = []; for (let i = 1; i < prices.length; i++) { returns.push(Math.log(prices[i] / prices[i - 1])); } const mean = returns.reduce((a, b) => a + b, 0) / returns.length; const variance = returns.reduce((sum, r) => sum + (r - mean) ** 2, 0) / (returns.length - 1); const monthlyVol = Math.sqrt(variance) * Math.sqrt(30); const label = monthlyVol >= 0.30 ? 'High' : monthlyVol >= 0.15 ? 'Medium' : 'Low'; return { label, monthlyVol: Math.round(monthlyVol * 100) / 100 }; } const volatilityByCondition: Record = {}; for (const [condition, prices] of Object.entries(byCondition)) { volatilityByCondition[condition] = computeVolatility(prices); } return new Response(JSON.stringify({ history: historyRows, volatilityByCondition }), { headers: { 'Content-Type': 'application/json' } }); };