175 lines
6.1 KiB
TypeScript
175 lines
6.1 KiB
TypeScript
import { ProviderConfig } from '../services/provider-registry.service';
|
|
import { getLogger } from '@stock-bot/logger';
|
|
|
|
const logger = getLogger('quotemedia-provider');
|
|
|
|
export const quotemediaProvider: ProviderConfig = {
|
|
name: 'quotemedia',
|
|
service: 'market-data',
|
|
operations: { 'live-data': async (payload: { symbol: string; fields?: string[] }) => {
|
|
logger.info('Fetching live data from QuoteMedia', { symbol: payload.symbol });
|
|
|
|
// Simulate QuoteMedia API call
|
|
const mockData = {
|
|
symbol: payload.symbol,
|
|
price: Math.random() * 1000 + 100,
|
|
volume: Math.floor(Math.random() * 1000000),
|
|
change: (Math.random() - 0.5) * 20,
|
|
changePercent: (Math.random() - 0.5) * 5,
|
|
timestamp: new Date().toISOString(),
|
|
source: 'quotemedia',
|
|
fields: payload.fields || ['price', 'volume', 'change']
|
|
};
|
|
|
|
// Simulate network delay
|
|
await new Promise(resolve => setTimeout(resolve, 100 + Math.random() * 200));
|
|
|
|
return mockData;
|
|
},
|
|
|
|
'historical-data': async (payload: {
|
|
symbol: string;
|
|
from: Date;
|
|
to: Date;
|
|
interval?: string;
|
|
fields?: string[]; }) => {
|
|
logger.info('Fetching historical data from QuoteMedia', {
|
|
symbol: payload.symbol,
|
|
from: payload.from,
|
|
to: payload.to,
|
|
interval: payload.interval || '1d'
|
|
});
|
|
|
|
// Generate mock historical data
|
|
const days = Math.ceil((payload.to.getTime() - payload.from.getTime()) / (1000 * 60 * 60 * 24));
|
|
const data = [];
|
|
|
|
for (let i = 0; i < Math.min(days, 100); i++) {
|
|
const date = new Date(payload.from.getTime() + i * 24 * 60 * 60 * 1000);
|
|
data.push({
|
|
date: date.toISOString().split('T')[0],
|
|
open: Math.random() * 1000 + 100,
|
|
high: Math.random() * 1000 + 100,
|
|
low: Math.random() * 1000 + 100,
|
|
close: Math.random() * 1000 + 100,
|
|
volume: Math.floor(Math.random() * 1000000),
|
|
source: 'quotemedia'
|
|
});
|
|
}
|
|
|
|
// Simulate network delay
|
|
await new Promise(resolve => setTimeout(resolve, 200 + Math.random() * 300));
|
|
|
|
return {
|
|
symbol: payload.symbol,
|
|
interval: payload.interval || '1d',
|
|
data,
|
|
source: 'quotemedia',
|
|
totalRecords: data.length
|
|
};
|
|
},
|
|
'batch-quotes': async (payload: { symbols: string[]; fields?: string[] }) => {
|
|
logger.info('Fetching batch quotes from QuoteMedia', {
|
|
symbols: payload.symbols,
|
|
count: payload.symbols.length
|
|
});
|
|
|
|
const quotes = payload.symbols.map(symbol => ({
|
|
symbol,
|
|
price: Math.random() * 1000 + 100,
|
|
volume: Math.floor(Math.random() * 1000000),
|
|
change: (Math.random() - 0.5) * 20,
|
|
timestamp: new Date().toISOString(),
|
|
source: 'quotemedia'
|
|
}));
|
|
|
|
// Simulate network delay
|
|
await new Promise(resolve => setTimeout(resolve, 300 + Math.random() * 200));
|
|
|
|
return {
|
|
quotes,
|
|
source: 'quotemedia',
|
|
timestamp: new Date().toISOString(),
|
|
totalSymbols: payload.symbols.length
|
|
};
|
|
}, 'company-profile': async (payload: { symbol: string }) => {
|
|
logger.info('Fetching company profile from QuoteMedia', { symbol: payload.symbol });
|
|
|
|
// Simulate company profile data
|
|
const profile = {
|
|
symbol: payload.symbol,
|
|
companyName: `${payload.symbol} Corporation`,
|
|
sector: 'Technology',
|
|
industry: 'Software',
|
|
description: `${payload.symbol} is a leading technology company.`,
|
|
marketCap: Math.floor(Math.random() * 1000000000000),
|
|
employees: Math.floor(Math.random() * 100000),
|
|
website: `https://www.${payload.symbol.toLowerCase()}.com`,
|
|
source: 'quotemedia'
|
|
};
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 150 + Math.random() * 100));
|
|
|
|
return profile;
|
|
}, 'options-chain': async (payload: { symbol: string; expiration?: string }) => {
|
|
logger.info('Fetching options chain from QuoteMedia', {
|
|
symbol: payload.symbol,
|
|
expiration: payload.expiration
|
|
});
|
|
|
|
// Generate mock options data
|
|
const strikes = Array.from({ length: 20 }, (_, i) => 100 + i * 5);
|
|
const calls = strikes.map(strike => ({
|
|
strike,
|
|
bid: Math.random() * 10,
|
|
ask: Math.random() * 10 + 0.5,
|
|
volume: Math.floor(Math.random() * 1000),
|
|
openInterest: Math.floor(Math.random() * 5000)
|
|
}));
|
|
|
|
const puts = strikes.map(strike => ({
|
|
strike,
|
|
bid: Math.random() * 10,
|
|
ask: Math.random() * 10 + 0.5,
|
|
volume: Math.floor(Math.random() * 1000),
|
|
openInterest: Math.floor(Math.random() * 5000)
|
|
}));
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 400 + Math.random() * 300));
|
|
return {
|
|
symbol: payload.symbol,
|
|
expiration: payload.expiration || new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString().split('T')[0],
|
|
calls,
|
|
puts,
|
|
source: 'quotemedia'
|
|
};
|
|
}
|
|
},
|
|
|
|
scheduledJobs: [
|
|
// {
|
|
// type: 'quotemedia-premium-refresh',
|
|
// operation: 'batch-quotes',
|
|
// payload: { symbols: ['AAPL', 'GOOGL', 'MSFT'] },
|
|
// cronPattern: '*/2 * * * *', // Every 2 minutes
|
|
// priority: 7,
|
|
// description: 'Refresh premium quotes with detailed market data'
|
|
// },
|
|
// {
|
|
// type: 'quotemedia-options-update',
|
|
// operation: 'options-chain',
|
|
// payload: { symbol: 'SPY' },
|
|
// cronPattern: '*/10 * * * *', // Every 10 minutes
|
|
// priority: 5,
|
|
// description: 'Update options chain data for SPY ETF'
|
|
// },
|
|
// {
|
|
// type: 'quotemedia-profiles',
|
|
// operation: 'company-profile',
|
|
// payload: { symbol: 'AAPL' },
|
|
// cronPattern: '0 9 * * 1-5', // Weekdays at 9 AM
|
|
// priority: 3,
|
|
// description: 'Update company profile data'
|
|
// }
|
|
]
|
|
};
|