import axios from 'axios'; const API_BASE = import.meta.env.DEV ? 'http://localhost:8000/api' : '/api'; const api = axios.create({ baseURL: API_BASE, headers: { 'Content-Type': 'application/json' }, }); // Attach JWT token to all requests api.interceptors.request.use((config) => { const token = localStorage.getItem('qh_token'); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); // Handle 401 responses api.interceptors.response.use( (response) => response, (error) => { if (error.response?.status === 401) { localStorage.removeItem('qh_token'); localStorage.removeItem('qh_user'); if (window.location.pathname !== '/login') { window.location.href = '/login'; } } return Promise.reject(error); } ); // ── Auth ───────────────────────────────────────────────────────────────── export const authAPI = { register: (data: { email: string; username: string; password: string; full_name?: string }) => api.post('/auth/register', data), login: (data: { email: string; password: string }) => api.post('/auth/login', data), getProfile: () => api.get('/auth/me'), updateProfile: (data: { full_name?: string; bio?: string }) => api.put('/auth/me', data), }; // ── Market Data ────────────────────────────────────────────────────────── export const dataAPI = { getExchanges: () => api.get('/data/exchanges'), getMarkets: () => api.get('/data/markets'), getSectors: () => api.get('/data/sectors'), getPopularTickers: (market: string = 'US') => api.get(`/data/popular-tickers?market=${market}`), getPrices: (ticker: string, period: string = '1y', interval: string = '1d') => api.get(`/data/prices/${ticker}?period=${period}&interval=${interval}`), getCompanyInfo: (ticker: string) => api.get(`/data/company/${ticker}`), computeFeatures: (data: { ticker: string; features?: string[]; period?: string }) => api.post('/data/features', data), searchNews: (data: { query: string; page_size?: number }) => api.post('/data/news', data), searchTickers: (query: string, limit: number = 15) => api.get(`/data/search-tickers?q=${encodeURIComponent(query)}&limit=${limit}`), }; // ── Quantitative ───────────────────────────────────────────────────────── export const quantAPI = { analyzeFactors: (data: { tickers: string[]; factors?: string[]; period?: string }) => api.post('/quant/factors/analyze', data), getFactorDefinitions: () => api.get('/quant/factors/definitions'), generateSignals: (data: { tickers: string[]; signal_types?: string[]; period?: string }) => api.post('/quant/signals/generate', data), }; // ── Strategies ─────────────────────────────────────────────────────────── export const strategyAPI = { create: (data: any) => api.post('/strategies/', data), list: () => api.get('/strategies/'), get: (id: number) => api.get(`/strategies/${id}`), update: (id: number, data: any) => api.put(`/strategies/${id}`, data), delete: (id: number) => api.delete(`/strategies/${id}`), evaluate: (id: number) => api.post(`/strategies/${id}/evaluate`), convertGraph: (graph: any) => api.post('/strategies/convert-visual-graph', graph), }; // ── Portfolios ─────────────────────────────────────────────────────────── export const portfolioAPI = { create: (data: any) => api.post('/portfolios/', data), list: () => api.get('/portfolios/'), get: (id: number) => api.get(`/portfolios/${id}`), optimize: (data: { tickers: string[]; method?: string; period?: string }) => api.post('/portfolios/optimize', data), }; // ── Risk ───────────────────────────────────────────────────────────────── export const riskAPI = { analyze: (data: { tickers: string[]; period?: string; benchmark_ticker?: string }) => api.post('/risk/analyze', data), correlation: (tickers: string[], period: string = '1y') => api.post(`/risk/correlation?period=${period}`, tickers), }; // ── Backtests ──────────────────────────────────────────────────────────── export const backtestAPI = { run: (data: any) => api.post('/backtests/run', data), list: () => api.get('/backtests/'), get: (id: number) => api.get(`/backtests/${id}`), compare: (strategyIds: number[]) => api.post('/analytics/compare', strategyIds), }; // ── Marketplace ────────────────────────────────────────────────────────── export const marketplaceAPI = { publish: (data: any) => api.post('/marketplace/publish', data), browse: (params?: { category?: string; sort_by?: string; page?: number; search?: string }) => api.get('/marketplace/browse', { params }), leaderboard: (sort_by: string = 'sharpe_ratio', limit: number = 25) => api.get(`/marketplace/leaderboard?sort_by=${sort_by}&limit=${limit}`), }; // ── AI Research ────────────────────────────────────────────────────────── export const researchAPI = { generate: (data: { insight_type: string; tickers?: string[]; context?: string }) => api.post('/research/generate', data), listReports: () => api.get('/research/reports'), getReport: (id: number) => api.get(`/research/reports/${id}`), exportPdf: (id: number) => api.get(`/research/reports/${id}/export/pdf`, { responseType: 'blob' }), exportDocx: (id: number) => api.get(`/research/reports/${id}/export/docx`, { responseType: 'blob' }), }; // ── Holdings ───────────────────────────────────────────────────────────── export const holdingsAPI = { list: () => api.get('/holdings/'), create: (data: any) => api.post('/holdings/', data), update: (id: number, data: any) => api.put(`/holdings/${id}`, data), delete: (id: number) => api.delete(`/holdings/${id}`), summary: () => api.get('/holdings/summary'), stressTest: (data: { scenario_id?: string; custom_shock?: number }) => api.post('/holdings/stress-test', data), allStressTests: () => api.get('/holdings/stress-test/all'), hedgeRecommendations: () => api.get('/holdings/hedge-recommendations'), optionsHedge: () => api.get('/holdings/options-hedge'), rebalance: () => api.get('/holdings/rebalance'), correlation: () => api.get('/holdings/correlation'), }; // ── Sentiment ──────────────────────────────────────────────────────────── export const sentimentAPI = { ticker: (ticker: string) => api.get(`/sentiment/ticker/${ticker}`), marketMood: () => api.get('/sentiment/market-mood'), multi: (tickers: string[]) => api.post('/sentiment/multi', tickers), portfolio: () => api.get('/sentiment/portfolio'), }; // ── Calendar ───────────────────────────────────────────────────────────── export const calendarAPI = { events: (days?: number) => api.get(`/calendar/events${days ? `?days=${days}` : ''}`), publicEvents: (days?: number) => api.get(`/calendar/events/public${days ? `?days=${days}` : ''}`), }; // ── ML Models ──────────────────────────────────────────────────────────── export const mlAPI = { predict: (ticker: string, period?: string, horizon?: number) => api.post('/ml/predict', { ticker, period: period || '2y', horizon: horizon || 5 }), regime: (ticker: string, period?: string, history_days?: number) => api.post('/ml/regime', { ticker, period: period || '2y', history_days: history_days || 60 }), clearCache: () => api.post('/ml/clear-cache'), }; export default api;