147 lines
4.3 KiB
TypeScript
147 lines
4.3 KiB
TypeScript
/**
|
|
* Market data routes
|
|
*/
|
|
import { Hono } from 'hono';
|
|
import type { IServiceContainer } from '@stock-bot/handlers';
|
|
import { getLogger } from '@stock-bot/logger';
|
|
import { processItems } from '@stock-bot/queue';
|
|
|
|
const logger = getLogger('market-data-routes');
|
|
|
|
export function createMarketDataRoutes(container: IServiceContainer) {
|
|
const marketDataRoutes = new Hono();
|
|
|
|
// Market data endpoints
|
|
marketDataRoutes.get('/api/live/:symbol', async c => {
|
|
const symbol = c.req.param('symbol');
|
|
logger.info('Live data request', { symbol });
|
|
|
|
try {
|
|
// Queue job for live data using Yahoo provider
|
|
const queueManager = container.queue;
|
|
if (!queueManager) {
|
|
return c.json({ status: 'error', message: 'Queue manager not available' }, 503);
|
|
}
|
|
|
|
const queue = queueManager.getQueue('yahoo-finance');
|
|
const job = await queue.add('live-data', {
|
|
handler: 'yahoo-finance',
|
|
operation: 'live-data',
|
|
payload: { symbol },
|
|
});
|
|
return c.json({
|
|
status: 'success',
|
|
message: 'Live data job queued',
|
|
jobId: job.id,
|
|
symbol,
|
|
});
|
|
} catch (error) {
|
|
logger.error('Failed to queue live data job', { symbol, error });
|
|
return c.json({ status: 'error', message: 'Failed to queue live data job' }, 500);
|
|
}
|
|
});
|
|
|
|
marketDataRoutes.get('/api/historical/:symbol', async c => {
|
|
const symbol = c.req.param('symbol');
|
|
const from = c.req.query('from');
|
|
const to = c.req.query('to');
|
|
|
|
logger.info('Historical data request', { symbol, from, to });
|
|
|
|
try {
|
|
const fromDate = from ? new Date(from) : new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); // 30 days ago
|
|
const toDate = to ? new Date(to) : new Date(); // Now
|
|
|
|
// Queue job for historical data using Yahoo provider
|
|
const queueManager = container.queue;
|
|
if (!queueManager) {
|
|
return c.json({ status: 'error', message: 'Queue manager not available' }, 503);
|
|
}
|
|
|
|
const queue = queueManager.getQueue('yahoo-finance');
|
|
const job = await queue.add('historical-data', {
|
|
handler: 'yahoo-finance',
|
|
operation: 'historical-data',
|
|
payload: {
|
|
symbol,
|
|
from: fromDate.toISOString(),
|
|
to: toDate.toISOString(),
|
|
},
|
|
});
|
|
|
|
return c.json({
|
|
status: 'success',
|
|
message: 'Historical data job queued',
|
|
jobId: job.id,
|
|
symbol,
|
|
from: fromDate,
|
|
to: toDate,
|
|
});
|
|
} catch (error) {
|
|
logger.error('Failed to queue historical data job', { symbol, from, to, error });
|
|
return c.json({ status: 'error', message: 'Failed to queue historical data job' }, 500);
|
|
}
|
|
});
|
|
|
|
// Batch processing endpoint using new queue system
|
|
marketDataRoutes.post('/api/process-symbols', async c => {
|
|
try {
|
|
const {
|
|
symbols,
|
|
provider = 'ib',
|
|
operation = 'fetch-session',
|
|
useBatching = true,
|
|
totalDelayHours = 0.0083, // ~30 seconds (30/3600 hours)
|
|
batchSize = 10,
|
|
} = await c.req.json();
|
|
|
|
if (!symbols || !Array.isArray(symbols) || symbols.length === 0) {
|
|
return c.json({ status: 'error', message: 'Invalid symbols array' }, 400);
|
|
}
|
|
|
|
logger.info('Batch processing symbols', {
|
|
count: symbols.length,
|
|
provider,
|
|
operation,
|
|
useBatching,
|
|
});
|
|
|
|
const queueManager = container.queue;
|
|
if (!queueManager) {
|
|
return c.json({ status: 'error', message: 'Queue manager not available' }, 503);
|
|
}
|
|
|
|
const result = await processItems(
|
|
symbols,
|
|
provider,
|
|
{
|
|
handler: provider,
|
|
operation,
|
|
totalDelayHours,
|
|
useBatching,
|
|
batchSize,
|
|
priority: 2,
|
|
retries: 2,
|
|
removeOnComplete: 5,
|
|
removeOnFail: 10,
|
|
},
|
|
queueManager
|
|
);
|
|
|
|
return c.json({
|
|
status: 'success',
|
|
message: 'Batch processing initiated',
|
|
result,
|
|
symbols: symbols.length,
|
|
});
|
|
} catch (error) {
|
|
logger.error('Failed to process symbols batch', { error });
|
|
return c.json({ status: 'error', message: 'Failed to process symbols batch' }, 500);
|
|
}
|
|
});
|
|
|
|
return marketDataRoutes;
|
|
}
|
|
|
|
// Legacy export for backward compatibility
|
|
export const marketDataRoutes = createMarketDataRoutes({} as IServiceContainer);
|