/* * ============================================================================= * VibeQuant (vquant) — AI-Powered Financial Intelligence Platform * ----------------------------------------------------------------------------- * File: client/src/components/market-ticker.tsx * * Author: Simon-Pierre Boucher * Contact: contact@spboucher.ai * Website: https://www.spboucher.ai * Demo: https://www.vquant.ai * License: MIT (see LICENSE) * * Copyright © 2026 Simon-Pierre Boucher. All rights reserved. * ============================================================================= */ import { useQuery } from "@tanstack/react-query"; import { TrendingUp, TrendingDown } from "lucide-react"; interface MarketIndex { symbol: string; name: string; price: number; change: number; changesPercentage: number; } export function MarketTicker() { const { data: marketIndices } = useQuery({ queryKey: ['market-ticker'], queryFn: async () => { const symbols = [ '^GSPC', // S&P 500 '^DJI', // Dow Jones '^IXIC', // NASDAQ '^RUT', // Russell 2000 '^FTSE', // FTSE 100 '^GDAXI', // DAX '^FCHI', // CAC 40 '^N225', // Nikkei 225 '^HSI', // Hang Seng '^GSPTSE' // S&P/TSX ]; const symbolsParam = symbols.join(','); const res = await fetch(`https://financialmodelingprep.com/stable/quote?symbol=${symbolsParam}&apikey=${import.meta.env.VITE_FMP_API_KEY || 'JeWwQMjWS3H6hBGHaVxKy1WfGyU5ZeFq'}`); if (!res.ok) throw new Error('Failed to fetch market indices'); const data = await res.json(); return data .filter((index: any) => index && index.symbol && index.price != null) .map((index: any) => ({ symbol: index.symbol, name: index.name || index.symbol, price: Number(index.price) || 0, change: Number(index.change) || 0, changesPercentage: Number(index.changesPercentage) || 0, })); }, refetchInterval: 30000, // Refresh every 30 seconds }); if (!marketIndices || marketIndices.length === 0) { return null; } // Duplicate the data to create seamless loop const tickerData = [...marketIndices, ...marketIndices]; return (