modified layout and made it so you can switch between card modals and keep the pricing chart
This commit is contained in:
@@ -8,7 +8,6 @@ export const prerender = false;
|
||||
export const GET: APIRoute = async ({ url }) => {
|
||||
const cardId = Number(url.searchParams.get('cardId')) || 0;
|
||||
|
||||
// Get all skus for this card
|
||||
const cardSkus = await db
|
||||
.select()
|
||||
.from(skus)
|
||||
@@ -20,8 +19,7 @@ export const GET: APIRoute = async ({ url }) => {
|
||||
|
||||
const skuIds = cardSkus.map(s => s.skuId);
|
||||
|
||||
// Fetch price history for all skus
|
||||
const history = await db
|
||||
const historyRows = await db
|
||||
.select({
|
||||
skuId: priceHistory.skuId,
|
||||
calculatedAt: priceHistory.calculatedAt,
|
||||
@@ -33,7 +31,41 @@ export const GET: APIRoute = async ({ url }) => {
|
||||
.where(inArray(priceHistory.skuId, skuIds))
|
||||
.orderBy(priceHistory.calculatedAt);
|
||||
|
||||
return new Response(JSON.stringify(history), {
|
||||
// Rolling 30-day cutoff for volatility
|
||||
const thirtyDaysAgo = new Date(Date.now() - 30 * 86_400_000);
|
||||
|
||||
const byCondition: Record<string, number[]> = {};
|
||||
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<string, { label: string; monthlyVol: number }> = {};
|
||||
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' }
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user