From 83480c09248c5530b050a48624e8ba95dd21a200 Mon Sep 17 00:00:00 2001 From: Annie Weng <126124914+Anniew31@users.noreply.github.com> Date: Sun, 19 Apr 2026 19:17:37 -0400 Subject: [PATCH] fix: add fallback when no feed data, arbitrage response aliases and volume field alias --- api/feed.ts | 45 +++++++++++++++++++++++++++++++--------- api/markets/arbitrage.ts | 10 ++++++++- src/types/market.ts | 1 + 3 files changed, 45 insertions(+), 11 deletions(-) diff --git a/api/feed.ts b/api/feed.ts index 4250c14..177312c 100644 --- a/api/feed.ts +++ b/api/feed.ts @@ -2,6 +2,7 @@ import type { VercelRequest, VercelResponse } from '@vercel/node'; import type { AnalyzedTweet, FeedResponse, AccountCategory } from '../src/types/feed'; import { batchGetFromKV, setFeedCache, getFeedCache, getFeedCacheTimestamp } from './lib/cache-helper'; import { kv } from './lib/vercel-kv'; +import { getMarkets } from './lib/market-cache' // ─── KV Storage Keys ─────────────────────────────────────────────────────── @@ -129,18 +130,43 @@ export default async function handler( if (feedIndex.length === 0) { // Empty feed (not an error) + // Fall back to live market movers so the feed always returns something + const markets = await getMarkets(); + + const movingMarkets = markets + .filter(m => m.platform === 'polymarket') + .filter(m => Math.abs(m.oneDayPriceChange ?? 0) >= 0.04) + .sort((a, b) => Math.abs(b.oneDayPriceChange ?? 0) - Math.abs(a.oneDayPriceChange ?? 0)) + .slice(0, limit); + + const syntheticTweets = movingMarkets.map(market => ({ + tweet: { + id: `synthetic-${market.id}`, + text: market.title, + author: 'synthetic one', + created_at: new Date().toISOString(), + metrics: { likes: 0, retweets: 0, replies: 0, quotes: 0 }, + url: market.url, + }, + matches: [], + sentiment: { + sentiment: (market.oneDayPriceChange ?? 0) > 0 ? 'bullish' : 'bearish', + confidence: Math.min(Math.abs(market.oneDayPriceChange ?? 0) * 4, 0.95), + }, + category: market.category ?? 'finance', + urgency: Math.abs(market.oneDayPriceChange ?? 0) >= 0.10 ? 'high' : 'medium', + confidence: Math.min(0.5 + Math.abs(market.oneDayPriceChange ?? 0) * 2, 0.95), + analyzed_at: new Date().toISOString(), + collected_at: new Date().toISOString(), + })); + const response: FeedResponse = { success: true, data: { - tweets: [], - count: 0, + tweets: syntheticTweets as any, + count: syntheticTweets.length, timestamp: new Date().toISOString(), - filters: { - limit, - category, - minUrgency, - since, - }, + filters: { limit, category, minUrgency, since }, metadata: { processing_time_ms: Date.now() - startTime, total_in_kv: 0, @@ -148,8 +174,7 @@ export default async function handler( }, }; - // Cache for 30 seconds - res.setHeader('Cache-Control', 's-maxage=30, stale-while-revalidate'); + res.setHeader('Cache-Control', 's-maxage=20, stale-while-revalidate'); res.status(200).json(response); return; } diff --git a/api/markets/arbitrage.ts b/api/markets/arbitrage.ts index 26a2f2a..d387d66 100644 --- a/api/markets/arbitrage.ts +++ b/api/markets/arbitrage.ts @@ -87,6 +87,13 @@ export default async function handler( .filter(arb => !category || arb.polymarket.category === category || arb.kalshi.category === category) .slice(0, limitNum); + // add volume alias to market objects because bot uses volume instead of volume24h + const opportunitiesAlias = opportunities.map (arb => ({ + ...arb, + polymarket: { ...arb.polymarket, volume: arb.polymarket.volume24h }, + kalshi: { ...arb.kalshi, volume: arb.kalshi.volume24h }, + })); + // Stage 0: Get freshness metadata const freshnessMetadata = getMarketMetadata(); @@ -94,7 +101,8 @@ export default async function handler( const response = { success: true, data: { - opportunities, + opportunities: opportunitiesAlias, + arbitrage_opportunities : opportunitiesAlias, //a key mismatch from bot count: opportunities.length, timestamp: new Date().toISOString(), filters: { diff --git a/src/types/market.ts b/src/types/market.ts index 93edfba..03b1a8c 100644 --- a/src/types/market.ts +++ b/src/types/market.ts @@ -13,6 +13,7 @@ export interface Market { noBid?: number; // best executable NO bid when available noAsk?: number; // best executable NO ask when available volume24h: number; // 24h trading volume in dollars + volume?: number; // alias for volume24h, added so bot can use url: string; category: string; lastUpdated: string; // ISO timestamp