import { Browser } from '@stock-bot/browser'; import { getLogger } from '@stock-bot/logger'; // Shared instances (module-scoped, not global) let isInitialized = false; // Track if resources are initialized let logger: ReturnType; // let cache: CacheProvider; export async function initializeIBResources(waitForCache = false): Promise { // Skip if already initialized if (isInitialized) { return; } logger = getLogger('proxy-tasks'); // cache = createCache({ // keyPrefix: 'proxy:', // ttl: PROXY_CONFIG.CACHE_TTL, // enableMetrics: true, // }); // httpClient = new HttpClient({ timeout: 15000 }, logger); // if (waitForCache) { // // logger.info('Initializing proxy cache...'); // // await cache.waitForReady(10000); // // logger.info('Proxy cache initialized successfully'); // logger.info('Proxy tasks initialized'); // } else { // logger.info('Proxy tasks initialized (fallback mode)'); // } isInitialized = true; } export async function fetchSymbolSummary(): Promise { try { await Browser.initialize({ headless: true, timeout: 10000, blockResources: false }); logger.info('✅ Browser initialized'); const { page, contextId } = await Browser.createPageWithProxy( 'https://www.interactivebrokers.com/en/trading/products-exchanges.php#/', 'http://doimvbnb-US-rotate:w5fpiwrb9895@p.webshare.io:80' ); logger.info('✅ Page created with proxy'); let summaryData: any = null; // Initialize summaryData to store API response let eventCount = 0; page.onNetworkEvent(event => { if (event.url.includes('/webrest/search/product-types/summary')) { console.log(`🎯 Found summary API call: ${event.type} ${event.url}`); if (event.type === 'response' && event.responseData) { console.log(`📊 Summary API Response Data: ${event.responseData}`); try { summaryData = JSON.parse(event.responseData) as any; const totalCount = summaryData[0].totalCount; console.log('📊 Summary API Response:', JSON.stringify(summaryData, null, 2)); console.log(`🔢 Total symbols found: ${totalCount || 'Unknown'}`); } catch (e) { console.log('📊 Raw Summary Response:', event.responseData); } } } eventCount++; logger.info(`📡 Event ${eventCount}: ${event.type} ${event.url}`); }); logger.info('⏳ Waiting for page load...'); await page.waitForLoadState('domcontentloaded', { timeout: 20000 }); logger.info('✅ Page loaded'); // RIGHT HERE - Interact with the page to find Stocks checkbox and Apply button logger.info('🔍 Looking for Products tab...'); // Wait for the page to fully load await page.waitForTimeout(20000); // First, click on the Products tab const productsTab = page.locator('#productSearchTab[role="tab"][href="#products"]'); await productsTab.waitFor({ timeout: 20000 }); logger.info('✅ Found Products tab'); logger.info('🖱️ Clicking Products tab...'); await productsTab.click(); logger.info('✅ Products tab clicked'); // Wait for the tab content to load await page.waitForTimeout(5000); // Click on the Asset Classes accordion to expand it logger.info('🔍 Looking for Asset Classes accordion...'); const assetClassesAccordion = page.locator( '#products .accordion-item #acc-products .accordion_btn:has-text("Asset Classes")' ); await assetClassesAccordion.waitFor({ timeout: 10000 }); logger.info('✅ Found Asset Classes accordion'); logger.info('🖱️ Clicking Asset Classes accordion...'); await assetClassesAccordion.click(); logger.info('✅ Asset Classes accordion clicked'); // Wait for the accordion content to expand await page.waitForTimeout(2000); logger.info('🔍 Looking for Stocks checkbox...'); // Find the span with class "fs-7 checkbox-text" and inner text containing "Stocks" const stocksSpan = page.locator('span.fs-7.checkbox-text:has-text("Stocks")'); await stocksSpan.waitFor({ timeout: 10000 }); logger.info('✅ Found Stocks span'); // Find the checkbox by looking in the same parent container const parentContainer = stocksSpan.locator('..'); const checkbox = parentContainer.locator('input[type="checkbox"]'); if ((await checkbox.count()) > 0) { logger.info('📋 Clicking Stocks checkbox...'); await checkbox.first().check(); logger.info('✅ Stocks checkbox checked'); } else { logger.info('⚠️ Could not find checkbox near Stocks text'); } // Wait a moment for any UI updates await page.waitForTimeout(1000); // Find and click the nearest Apply button logger.info('🔍 Looking for Apply button...'); const applyButton = page.locator( 'button:has-text("Apply"), input[type="submit"][value*="Apply"], input[type="button"][value*="Apply"]' ); if ((await applyButton.count()) > 0) { logger.info('🎯 Clicking Apply button...'); await applyButton.first().click(); logger.info('✅ Apply button clicked'); // Wait for any network requests triggered by the Apply button await page.waitForTimeout(2000); } else { logger.info('⚠️ Could not find Apply button'); } return 0; } catch (error) { logger.error('Failed to fetch IB symbol summary', { error }); return 0; } } // Optional: Export a convenience object that groups related tasks export const ibTasks = { fetchSymbolSummary, };