work on prices

This commit is contained in:
Boki 2025-06-29 12:25:38 -04:00
parent 77bba31456
commit 2f5eaef19c
2 changed files with 46 additions and 32 deletions

View file

@ -28,26 +28,25 @@ async function getOperationTracker(handler: QMHandler): Promise<QMOperationTrack
export async function updatePrices(
this: QMHandler,
input: {
symbol: string;
symbolId: number;
qmSearchCode: string;
lastRecordDate?: Date;
},
_context?: ExecutionContext
): Promise<{
success: boolean;
symbol: string;
qmSearchCode: string;
message: string;
data?: any;
}> {
const { symbol, symbolId, qmSearchCode } = input;
const { qmSearchCode, lastRecordDate } = input;
this.logger.info('Fetching daily prices', { symbol, symbolId });
this.logger.info(`Fetching daily prices ${qmSearchCode}`, { qmSearchCode });
const sessionManager = QMSessionManager.getInstance();
sessionManager.initialize(this.cache, this.logger);
// Get a session - you'll need to add the appropriate session ID for prices
const sessionId = QM_SESSION_IDS.LOOKUP; // TODO: Update with correct session ID
const sessionId = QM_SESSION_IDS.PRICES;
const session = await sessionManager.getSession(sessionId);
if (!session || !session.uuid) {
@ -57,15 +56,20 @@ export async function updatePrices(
try {
// Build API request for daily prices
const searchParams = new URLSearchParams({
symbol: symbol,
symbolId: symbolId.toString(),
qmodTool: 'DailyPrices',
webmasterId: '500',
days: '30' // Get last 30 days
zeroTradeDays: 'false',
start: lastRecordDate?.toISOString().split('T')[0] ?? '1960-01-01',
interval: '1',
marketSession: 'mkt',
freq: 'day',
adjusted: 'false',
adjustmentType: 'none',
unadjusted: 'true',
datatype: 'eod',
symbol: qmSearchCode,
});
// https://app.quotemedia.com/datatool/getEnhancedChartData.json?zeroTradeDays=false&start=2025-06-22&interval=1&marketSession=mkt&freq=day&adjusted=true&adjustmentType=none&unadjusted=false&datatype=int&symbol=AAPL
// TODO: Update with correct prices endpoint
const apiUrl = `${QM_CONFIG.BASE_URL}/datatool/prices.json?${searchParams.toString()}`;
const apiUrl = `${QM_CONFIG.PRICES_URL}?${searchParams.toString()}`;
const response = await fetch(apiUrl, {
method: 'GET',
@ -77,31 +81,40 @@ export async function updatePrices(
throw new Error(`QM API request failed: ${response.status} ${response.statusText}`);
}
const priceData = await response.json();
const responseData = await response.json();
// Update session success stats
await sessionManager.incrementSuccessfulCalls(sessionId, session.uuid);
const priceData = responseData.results?.history[0].eoddata || [];
if(!priceData || priceData.length === 0) {
this.logger.warn(`No price data found for symbol ${qmSearchCode}`);
return {
success: false,
qmSearchCode,
message: `No price data found for symbol ${qmSearchCode}`
};
}
// Process and store price data
if (priceData && priceData.length > 0) {
// Store prices in a separate collection
const processedPrices = priceData.map((price: any) => ({
...price,
symbol,
symbolId,
date: new Date(price.date),
updated_at: new Date()
qmSearchCode,
dateTime: new Date(price.date),
}));
await this.mongodb.batchUpsert(
'qmPrices',
processedPrices,
['symbol', 'date'] // Unique keys
['qmSearchCode', 'date'] // Unique keys
);
// Find the latest price date
const latestDate = processedPrices.reduce((latest: Date, price: any) =>
price.date > latest ? price.date : latest,
price.dateTime > latest ? price.dateTime : latest,
new Date(0)
);
@ -114,26 +127,26 @@ export async function updatePrices(
});
this.logger.info('Prices updated successfully', {
symbol,
qmSearchCode,
priceCount: priceData.length,
latestDate
});
return {
success: true,
symbol,
message: `Prices updated for ${symbol}`,
qmSearchCode,
message: `Prices updated for ${qmSearchCode}`,
data: {
count: priceData.length,
latestDate
}
};
} else {
this.logger.warn('No price data returned from API', { symbol });
this.logger.warn('No price data returned from API', { qmSearchCode });
return {
success: false,
symbol,
message: `No price data found for symbol ${symbol}`
qmSearchCode,
message: `No price data found for qmSearchCode ${qmSearchCode}`
};
}
@ -144,7 +157,7 @@ export async function updatePrices(
}
this.logger.error('Error fetching prices', {
symbol,
qmSearchCode,
error: error instanceof Error ? error.message : 'Unknown error'
});
@ -156,7 +169,7 @@ export async function updatePrices(
return {
success: false,
symbol,
qmSearchCode,
message: `Failed to fetch prices: ${error instanceof Error ? error.message : 'Unknown error'}`
};
}
@ -177,7 +190,7 @@ export async function schedulePriceUpdates(
symbolsQueued: number;
errors: number;
}> {
const { limit = 100, forceUpdate = false } = input;
const { limit = 1, forceUpdate = false } = input;
const tracker = await getOperationTracker(this);
this.logger.info('Scheduling price updates', { limit, forceUpdate });
@ -219,8 +232,6 @@ export async function schedulePriceUpdates(
}
await this.scheduleOperation('update-prices', {
symbol: doc.symbol,
symbolId: doc.symbolId,
qmSearchCode: doc.qmSearchCode
}, {
priority: 7, // High priority for price data

View file

@ -8,11 +8,13 @@ import { getRandomUserAgent } from "@stock-bot/utils";
export const QM_SESSION_IDS = {
LOOKUP: 'dc8c9930437f65d30f6597768800957017bac203a0a50342932757c8dfa158d6', // lookup endpoint
SYMBOL: '1e1d7cb1de1fd2fe52684abdea41a446919a5fe12776dfab88615ac1ce1ec2f6', // getProfiles
PRICES: '5ad521e05faf5778d567f6d0012ec34d6cdbaeb2462f41568f66558bc7b4ced9', // getEnhancedChartData
// EDS: '', //
// FILINGS: '', //
// PRICES: '', //
// FINANCIALS: '', //
// INTRADAY: '', //
// '5ad521e05faf5778d567f6d0012ec34d6cdbaeb2462f41568f66558bc7b4ced9' // getEhnachedChartData
// '5ad521e05faf5778d567f6d0012ec34d6cdbaeb2462f41568f66558bc7b4ced9': [], //4488d072b
// cc1cbdaf040f76db8f4c94f7d156b9b9b716e1a7509ec9c74a48a47f6b6b9f87: [], //97ff00cf3 // getQuotes
// '74963ff42f1db2320d051762b5d3950ff9eab23f9d5c5b592551b4ca0441d086': [], //32ca24e394b // getSplitsBySymbol getBrokerRatingsBySymbol getDividendsBySymbol getEarningsSurprisesBySymbol getEarningsEventsBySymbol
@ -35,6 +37,7 @@ export const QM_CONFIG = {
SESSION_PATH: '/auth/g/authenticate/dataTool/v0/500',
LOOKUP_URL: 'https://app.quotemedia.com/datatool/lookup.json',
SYMBOL_URL: 'https://app.quotemedia.com/datatool/getProfiles.json',
PRICES_URL: 'https://app.quotemedia.com/datatool/getEnhancedChartData.json',
} as const;
// Session management settings