diff --git a/components/Dashboard.tsx b/components/Dashboard.tsx index 4f0add5..c56b72c 100644 --- a/components/Dashboard.tsx +++ b/components/Dashboard.tsx @@ -17,7 +17,8 @@ export default function Dashboard() { dailyPnL: 0, winRate: 0, totalTrades: 0, - accountValue: 0 + accountValue: 0, + netUsdValue: 0 }) useEffect(() => { @@ -48,7 +49,8 @@ export default function Dashboard() { const balanceData = await balanceRes.json() setStats(prev => ({ ...prev, - accountValue: balanceData.accountValue || 0 + accountValue: balanceData.accountValue || 0, + netUsdValue: balanceData.netUsdValue || 0 })) } } catch (e) { @@ -62,7 +64,8 @@ export default function Dashboard() { dailyPnL: 0, winRate: 0, totalTrades: 0, - accountValue: 0 + accountValue: 0, + netUsdValue: 0 }) } } else { @@ -74,7 +77,8 @@ export default function Dashboard() { dailyPnL: 0, winRate: 0, totalTrades: 0, - accountValue: 0 + accountValue: 0, + netUsdValue: 0 }) } } catch (e) { @@ -86,7 +90,8 @@ export default function Dashboard() { dailyPnL: 0, winRate: 0, totalTrades: 0, - accountValue: 0 + accountValue: 0, + netUsdValue: 0 }) } setLoading(false) @@ -97,7 +102,21 @@ export default function Dashboard() { return (
{/* Stats Cards */} -
+
+
+
+
+

Net USD Value

+

+ ${stats.netUsdValue.toFixed(2)} +

+
+
+ ๐Ÿ’Ž +
+
+
+
diff --git a/lib/drift-trading.ts b/lib/drift-trading.ts index 6ded764..d0e4383 100644 --- a/lib/drift-trading.ts +++ b/lib/drift-trading.ts @@ -50,6 +50,8 @@ export interface AccountBalance { accountValue: number leverage: number availableBalance: number + netUsdValue: number + unrealizedPnl: number } export interface TradeHistory { @@ -181,8 +183,11 @@ export class DriftTradingService { async getAccountBalance(): Promise { try { if (this.isInitialized && this.driftClient) { - // Try to use SDK without subscription + // Subscribe to user account to access balance data try { + console.log('๐Ÿ” Subscribing to user account for balance...') + await this.driftClient.subscribe() + const user = this.driftClient.getUser() // Get account equity and collateral information using proper SDK methods @@ -213,17 +218,67 @@ export class DriftTradingService { const leverage = marginRequirement > 0 ? totalCollateral / marginRequirement : 1 const availableBalance = freeCollateral + // Calculate unrealized PnL from all positions + let totalUnrealizedPnl = 0 + try { + // Get all perp positions to calculate total unrealized PnL + const mainMarkets = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] // Check more markets for PnL + + for (const marketIndex of mainMarkets) { + try { + const position = user.getPerpPosition(marketIndex) + if (!position || position.baseAssetAmount.isZero()) continue + + // Calculate unrealized PnL manually + const marketData = this.driftClient.getPerpMarketAccount(marketIndex) + const markPrice = convertToNumber(marketData?.amm.lastMarkPriceTwap || new BN(0), PRICE_PRECISION) + + const entryPrice = convertToNumber(position.quoteEntryAmount.abs(), PRICE_PRECISION) / + convertToNumber(position.baseAssetAmount.abs(), BASE_PRECISION) + const size = convertToNumber(position.baseAssetAmount.abs(), BASE_PRECISION) + const isLong = position.baseAssetAmount.gt(new BN(0)) + + const unrealizedPnl = isLong ? + (markPrice - entryPrice) * size : + (entryPrice - markPrice) * size + + totalUnrealizedPnl += unrealizedPnl + } catch (e) { + // Skip markets that don't exist + continue + } + } + } catch (e) { + console.warn('Could not calculate unrealized PnL:', e) + } + + // Net USD Value = Total Collateral + Unrealized PnL + const netUsdValue = totalCollateral + totalUnrealizedPnl + + console.log(`๐Ÿ’ฐ Account balance: $${accountValue.toFixed(2)}, Net USD: $${netUsdValue.toFixed(2)}, PnL: $${totalUnrealizedPnl.toFixed(2)}`) + return { totalCollateral, freeCollateral, marginRequirement, accountValue, leverage, - availableBalance + availableBalance, + netUsdValue, + unrealizedPnl: totalUnrealizedPnl } } catch (sdkError: any) { - console.log('โš ๏ธ SDK method failed, using fallback:', sdkError.message) + console.log('โš ๏ธ SDK balance method failed, using fallback:', sdkError.message) // Fall through to fallback method + } finally { + // Always unsubscribe to clean up + if (this.driftClient) { + try { + await this.driftClient.unsubscribe() + } catch (e) { + // Ignore unsubscribe errors + } + } } } @@ -237,7 +292,9 @@ export class DriftTradingService { marginRequirement: 0, accountValue: balance / 1e9, // SOL balance leverage: 0, - availableBalance: 0 + availableBalance: 0, + netUsdValue: balance / 1e9, // Use SOL balance as fallback + unrealizedPnl: 0 } } catch (error: any) { @@ -281,8 +338,11 @@ export class DriftTradingService { async getPositions(): Promise { try { if (this.isInitialized && this.driftClient) { - // Try to use SDK without subscription + // Subscribe to user account to access positions try { + console.log('๐Ÿ” Subscribing to user account for positions...') + await this.driftClient.subscribe() + const user = this.driftClient.getUser() // Get all available markets @@ -296,7 +356,7 @@ export class DriftTradingService { const p = user.getPerpPosition(marketIndex) if (!p || p.baseAssetAmount.isZero()) continue - // Get market price without subscription + // Get market price const marketData = this.driftClient.getPerpMarketAccount(marketIndex) const markPrice = convertToNumber(marketData?.amm.lastMarkPriceTwap || new BN(0), PRICE_PRECISION) @@ -319,16 +379,29 @@ export class DriftTradingService { marketIndex, marketType: 'PERP' }) + + console.log(`โœ… Found position: ${this.getSymbolFromMarketIndex(marketIndex)} ${isLong ? 'LONG' : 'SHORT'} ${size}`) } catch (error) { // Skip markets that don't exist or have errors continue } } + console.log(`๐Ÿ“Š Found ${positions.length} total positions`) return positions + } catch (sdkError: any) { console.log('โš ๏ธ SDK positions method failed, using fallback:', sdkError.message) // Fall through to fallback method + } finally { + // Always unsubscribe to clean up + if (this.driftClient) { + try { + await this.driftClient.unsubscribe() + } catch (e) { + // Ignore unsubscribe errors + } + } } } diff --git a/lib/tradingview-automation.ts b/lib/tradingview-automation.ts index 09f82cb..af304d3 100644 --- a/lib/tradingview-automation.ts +++ b/lib/tradingview-automation.ts @@ -81,7 +81,7 @@ export class TradingViewAutomation { } if (this.browser) { - console.log('โœ… Browser already initialized and connected') + console.log('SUCCESS: Browser already initialized and connected') return } @@ -141,7 +141,7 @@ export class TradingViewAutomation { ] }) } catch (error) { - console.error('โŒ Failed to launch browser:', error) + console.error('ERROR: Failed to launch browser:', error) // Cleanup any partial state await this.forceCleanup() throw new Error(`Failed to launch browser: ${error}`) @@ -300,7 +300,7 @@ export class TradingViewAutomation { }); }) - console.log('โœ… Browser and session initialized successfully') + console.log('SUCCESS: Browser and session initialized successfully') } /** @@ -310,7 +310,7 @@ export class TradingViewAutomation { if (!this.page) return false try { - console.log('๐Ÿ” Checking login status...') + console.log('CHECKING: Checking login status...') // Navigate to TradingView if not already there const currentUrl = await this.page.url() @@ -332,7 +332,7 @@ export class TradingViewAutomation { await this.takeDebugScreenshot('login_status_check') // Enhanced login detection with multiple strategies - console.log('๐Ÿ” Strategy 1: Checking for user account indicators...') + console.log('CHECKING: Strategy 1: Checking for user account indicators...') // Strategy 1: Look for user account elements (more comprehensive) const userAccountSelectors = [ @@ -366,7 +366,7 @@ export class TradingViewAutomation { for (const selector of userAccountSelectors) { try { if (await this.page.locator(selector).isVisible({ timeout: 1500 })) { - console.log(`โœ… Found user account element: ${selector}`) + console.log(`SUCCESS: Found user account element: ${selector}`) foundUserElement = true break } @@ -376,7 +376,7 @@ export class TradingViewAutomation { } // Strategy 2: Check for sign-in/anonymous indicators (should NOT be present if logged in) - console.log('๐Ÿ” Strategy 2: Checking for anonymous/sign-in indicators...') + console.log('CHECKING: Strategy 2: Checking for anonymous/sign-in indicators...') const anonymousSelectors = [ // Sign in buttons/links @@ -402,7 +402,7 @@ export class TradingViewAutomation { for (const selector of anonymousSelectors) { try { if (await this.page.locator(selector).isVisible({ timeout: 1500 })) { - console.log(`โŒ Found anonymous indicator: ${selector} - not logged in`) + console.log(`ERROR: Found anonymous indicator: ${selector} - not logged in`) foundAnonymousElement = true break } @@ -412,7 +412,7 @@ export class TradingViewAutomation { } // Strategy 3: Check page URL patterns for authentication - console.log('๐Ÿ” Strategy 3: Checking URL patterns...') + console.log('CHECKING: Strategy 3: Checking URL patterns...') const url = await this.page.url() const isOnLoginPage = url.includes('/accounts/signin') || @@ -420,13 +420,13 @@ export class TradingViewAutomation { url.includes('/login') if (isOnLoginPage) { - console.log(`โŒ Currently on login page: ${url}`) + console.log(`ERROR: Currently on login page: ${url}`) this.isAuthenticated = false return false } // Strategy 4: Check for authentication-specific cookies - console.log('๐Ÿ” Strategy 4: Checking authentication cookies...') + console.log('CHECKING: Strategy 4: Checking authentication cookies...') let hasAuthCookies = false if (this.context) { @@ -450,11 +450,11 @@ export class TradingViewAutomation { } } - console.log(`๐Ÿ“Š Total cookies: ${cookies.length}, Auth cookies found: ${hasAuthCookies}`) + console.log(`DATA: Total cookies: ${cookies.length}, Auth cookies found: ${hasAuthCookies}`) } // Strategy 5: Try to detect personal elements by checking page content - console.log('๐Ÿ” Strategy 5: Checking for personal content...') + console.log('CHECKING: Strategy 5: Checking for personal content...') let hasPersonalContent = false try { @@ -476,7 +476,7 @@ export class TradingViewAutomation { for (const selector of personalContentSelectors) { try { if (await this.page.locator(selector).isVisible({ timeout: 1000 })) { - console.log(`โœ… Found personal content: ${selector}`) + console.log(`SUCCESS: Found personal content: ${selector}`) hasPersonalContent = true break } @@ -491,16 +491,16 @@ export class TradingViewAutomation { pageText.includes('Portfolio') || pageText.includes('Alerts') || pageText.includes('Account')) { - console.log('โœ… Found account-specific text content') + console.log('SUCCESS: Found account-specific text content') hasPersonalContent = true } } catch (e) { - console.log('โš ๏ธ Error checking personal content:', e) + console.log('WARNING: Error checking personal content:', e) } // Final decision logic - console.log('๐Ÿ“Š Login detection summary:') + console.log('DATA: Login detection summary:') console.log(` User elements found: ${foundUserElement}`) console.log(` Anonymous elements found: ${foundAnonymousElement}`) console.log(` On login page: ${isOnLoginPage}`) @@ -513,17 +513,17 @@ export class TradingViewAutomation { !isOnLoginPage if (isLoggedIn) { - console.log('โœ… User appears to be logged in') + console.log('SUCCESS: User appears to be logged in') this.isAuthenticated = true return true } else { - console.log('โŒ User appears to be NOT logged in') + console.log('ERROR: User appears to be NOT logged in') this.isAuthenticated = false return false } } catch (error) { - console.error('โŒ Error checking login status:', error) + console.error('ERROR: Error checking login status:', error) await this.takeDebugScreenshot('login_status_error') this.isAuthenticated = false return false @@ -545,7 +545,7 @@ export class TradingViewAutomation { // Check if already logged in with enhanced detection const loggedIn = await this.checkLoginStatus() if (loggedIn) { - console.log('โœ… Already logged in, skipping login steps') + console.log('SUCCESS: Already logged in, skipping login steps') return true } @@ -557,7 +557,7 @@ export class TradingViewAutomation { await this.context.clearCookies() console.log('๐Ÿงน Cleared existing cookies for clean login') } catch (e) { - console.log('โš ๏ธ Could not clear cookies:', e) + console.log('WARNING: Could not clear cookies:', e) } } @@ -589,7 +589,7 @@ export class TradingViewAutomation { break } else if (url === 'https://www.tradingview.com/') { // Try to find and click sign in button - console.log('๐Ÿ” Looking for Sign In button on main page...') + console.log('CHECKING: Looking for Sign In button on main page...') const signInSelectors = [ 'a[href*="signin"]:visible', @@ -602,24 +602,24 @@ export class TradingViewAutomation { for (const selector of signInSelectors) { try { - console.log(`๐ŸŽฏ Trying sign in selector: ${selector}`) + console.log(`TARGET: Trying sign in selector: ${selector}`) const element = this.page.locator(selector).first() if (await element.isVisible({ timeout: 3000 })) { await element.click() - console.log(`โœ… Clicked sign in button: ${selector}`) + console.log(`SUCCESS: Clicked sign in button: ${selector}`) // Wait for navigation to login page await this.page.waitForTimeout(3000) const newUrl = await this.page.url() if (newUrl.includes('signin') || newUrl.includes('login')) { - console.log('โœ… Successfully navigated to login page') + console.log('SUCCESS: Successfully navigated to login page') loginPageLoaded = true break } } } catch (e) { - console.log(`โŒ Sign in selector failed: ${selector}`) + console.log(`ERROR: Sign in selector failed: ${selector}`) continue } } @@ -628,7 +628,7 @@ export class TradingViewAutomation { } } catch (e) { - console.log(`โŒ Failed to load ${url}:`, e) + console.log(`ERROR: Failed to load ${url}:`, e) continue } } @@ -645,7 +645,7 @@ export class TradingViewAutomation { await this.page.waitForTimeout(5000) // CRITICAL: Look for and click "Email" button if present (TradingView uses this pattern) - console.log('๐Ÿ” Looking for Email login option...') + console.log('CHECKING: Looking for Email login option...') // First try Playwright locator approach const emailTriggers = [ @@ -663,9 +663,9 @@ export class TradingViewAutomation { try { const element = this.page.locator(trigger).first() if (await element.isVisible({ timeout: 2000 })) { - console.log(`๐ŸŽฏ Found email trigger: ${trigger}`) + console.log(`TARGET: Found email trigger: ${trigger}`) await element.click() - console.log('โœ… Clicked email trigger') + console.log('SUCCESS: Clicked email trigger') // Wait for email form to appear await this.page.waitForTimeout(3000) @@ -686,7 +686,7 @@ export class TradingViewAutomation { // Get all buttons and check their text content const buttons = await this.page.locator('button').all() - console.log(`๐Ÿ” Found ${buttons.length} buttons to check`) + console.log(`CHECKING: Found ${buttons.length} buttons to check`) for (let i = 0; i < buttons.length; i++) { try { @@ -695,14 +695,14 @@ export class TradingViewAutomation { const text = await button.textContent() || '' const trimmedText = text.trim().toLowerCase() - console.log(`๐Ÿ“ + console.log(`INFO: if (trimmedText.includes('email') || trimmedText.includes('continue with email') || trimmedText.includes('sign in with email')) { - console.log(`๐ŸŽฏ Found email button: "${trimmedText}"`) + console.log('Found email button: ' + trimmedText) await button.click() - console.log('โœ… Clicked email button') + console.log('SUCCESS: Clicked email button') // Wait for email form to appear await this.page.waitForTimeout(3000) @@ -711,12 +711,12 @@ export class TradingViewAutomation { } } } catch (e) { - console.log(`โš ๏ธ Error checking button ${i + 1}:`, e) + console.log('WARNING: Error checking button ' + (i + 1) + ':', e) continue } } } catch (e) { - console.log('โŒ Manual button search failed:', e) + console.log('ERROR: Manual button search failed:', e) } } @@ -735,7 +735,7 @@ export class TradingViewAutomation { for (const selector of emailInputSelectors) { try { if (await this.page.locator(selector).isVisible({ timeout: 1000 })) { - console.log(`โœ… Email input already visible: ${selector}`) + console.log(`SUCCESS: Email input already visible: ${selector}`) emailFormVisible = true break } @@ -760,7 +760,7 @@ export class TradingViewAutomation { return { buttons, inputs, forms } }) - console.log('๐Ÿ” Available elements:', JSON.stringify(availableElements, null, 2)) + console.log('CHECKING: Available elements:', JSON.stringify(availableElements, null, 2)) throw new Error('Could not find or activate email login form') } @@ -782,10 +782,10 @@ export class TradingViewAutomation { let emailInput = null for (const selector of emailSelectors) { try { - console.log(`๐Ÿ” Trying email selector: ${selector}`) + console.log(`CHECKING: Trying email selector: ${selector}`) if (await this.page.locator(selector).isVisible({ timeout: 2000 })) { emailInput = selector - console.log(`โœ… Found email input: ${selector}`) + console.log(`SUCCESS: Found email input: ${selector}`) break } } catch (e) { @@ -798,7 +798,7 @@ export class TradingViewAutomation { console.log('๐Ÿ”„ Selector approach failed, trying manual input search...') try { const inputs = await this.page.locator('input').all() - console.log(`๐Ÿ” Found ${inputs.length} inputs to check`) + console.log(`CHECKING: Found ${inputs.length} inputs to check`) for (let i = 0; i < inputs.length; i++) { try { @@ -808,14 +808,14 @@ export class TradingViewAutomation { const name = await input.getAttribute('name') || '' const placeholder = await input.getAttribute('placeholder') || '' - console.log(`๐Ÿ“ Input ${i + 1}: type="${type}" name="${name}" placeholder="${placeholder}"`) + console.log(`INFO: Input ${i + 1}: type="${type}" name="${name}" placeholder="${placeholder}"`) if (type === 'email' || name.toLowerCase().includes('email') || name.toLowerCase().includes('username') || placeholder.toLowerCase().includes('email') || placeholder.toLowerCase().includes('username')) { - console.log(`๐ŸŽฏ Found email input manually: ${name || type || placeholder}`) + console.log(`TARGET: Found email input manually: ${name || type || placeholder}`) emailInput = `input:nth-of-type(${i + 1})` break } @@ -825,7 +825,7 @@ export class TradingViewAutomation { } } } catch (e) { - console.log('โŒ Manual input search failed:', e) + console.log('ERROR: Manual input search failed:', e) } } @@ -837,7 +837,7 @@ export class TradingViewAutomation { // Fill email console.log('๐Ÿ“ง Filling email field...') await this.page.fill(emailInput, email) - console.log('โœ… Email filled') + console.log('SUCCESS: Email filled') // Find and fill password field console.log('๐Ÿ”‘ Looking for password input field...') @@ -853,10 +853,10 @@ export class TradingViewAutomation { let passwordInput = null for (const selector of passwordSelectors) { try { - console.log(`๐Ÿ” Trying password selector: ${selector}`) + console.log(`CHECKING: Trying password selector: ${selector}`) if (await this.page.locator(selector).isVisible({ timeout: 2000 })) { passwordInput = selector - console.log(`โœ… Found password input: ${selector}`) + console.log(`SUCCESS: Found password input: ${selector}`) break } } catch (e) { @@ -872,7 +872,7 @@ export class TradingViewAutomation { // Fill password console.log('๐Ÿ”‘ Filling password field...') await this.page.fill(passwordInput, password) - console.log('โœ… Password filled') + console.log('SUCCESS: Password filled') // Handle potential captcha console.log('๐Ÿค– Checking for captcha...') @@ -909,7 +909,7 @@ export class TradingViewAutomation { } if (captchaFound) { - console.log('โš ๏ธ CAPTCHA/Robot verification detected!') + console.log('WARNING: CAPTCHA/Robot verification detected!') console.log('๐Ÿšซ This indicates TradingView has flagged this as automated behavior.') console.log('๏ฟฝ In a Docker environment, automated captcha solving is not feasible.') @@ -917,7 +917,7 @@ export class TradingViewAutomation { await this.takeDebugScreenshot('captcha_detected') // Instead of waiting, we should fail fast and suggest alternatives - console.log('โŒ Cannot proceed with automated login due to captcha protection.') + console.log('ERROR: Cannot proceed with automated login due to captcha protection.') console.log('๐Ÿ”ง Possible solutions:') console.log(' 1. Use a different IP address or VPN') console.log(' 2. Wait some time before retrying (rate limiting)') @@ -935,7 +935,7 @@ export class TradingViewAutomation { if (captchaError.message.includes('Captcha detected')) { throw captchaError } - console.log('โš ๏ธ Captcha check failed:', captchaError?.message) + console.log('WARNING: Captcha check failed:', captchaError?.message) } // Find and click submit button @@ -957,10 +957,10 @@ export class TradingViewAutomation { let submitButton = null for (const selector of submitSelectors) { try { - console.log(`๐Ÿ” Trying submit selector: ${selector}`) + console.log(`CHECKING: Trying submit selector: ${selector}`) if (await this.page.locator(selector).isVisible({ timeout: 2000 })) { submitButton = selector - console.log(`โœ… Found submit button: ${selector}`) + console.log(`SUCCESS: Found submit button: ${selector}`) break } } catch (e) { @@ -973,7 +973,7 @@ export class TradingViewAutomation { console.log('๐Ÿ”„ Selector approach failed, trying manual button search for submit...') try { const buttons = await this.page.locator('button').all() - console.log(`๐Ÿ” Found ${buttons.length} buttons to check for submit`) + console.log(`CHECKING: Found ${buttons.length} buttons to check for submit`) for (let i = 0; i < buttons.length; i++) { try { @@ -982,13 +982,13 @@ export class TradingViewAutomation { const text = (await button.textContent() || '').toLowerCase() const type = await button.getAttribute('type') || '' - console.log(`๐Ÿ“ Submit Button ${i + 1}: "${text}" type="${type}"`) + console.log(`INFO: Submit Button ${i + 1}: "${text}" type="${type}"`) if (type === 'submit' || text.includes('sign in') || text.includes('login') || text.includes('submit')) { - console.log(`๐ŸŽฏ Found submit button manually: "${text}"`) + console.log(`TARGET: Found submit button manually: "${text}"`) submitButton = `button:nth-of-type(${i + 1})` break } @@ -998,7 +998,7 @@ export class TradingViewAutomation { } } } catch (e) { - console.log('โŒ Manual submit button search failed:', e) + console.log('ERROR: Manual submit button search failed:', e) } } @@ -1010,7 +1010,7 @@ export class TradingViewAutomation { // Click submit button console.log('๐Ÿ–ฑ๏ธ Clicking submit button...') await this.page.click(submitButton) - console.log('โœ… Submit button clicked') + console.log('SUCCESS: Submit button clicked') // Wait for login to complete console.log('โณ Waiting for login to complete...') @@ -1041,7 +1041,7 @@ export class TradingViewAutomation { ).first() hasUserElements = await userElement.isVisible({ timeout: 500 }) if (hasUserElements) { - console.log('โœ… Found user-specific elements') + console.log('SUCCESS: Found user-specific elements') } } catch (e) { // Element not found, continue checking @@ -1059,7 +1059,7 @@ export class TradingViewAutomation { for (const selector of errorSelectors) { if (await this.page.locator(selector).isVisible({ timeout: 500 })) { const errorText = await this.page.locator(selector).textContent() - console.log(`โŒ Login error detected: ${errorText}`) + console.log(`ERROR: Login error detected: ${errorText}`) throw new Error(`Login failed: ${errorText}`) } } @@ -1088,7 +1088,7 @@ export class TradingViewAutomation { const loginSuccessful = await this.checkLoginStatus() if (loginSuccessful) { - console.log('โœ… Login verified successful!') + console.log('SUCCESS: Login verified successful!') this.isAuthenticated = true // Save session for future use @@ -1097,19 +1097,19 @@ export class TradingViewAutomation { return true } else { - console.log('โŒ Login verification failed') + console.log('ERROR: Login verification failed') await this.takeDebugScreenshot('login_verification_failed') return false } } catch (error) { - console.error('โŒ Login completion timeout or error:', error) + console.error('ERROR: Login completion timeout or error:', error) await this.takeDebugScreenshot('login_timeout') return false } } catch (error) { - console.error('โŒ Login failed:', error) + console.error('ERROR: Login failed:', error) await this.takeDebugScreenshot('login_error') return false } @@ -1122,7 +1122,7 @@ export class TradingViewAutomation { if (!this.page) throw new Error('Page not initialized') try { - console.log('๐Ÿ” Attempting smart login with session persistence...') + console.log('CHECKING: Attempting smart login with session persistence...') // First check if already logged in const alreadyLoggedIn = await this.checkLoginStatus() @@ -1136,7 +1136,7 @@ export class TradingViewAutomation { // Before attempting login, check if we have any saved session data const sessionInfo = await this.testSessionPersistence() - console.log('๐Ÿ“Š Session persistence check:', sessionInfo) + console.log('DATA: Session persistence check:', sessionInfo) if (sessionInfo.cookiesCount > 0) { console.log('๐Ÿช Found saved session data, attempting to restore...') @@ -1156,15 +1156,15 @@ export class TradingViewAutomation { const nowLoggedIn = await this.checkLoginStatus() if (nowLoggedIn) { - console.log('โœ… Session restoration successful! Login confirmed.') + console.log('SUCCESS: Session restoration successful! Login confirmed.') this.isAuthenticated = true await this.saveSession() return true } else { - console.log('โš ๏ธ Session restoration failed, saved session may be expired') + console.log('WARNING: Session restoration failed, saved session may be expired') } } catch (e) { - console.log('โŒ Session restoration attempt failed:', e) + console.log('ERROR: Session restoration attempt failed:', e) } } @@ -1174,7 +1174,7 @@ export class TradingViewAutomation { const autoLoginSuccess = await this.login(credentials) if (autoLoginSuccess) { - console.log('โœ… Automated login successful! Saving session for future use.') + console.log('SUCCESS: Automated login successful! Saving session for future use.') this.isAuthenticated = true await this.saveSession() return true @@ -1192,14 +1192,14 @@ export class TradingViewAutomation { throw loginError } - console.log('โŒ Automated login failed, this is likely due to captcha protection.') - console.log('โš ๏ธ In Docker environment, manual login is not practical.') + console.log('ERROR: Automated login failed, this is likely due to captcha protection.') + console.log('WARNING: In Docker environment, manual login is not practical.') console.log('๏ฟฝ Checking if we can proceed with session persistence...') // Try to check if there are any existing valid session cookies - const sessionInfo = await this.testSessionPersistence() - if (sessionInfo.isValid) { - console.log('โœ… Found valid session data, attempting to use it...') + const fallbackSessionInfo = await this.testSessionPersistence() + if (fallbackSessionInfo.isValid) { + console.log('SUCCESS: Found valid session data, attempting to use it...') try { // Navigate to main TradingView page to test session await this.page.goto('https://www.tradingview.com/', { @@ -1211,22 +1211,22 @@ export class TradingViewAutomation { const nowLoggedIn = await this.checkLoginStatus() if (nowLoggedIn) { - console.log('โœ… Session persistence worked! Login successful.') + console.log('SUCCESS: Session persistence worked! Login successful.') this.isAuthenticated = true await this.saveSession() return true } } catch (e) { - console.log('โŒ Session persistence test failed:', e) + console.log('ERROR: Session persistence test failed:', e) } } - console.log('โŒ All login methods failed. This may require manual intervention.') + console.log('ERROR: All login methods failed. This may require manual intervention.') console.log('๐Ÿ’ก To fix: Log in manually in a browser with the same credentials and restart the application.') return false } catch (error) { - console.error('โŒ Smart login failed:', error) + console.error('ERROR: Smart login failed:', error) return false } } @@ -1241,7 +1241,7 @@ export class TradingViewAutomation { // Validate session integrity before proceeding const sessionValid = await this.validateSessionIntegrity() if (!sessionValid) { - console.log('โš ๏ธ Session integrity compromised, may require re-authentication') + console.log('WARNING: Session integrity compromised, may require re-authentication') } const { symbol = 'SOLUSD', timeframe = '5', waitForChart = true } = options @@ -1458,7 +1458,7 @@ export class TradingViewAutomation { await this.takeDebugScreenshot('before_timeframe_change') // CRITICAL: Click the interval legend to open timeframe selector - console.log('๐ŸŽฏ Looking for interval legend to open timeframe selector...') + console.log('TARGET: Looking for interval legend to open timeframe selector...') const intervalLegendSelectors = [ '[data-name="legend-source-interval"]', '.intervalTitle-l31H9iuA', @@ -1473,7 +1473,7 @@ export class TradingViewAutomation { console.log(`Trying interval legend selector: ${selector}`) const element = this.page.locator(selector).first() if (await element.isVisible({ timeout: 3000 })) { - console.log(`โœ… Found interval legend: ${selector}`) + console.log(`SUCCESS: Found interval legend: ${selector}`) await element.click() await this.page.waitForTimeout(2000) console.log('๐Ÿ–ฑ๏ธ Clicked interval legend - timeframe selector should be open') @@ -1486,13 +1486,13 @@ export class TradingViewAutomation { } if (!intervalLegendClicked) { - console.log('โŒ Could not find interval legend to click') + console.log('ERROR: Could not find interval legend to click') await this.takeDebugScreenshot('no_interval_legend') return } // Now look for timeframe options in the opened selector - console.log('๐Ÿ” Looking for timeframe options in selector...') + console.log('CHECKING: Looking for timeframe options in selector...') for (const tf of timeframesToTry) { const timeframeSelectors = [ @@ -1531,7 +1531,7 @@ export class TradingViewAutomation { // Check if element exists and is visible const isVisible = await element.isVisible({ timeout: 2000 }) if (isVisible) { - console.log(`โœ… Found timeframe option: ${selector}`) + console.log(`SUCCESS: Found timeframe option: ${selector}`) await element.click() await this.page.waitForTimeout(2000) console.log(`๐ŸŽ‰ Successfully clicked timeframe option for ${tf}`) @@ -1569,10 +1569,10 @@ export class TradingViewAutomation { } if (found) { - console.log(`โœ… Successfully changed timeframe to ${timeframe}`) + console.log(`SUCCESS: Successfully changed timeframe to ${timeframe}`) await this.takeDebugScreenshot('after_timeframe_change') } else { - console.log(`โŒ Could not change timeframe to ${timeframe} - timeframe options not found`) + console.log(`ERROR: Could not change timeframe to ${timeframe} - timeframe options not found`) // Take a debug screenshot to see current state await this.takeDebugScreenshot('timeframe_change_failed') @@ -1636,11 +1636,11 @@ export class TradingViewAutomation { currentUrl } - console.log('๐Ÿ“Š Current session info:', result) + console.log('DATA: Current session info:', result) return result } catch (error) { - console.error('โŒ Error testing session persistence:', error) + console.error('ERROR: Error testing session persistence:', error) return { isValid: false, cookiesCount: 0, hasStorage: false, currentUrl: 'about:blank' } } } @@ -1683,7 +1683,7 @@ export class TradingViewAutomation { } if (!chartFound) { - console.log('โš ๏ธ No chart elements found') + console.log('WARNING: No chart elements found') return false } @@ -1705,7 +1705,7 @@ export class TradingViewAutomation { console.log('Chart data loaded successfully') return hasData } catch (error) { - console.error('โŒ Error waiting for chart data:', error) + console.error('ERROR: Error waiting for chart data:', error) return false } } @@ -1737,7 +1737,7 @@ export class TradingViewAutomation { console.log(`Screenshot saved: ${filename}`) return filePath } catch (error) { - console.error('โŒ Error taking screenshot:', error) + console.error('ERROR: Error taking screenshot:', error) throw error } } @@ -1764,7 +1764,7 @@ export class TradingViewAutomation { console.log(`Screenshot saved: ${filename}`) } catch (error) { - console.log('โš ๏ธ Error taking debug screenshot:', error) + console.log('WARNING: Error taking debug screenshot:', error) } } @@ -1793,7 +1793,7 @@ export class TradingViewAutomation { try { await this.page.close() } catch (e) { - console.log('โš ๏ธ Error closing page:', e) + console.log('WARNING: Error closing page:', e) } this.page = null } @@ -1802,7 +1802,7 @@ export class TradingViewAutomation { try { await this.context.close() } catch (e) { - console.log('โš ๏ธ Error closing context:', e) + console.log('WARNING: Error closing context:', e) } this.context = null } @@ -1811,7 +1811,7 @@ export class TradingViewAutomation { try { await this.browser.close() } catch (e) { - console.log('โš ๏ธ Error closing browser:', e) + console.log('WARNING: Error closing browser:', e) } this.browser = null } @@ -1822,7 +1822,7 @@ export class TradingViewAutomation { this.initPromise = null } catch (error) { - console.error('โŒ Error during force cleanup:', error) + console.error('ERROR: Error during force cleanup:', error) } } @@ -1848,13 +1848,13 @@ export class TradingViewAutomation { const cookiesData = await fs.readFile(COOKIES_FILE, 'utf8') const cookies = JSON.parse(cookiesData) await this.context!.addCookies(cookies) - console.log(`โœ… Loaded ${cookies.length} cookies from saved session`) + console.log(`SUCCESS: Loaded ${cookies.length} cookies from saved session`) } // Note: Session storage will be loaded after page navigation } catch (error) { - console.log('โš ๏ธ Could not load session data (starting fresh):', error) + console.log('WARNING: Could not load session data (starting fresh):', error) } } @@ -1870,7 +1870,7 @@ export class TradingViewAutomation { // Save cookies const cookies = await this.context.cookies() await fs.writeFile(COOKIES_FILE, JSON.stringify(cookies, null, 2)) - console.log(`โœ… Saved ${cookies.length} cookies`) + console.log(`SUCCESS: Saved ${cookies.length} cookies`) // Save session storage and localStorage const sessionData = await this.page.evaluate(() => { @@ -1897,10 +1897,10 @@ export class TradingViewAutomation { }) await fs.writeFile(SESSION_STORAGE_FILE, JSON.stringify(sessionData, null, 2)) - console.log('โœ… Saved session storage and localStorage') + console.log('SUCCESS: Saved session storage and localStorage') } catch (error) { - console.error('โŒ Failed to save session data:', error) + console.error('ERROR: Failed to save session data:', error) } } @@ -1937,10 +1937,10 @@ export class TradingViewAutomation { } }, sessionData) - console.log('โœ… Restored session storage and localStorage') + console.log('SUCCESS: Restored session storage and localStorage') } catch (error) { - console.log('โš ๏ธ Could not restore session storage:', error) + console.log('WARNING: Could not restore session storage:', error) } } @@ -1965,17 +1965,17 @@ export class TradingViewAutomation { // Verify still logged in const stillLoggedIn = await this.checkLoginStatus() if (stillLoggedIn) { - console.log('โœ… Session refreshed successfully') + console.log('SUCCESS: Session refreshed successfully') await this.saveSession() // Save refreshed session return true } else { - console.log('โŒ Session expired during refresh') + console.log('ERROR: Session expired during refresh') this.isAuthenticated = false return false } } catch (error) { - console.error('โŒ Failed to refresh session:', error) + console.error('ERROR: Failed to refresh session:', error) return false } } @@ -1989,25 +1989,25 @@ export class TradingViewAutomation { if (await this.fileExists(COOKIES_FILE)) { await fs.unlink(COOKIES_FILE) - console.log('โœ… Cleared cookies file') + console.log('SUCCESS: Cleared cookies file') } if (await this.fileExists(SESSION_STORAGE_FILE)) { await fs.unlink(SESSION_STORAGE_FILE) - console.log('โœ… Cleared session storage file') + console.log('SUCCESS: Cleared session storage file') } // Clear browser context storage if available if (this.context) { await this.context.clearCookies() - console.log('โœ… Cleared browser context cookies') + console.log('SUCCESS: Cleared browser context cookies') } this.isAuthenticated = false - console.log('โœ… Session data cleared successfully') + console.log('SUCCESS: Session data cleared successfully') } catch (error) { - console.error('โŒ Failed to clear session data:', error) + console.error('ERROR: Failed to clear session data:', error) } } @@ -2094,7 +2094,7 @@ export class TradingViewAutomation { await new Promise(resolve => setTimeout(resolve, Math.random() * 300 + 100)) } } catch (error) { - console.log('โš ๏ธ Error simulating mouse movement:', error) + console.log('WARNING: Error simulating mouse movement:', error) } } @@ -2115,7 +2115,7 @@ export class TradingViewAutomation { await new Promise(resolve => setTimeout(resolve, Math.random() * 800 + 300)) } } catch (error) { - console.log('โš ๏ธ Error simulating scrolling:', error) + console.log('WARNING: Error simulating scrolling:', error) } } @@ -2179,7 +2179,7 @@ export class TradingViewAutomation { this.sessionFingerprint = fingerprint return fingerprint } catch (error) { - console.error('โŒ Error generating session fingerprint:', error) + console.error('ERROR: Error generating session fingerprint:', error) return `fallback-${Date.now()}` } } @@ -2206,7 +2206,7 @@ export class TradingViewAutomation { for (const indicator of invalidationIndicators) { try { if (await this.page.locator(indicator).isVisible({ timeout: 1000 })) { - console.log(`โš ๏ธ Session invalidation detected: ${indicator}`) + console.log(`WARNING: Session invalidation detected: ${indicator}`) return false } } catch (e) { @@ -2224,14 +2224,14 @@ export class TradingViewAutomation { if (stored.userAgent !== current.userAgent || stored.platform !== current.platform || stored.language !== current.language) { - console.log('โš ๏ธ Session fingerprint mismatch detected') + console.log('WARNING: Session fingerprint mismatch detected') return false } } return true } catch (error) { - console.error('โŒ Error validating session integrity:', error) + console.error('ERROR: Error validating session integrity:', error) return false } } @@ -2262,7 +2262,7 @@ export class TradingViewAutomation { // Wait a bit longer to let the page settle await this.humanDelay(2000, 4000) } catch (error) { - console.log('โš ๏ธ Error performing human-like interactions:', error) + console.log('WARNING: Error performing human-like interactions:', error) } } @@ -2288,9 +2288,9 @@ export class TradingViewAutomation { } await fs.writeFile(captchaMarkerFile, JSON.stringify(markerData, null, 2)) - console.log(`๐Ÿ“ Marked captcha detection #${markerData.count} at ${markerData.timestamp}`) + console.log(`INFO: Marked captcha detection #${markerData.count} at ${markerData.timestamp}`) } catch (error) { - console.log('โš ๏ธ Error marking captcha detection:', error) + console.log('WARNING: Error marking captcha detection:', error) } }