finished symbol info
This commit is contained in:
parent
5640444c47
commit
77bba31456
4 changed files with 73 additions and 54 deletions
|
|
@ -106,6 +106,14 @@ export async function updateIntradayBars(
|
||||||
['symbol', 'timestamp'] // Unique keys
|
['symbol', 'timestamp'] // Unique keys
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Update operation tracking
|
||||||
|
const tracker = await getOperationTracker(this);
|
||||||
|
await tracker.updateSymbolOperation(qmSearchCode, 'intraday_bars', {
|
||||||
|
status: 'success',
|
||||||
|
lastRecordDate: targetDate,
|
||||||
|
recordCount: barsData.length
|
||||||
|
});
|
||||||
|
|
||||||
this.logger.info('Intraday bars updated successfully', {
|
this.logger.info('Intraday bars updated successfully', {
|
||||||
symbol,
|
symbol,
|
||||||
date: targetDate,
|
date: targetDate,
|
||||||
|
|
@ -124,6 +132,15 @@ export async function updateIntradayBars(
|
||||||
} else {
|
} else {
|
||||||
// No data for this date (weekend, holiday, or no trading)
|
// No data for this date (weekend, holiday, or no trading)
|
||||||
this.logger.info('No intraday data for date', { symbol, date: targetDate });
|
this.logger.info('No intraday data for date', { symbol, date: targetDate });
|
||||||
|
|
||||||
|
// Still update operation tracking as successful (no data is a valid result)
|
||||||
|
const tracker = await getOperationTracker(this);
|
||||||
|
await tracker.updateSymbolOperation(qmSearchCode, 'intraday_bars', {
|
||||||
|
status: 'success',
|
||||||
|
lastRecordDate: targetDate,
|
||||||
|
recordCount: 0
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
symbol,
|
symbol,
|
||||||
|
|
@ -146,6 +163,12 @@ export async function updateIntradayBars(
|
||||||
error: error instanceof Error ? error.message : 'Unknown error'
|
error: error instanceof Error ? error.message : 'Unknown error'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Update operation tracking for failure
|
||||||
|
const tracker = await getOperationTracker(this);
|
||||||
|
await tracker.updateSymbolOperation(qmSearchCode, 'intraday_bars', {
|
||||||
|
status: 'failure'
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
symbol,
|
symbol,
|
||||||
|
|
@ -256,14 +279,7 @@ export async function scheduleIntradayUpdates(
|
||||||
jobsQueued++;
|
jobsQueued++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update crawl state
|
// Note: Crawl state will be updated when the actual jobs run
|
||||||
await tracker.updateSymbolOperation(doc.qmSearchCode, 'intraday_bars', {
|
|
||||||
status: 'partial',
|
|
||||||
crawlState: {
|
|
||||||
finished: false,
|
|
||||||
oldestDateReached: new Date(startDate.getTime() - daysToFetch * 24 * 60 * 60 * 1000),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
// For update mode, just fetch today's data
|
// For update mode, just fetch today's data
|
||||||
await this.scheduleOperation('update-intraday-bars', {
|
await this.scheduleOperation('update-intraday-bars', {
|
||||||
|
|
|
||||||
|
|
@ -29,25 +29,24 @@ async function getOperationTracker(handler: QMHandler): Promise<QMOperationTrack
|
||||||
export async function updateSymbolInfo(
|
export async function updateSymbolInfo(
|
||||||
this: QMHandler,
|
this: QMHandler,
|
||||||
input: {
|
input: {
|
||||||
symbol: string;
|
|
||||||
qmSearchCode: string;
|
qmSearchCode: string;
|
||||||
},
|
},
|
||||||
_context?: ExecutionContext
|
_context?: ExecutionContext
|
||||||
): Promise<{
|
): Promise<{
|
||||||
success: boolean;
|
success: boolean;
|
||||||
symbol: string;
|
qmSearchCode: string;
|
||||||
message: string;
|
message: string;
|
||||||
data?: any;
|
data?: any;
|
||||||
}> {
|
}> {
|
||||||
const { symbol, qmSearchCode } = input;
|
const { qmSearchCode } = input;
|
||||||
|
|
||||||
this.logger.info('Fetching symbol info', { symbol, qmSearchCode });
|
this.logger.info(`Fetching symbol info ${qmSearchCode}`, { qmSearchCode });
|
||||||
|
|
||||||
const sessionManager = QMSessionManager.getInstance();
|
const sessionManager = QMSessionManager.getInstance();
|
||||||
sessionManager.initialize(this.cache, this.logger);
|
sessionManager.initialize(this.cache, this.logger);
|
||||||
|
|
||||||
// Get a session
|
// Get a session
|
||||||
const sessionId = QM_SESSION_IDS.LOOKUP;
|
const sessionId = QM_SESSION_IDS.SYMBOL;
|
||||||
const session = await sessionManager.getSession(sessionId);
|
const session = await sessionManager.getSession(sessionId);
|
||||||
|
|
||||||
if (!session || !session.uuid) {
|
if (!session || !session.uuid) {
|
||||||
|
|
@ -57,13 +56,15 @@ export async function updateSymbolInfo(
|
||||||
try {
|
try {
|
||||||
// Build API request for symbol info
|
// Build API request for symbol info
|
||||||
const searchParams = new URLSearchParams({
|
const searchParams = new URLSearchParams({
|
||||||
q: qmSearchCode || symbol,
|
fullDescription: 'true',
|
||||||
qmodTool: 'SymbolInfo',
|
qmodTool: 'CompanyProfile',
|
||||||
|
symbols: qmSearchCode,
|
||||||
|
lang: 'en',
|
||||||
|
pathName: '/demo/portal/company-summary.php',
|
||||||
webmasterId: '500',
|
webmasterId: '500',
|
||||||
includeExtended: 'true'
|
} as Record<string, string>);
|
||||||
});
|
|
||||||
|
|
||||||
const apiUrl = `${QM_CONFIG.LOOKUP_URL}?${searchParams.toString()}`;
|
const apiUrl = `${QM_CONFIG.SYMBOL_URL}?${searchParams.toString()}`;
|
||||||
|
|
||||||
const response = await fetch(apiUrl, {
|
const response = await fetch(apiUrl, {
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
|
|
@ -81,43 +82,44 @@ export async function updateSymbolInfo(
|
||||||
await sessionManager.incrementSuccessfulCalls(sessionId, session.uuid);
|
await sessionManager.incrementSuccessfulCalls(sessionId, session.uuid);
|
||||||
|
|
||||||
// Process and store symbol info
|
// Process and store symbol info
|
||||||
if (symbolData && (Array.isArray(symbolData) ? symbolData.length > 0 : true)) {
|
if (symbolData && Array.isArray(symbolData?.results?.company) && symbolData?.results?.company.length > 0) {
|
||||||
const symbolInfo = Array.isArray(symbolData) ? symbolData[0] : symbolData;
|
|
||||||
|
|
||||||
// Update symbol in database with new metadata
|
// Update symbol in database with new metadata
|
||||||
const updateData = {
|
const updateData = {
|
||||||
...symbolInfo,
|
qmSearchCode: qmSearchCode,
|
||||||
symbol: symbol,
|
profile: symbolData?.results?.company[0].profile,
|
||||||
qmSearchCode: qmSearchCode || symbolInfo.symbol,
|
symbolInfo: symbolData?.results?.company[0].symbolinfo,
|
||||||
lastInfoUpdate: new Date(),
|
}
|
||||||
updated_at: new Date()
|
|
||||||
};
|
|
||||||
|
|
||||||
await this.mongodb.updateOne(
|
await this.mongodb.updateOne(
|
||||||
'qmSymbols',
|
'qmSymbols',
|
||||||
{ symbol },
|
{ qmSearchCode, },
|
||||||
{ $set: updateData },
|
{ $set: updateData },
|
||||||
{ upsert: true }
|
{ upsert: true }
|
||||||
);
|
);
|
||||||
|
|
||||||
this.logger.info('Symbol info updated successfully', {
|
// Update operation tracking
|
||||||
symbol,
|
const tracker = await getOperationTracker(this);
|
||||||
name: symbolInfo.name,
|
await tracker.updateSymbolOperation(qmSearchCode, 'symbol_info', {
|
||||||
exchange: symbolInfo.exchange
|
status: 'success',
|
||||||
|
lastRecordDate: new Date()
|
||||||
|
});
|
||||||
|
|
||||||
|
this.logger.info(`Symbol info updated successfully ${qmSearchCode}`, {
|
||||||
|
qmSearchCode,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
symbol,
|
qmSearchCode,
|
||||||
message: `Symbol info updated for ${symbol}`,
|
message: `Symbol info updated for ${qmSearchCode}`,
|
||||||
data: symbolInfo
|
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
this.logger.warn('No symbol data returned from API', { symbol });
|
this.logger.warn('No symbol data returned from API', { qmSearchCode });
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
symbol,
|
qmSearchCode,
|
||||||
message: `No data found for symbol ${symbol}`
|
message: `No data found for symbol ${qmSearchCode}`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,13 +130,19 @@ export async function updateSymbolInfo(
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.error('Error fetching symbol info', {
|
this.logger.error('Error fetching symbol info', {
|
||||||
symbol,
|
qmSearchCode,
|
||||||
error: error instanceof Error ? error.message : 'Unknown error'
|
error: error instanceof Error ? error.message : 'Unknown error'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Update operation tracking for failure
|
||||||
|
const tracker = await getOperationTracker(this);
|
||||||
|
await tracker.updateSymbolOperation(qmSearchCode, 'symbol_info', {
|
||||||
|
status: 'failure'
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
symbol,
|
qmSearchCode,
|
||||||
message: `Failed to fetch symbol info: ${error instanceof Error ? error.message : 'Unknown error'}`
|
message: `Failed to fetch symbol info: ${error instanceof Error ? error.message : 'Unknown error'}`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -156,7 +164,7 @@ export async function scheduleSymbolInfoUpdates(
|
||||||
symbolsQueued: number;
|
symbolsQueued: number;
|
||||||
errors: number;
|
errors: number;
|
||||||
}> {
|
}> {
|
||||||
const { limit = 100, forceUpdate = false } = input;
|
const { limit = 1, forceUpdate = false } = input;
|
||||||
const tracker = await getOperationTracker(this);
|
const tracker = await getOperationTracker(this);
|
||||||
|
|
||||||
this.logger.info('Scheduling symbol info updates', { limit, forceUpdate });
|
this.logger.info('Scheduling symbol info updates', { limit, forceUpdate });
|
||||||
|
|
@ -181,9 +189,9 @@ export async function scheduleSymbolInfoUpdates(
|
||||||
|
|
||||||
// Get full symbol data to include qmSearchCode
|
// Get full symbol data to include qmSearchCode
|
||||||
const symbolDocs = await this.mongodb.find('qmSymbols', {
|
const symbolDocs = await this.mongodb.find('qmSymbols', {
|
||||||
symbol: { $in: staleSymbols }
|
qmSearchCode: { $in: staleSymbols }
|
||||||
}, {
|
}, {
|
||||||
projection: { symbol: 1, qmSearchCode: 1 }
|
projection: { qmSearchCode: 1 }
|
||||||
});
|
});
|
||||||
|
|
||||||
let queued = 0;
|
let queued = 0;
|
||||||
|
|
@ -193,22 +201,16 @@ export async function scheduleSymbolInfoUpdates(
|
||||||
for (const doc of symbolDocs) {
|
for (const doc of symbolDocs) {
|
||||||
try {
|
try {
|
||||||
await this.scheduleOperation('update-symbol-info', {
|
await this.scheduleOperation('update-symbol-info', {
|
||||||
symbol: doc.symbol,
|
qmSearchCode: doc.qmSearchCode
|
||||||
qmSearchCode: doc.qmSearchCode || doc.symbol
|
|
||||||
}, {
|
}, {
|
||||||
// priority: 3,
|
// priority: 3,
|
||||||
// Add some delay to avoid overwhelming the API
|
// Add some delay to avoid overwhelming the API
|
||||||
// delay: queued * 1000 // 1 second between jobs
|
// delay: queued * 1000 // 1 second between jobs
|
||||||
});
|
});
|
||||||
|
|
||||||
// Track that we've scheduled this symbol
|
|
||||||
await tracker.updateSymbolOperation(doc.qmSearchCode, 'symbol_info', {
|
|
||||||
status: 'success'
|
|
||||||
});
|
|
||||||
|
|
||||||
queued++;
|
queued++;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.logger.error(`Failed to schedule update for ${doc.symbol}`, { error });
|
this.logger.error(`Failed to schedule update for ${doc.qmSearchCode}`, { error });
|
||||||
errors++;
|
errors++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ export class QMHandler extends BaseHandler<DataIngestionServices> {
|
||||||
@Operation('update-symbol-info')
|
@Operation('update-symbol-info')
|
||||||
updateSymbolInfo = updateSymbolInfo;
|
updateSymbolInfo = updateSymbolInfo;
|
||||||
|
|
||||||
@Disabled()
|
// @Disabled()
|
||||||
@ScheduledOperation('schedule-symbol-info-updates', '0 */6 * * *', {
|
@ScheduledOperation('schedule-symbol-info-updates', '0 */6 * * *', {
|
||||||
priority: 7,
|
priority: 7,
|
||||||
immediately: false,
|
immediately: false,
|
||||||
|
|
|
||||||
|
|
@ -34,12 +34,13 @@ export const QM_CONFIG = {
|
||||||
BASE_URL: 'https://app.quotemedia.com',
|
BASE_URL: 'https://app.quotemedia.com',
|
||||||
SESSION_PATH: '/auth/g/authenticate/dataTool/v0/500',
|
SESSION_PATH: '/auth/g/authenticate/dataTool/v0/500',
|
||||||
LOOKUP_URL: 'https://app.quotemedia.com/datatool/lookup.json',
|
LOOKUP_URL: 'https://app.quotemedia.com/datatool/lookup.json',
|
||||||
|
SYMBOL_URL: 'https://app.quotemedia.com/datatool/getProfiles.json',
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
// Session management settings
|
// Session management settings
|
||||||
export const SESSION_CONFIG = {
|
export const SESSION_CONFIG = {
|
||||||
MIN_SESSIONS: 10,
|
MIN_SESSIONS: 2,
|
||||||
MAX_SESSIONS: 10,
|
MAX_SESSIONS: 2,
|
||||||
MAX_FAILED_CALLS: 3,
|
MAX_FAILED_CALLS: 3,
|
||||||
SESSION_TIMEOUT: 5000, // 10 seconds
|
SESSION_TIMEOUT: 5000, // 10 seconds
|
||||||
API_TIMEOUT: 30000, // 15 seconds
|
API_TIMEOUT: 30000, // 15 seconds
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue