diff --git a/app/api/drift/transaction-history/route.ts b/app/api/drift/transaction-history/route.ts new file mode 100644 index 0000000..596530e --- /dev/null +++ b/app/api/drift/transaction-history/route.ts @@ -0,0 +1,98 @@ +import { NextResponse } from 'next/server' +import { Connection, PublicKey } from '@solana/web3.js' +import { Wallet } from '@coral-xyz/anchor' +import { Keypair } from '@solana/web3.js' + +export async function GET(request: Request) { + try { + const { searchParams } = new URL(request.url) + const limit = parseInt(searchParams.get('limit') || '50') + + console.log('📊 API: Getting Solana transaction history...') + + // Get private key from environment + const privateKeyString = process.env.PRIVATE_KEY + if (!privateKeyString) { + throw new Error('PRIVATE_KEY not found in environment variables') + } + + // Convert private key to Keypair + const privateKeyBytes = JSON.parse(privateKeyString) + const keypair = Keypair.fromSecretKey(new Uint8Array(privateKeyBytes)) + const wallet = new Wallet(keypair) + + // Connect to Helius RPC + const connection = new Connection(process.env.HELIUS_RPC_ENDPOINT || 'https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY') + + // Get transaction signatures for this wallet + const signatures = await connection.getSignaturesForAddress( + wallet.publicKey, + { limit: limit * 2 } // Get more signatures to filter for Drift transactions + ) + + console.log(`🔍 Found ${signatures.length} total signatures`) + + // Get transaction details for each signature + const transactions = [] + const driftProgramId = 'dRiftyHA39MWEi3m9aunc5MzRF1JYuBsbn6VPcn33UH' // Drift program ID + + for (const sig of signatures.slice(0, limit)) { + try { + const tx = await connection.getTransaction(sig.signature, { + maxSupportedTransactionVersion: 0 + }) + + if (!tx) continue + + // Check if this transaction involves the Drift program + const isDriftTransaction = tx.transaction.message.staticAccountKeys?.some( + key => key.toString() === driftProgramId + ) || tx.transaction.message.compiledInstructions?.some( + instruction => { + const programKey = tx.transaction.message.staticAccountKeys?.[instruction.programIdIndex] + return programKey?.toString() === driftProgramId + } + ) + + if (isDriftTransaction) { + // Parse the transaction to extract trading information + const blockTime = tx.blockTime ? new Date(tx.blockTime * 1000) : new Date() + + transactions.push({ + id: sig.signature, + signature: sig.signature, + blockTime: blockTime.toISOString(), + slot: tx.slot, + status: sig.err ? 'FAILED' : 'SUCCESS', + fee: tx.meta?.fee || 0, + // Try to extract more details from logs + logs: tx.meta?.logMessages?.slice(0, 5) || [], + accounts: tx.transaction.message.staticAccountKeys?.slice(0, 10).map(k => k.toString()) || [] + }) + } + } catch (txError) { + console.log(`⚠️ Failed to get transaction ${sig.signature}:`, txError) + } + } + + console.log(`📊 Found ${transactions.length} Drift transactions`) + + return NextResponse.json({ + success: true, + transactions, + count: transactions.length, + totalSignatures: signatures.length + }) + + } catch (error: any) { + console.error('❌ API: Error getting transaction history:', error) + return NextResponse.json( + { + success: false, + error: error.message, + transactions: [] + }, + { status: 500 } + ) + } +} diff --git a/components/AIAnalysisPanel_old.tsx b/components/AIAnalysisPanel_old.tsx index 1eb9697..05c870a 100644 --- a/components/AIAnalysisPanel_old.tsx +++ b/components/AIAnalysisPanel_old.tsx @@ -387,175 +387,4 @@ export default function AIAnalysisPanel() { )} ) -} - {error && ( -
-
- {error.includes('frame was detached') ? ( - <> - TradingView Error: Chart could not be loaded. Please check your symbol and layout, or try again.
- Technical: {error} - - ) : error.includes('layout not found') ? ( - <> - Layout Error: TradingView layout not found. Please select a valid layout.
- Technical: {error} - - ) : error.includes('Private layout access denied') ? ( - <> - Access Error: The selected layout is private or requires authentication. Try a different layout or check your TradingView login.
- Technical: {error} - - ) : ( - <> - Analysis Error: {error} - - )} -
-
- )} - {loading && ( -
-
- - - - - Analyzing {symbol} chart... -
-
- )} - {result && ( -
-

Analysis Results

- {result.layoutsAnalyzed && ( -
- Layouts analyzed: - {result.layoutsAnalyzed.join(', ')} -
- )} -
-
- Summary: -

{safeRender(result.summary)}

-
-
-
- Sentiment: -

{safeRender(result.marketSentiment)}

-
-
- Recommendation: -

{safeRender(result.recommendation)}

- ({safeRender(result.confidence)}% confidence) -
-
- {result.keyLevels && ( -
-
- Support Levels: -

{result.keyLevels.support?.join(', ') || 'None identified'}

-
-
- Resistance Levels: -

{result.keyLevels.resistance?.join(', ') || 'None identified'}

-
-
- )} - - {/* Enhanced Trading Analysis */} - {result.entry && ( -
- Entry: -

${safeRender(result.entry.price || result.entry)}

- {result.entry.buffer &&

{safeRender(result.entry.buffer)}

} - {result.entry.rationale &&

{safeRender(result.entry.rationale)}

} -
- )} - - {result.stopLoss && ( -
- Stop Loss: -

${safeRender(result.stopLoss.price || result.stopLoss)}

- {result.stopLoss.rationale &&

{safeRender(result.stopLoss.rationale)}

} -
- )} - - {result.takeProfits && ( -
- Take Profits: - {typeof result.takeProfits === 'object' ? ( - <> - {result.takeProfits.tp1 && ( -
-

TP1: ${safeRender(result.takeProfits.tp1.price || result.takeProfits.tp1)}

- {result.takeProfits.tp1.description &&

{safeRender(result.takeProfits.tp1.description)}

} -
- )} - {result.takeProfits.tp2 && ( -
-

TP2: ${safeRender(result.takeProfits.tp2.price || result.takeProfits.tp2)}

- {result.takeProfits.tp2.description &&

{safeRender(result.takeProfits.tp2.description)}

} -
- )} - - ) : ( -

{safeRender(result.takeProfits)}

- )} -
- )} - - {result.riskToReward && ( -
- Risk to Reward: -

{safeRender(result.riskToReward)}

-
- )} - - {result.confirmationTrigger && ( -
- Confirmation Trigger: -

{safeRender(result.confirmationTrigger)}

-
- )} - - {result.indicatorAnalysis && ( -
- Indicator Analysis: - {typeof result.indicatorAnalysis === 'object' ? ( -
- {result.indicatorAnalysis.rsi && ( -
- RSI: - {safeRender(result.indicatorAnalysis.rsi)} -
- )} - {result.indicatorAnalysis.vwap && ( -
- VWAP: - {safeRender(result.indicatorAnalysis.vwap)} -
- )} - {result.indicatorAnalysis.obv && ( -
- OBV: - {safeRender(result.indicatorAnalysis.obv)} -
- )} -
- ) : ( -

{safeRender(result.indicatorAnalysis)}

- )} -
- )} - -
- Reasoning: -

{safeRender(result.reasoning)}

-
-
-
- )} - - ) } diff --git a/components/SessionStatus_old.tsx b/components/SessionStatus_old.tsx index c13d68d..a8c0c6f 100644 --- a/components/SessionStatus_old.tsx +++ b/components/SessionStatus_old.tsx @@ -199,120 +199,4 @@ export default function SessionStatus() { ) -} - } else if (sessionInfo.hasSavedCookies || sessionInfo.hasSavedStorage) { - return `Session Available${dockerSuffix}` - } else { - return `Not Logged In${dockerSuffix}` - } - } - - const getDetailedStatus = () => { - if (!sessionInfo) return [] - - return [ - { label: 'Authenticated', value: sessionInfo.isAuthenticated ? '✅' : '❌' }, - { label: 'Connection', value: sessionInfo.connectionStatus === 'connected' ? '✅' : - sessionInfo.connectionStatus === 'disconnected' ? '🔌' : - sessionInfo.connectionStatus === 'error' ? '❌' : '❓' }, - { label: 'Browser Active', value: sessionInfo.browserActive ? '✅' : '❌' }, - { label: 'Saved Cookies', value: sessionInfo.hasSavedCookies ? `✅ (${sessionInfo.cookiesCount})` : '❌' }, - { label: 'Saved Storage', value: sessionInfo.hasSavedStorage ? '✅' : '❌' }, - { label: 'Environment', value: sessionInfo.dockerEnv ? '🐳 Docker' : '💻 Local' }, - ] - } - - return ( -
-
-

TradingView Session

- -
- - {/* Status Indicator */} -
-
- {getStatusText()} -
- - {/* Detailed Status */} - {sessionInfo && ( -
- {getDetailedStatus().map((item, index) => ( -
- {item.label}: - {item.value} -
- ))} -
- Last Checked: - - {new Date(sessionInfo.lastChecked).toLocaleTimeString()} - -
-
- )} - - {/* Error Display */} - {error && ( -
-

{error}

-
- )} - - {/* Action Buttons */} -
- - - -
- - {/* Usage Instructions */} - {sessionInfo && !sessionInfo.isAuthenticated && ( -
-

- 💡 To establish session: Run the analysis or screenshot capture once to trigger manual login, - then future requests will use the saved session and avoid captchas. - {sessionInfo.dockerEnv && ( - <>
🐳 Docker: Session data is persisted in the container volume for reuse across restarts. - )} -

-
- )} - - {/* Docker Environment Info */} - {sessionInfo?.dockerEnv && ( -
-

- 🐳 Docker Environment: Running in containerized mode. Session persistence is enabled - via volume mount at /.tradingview-session -

-
- )} -
- ) } diff --git a/components/TradingHistory_old.tsx b/components/TradingHistory_old.tsx index 8d9621c..2d38f45 100644 --- a/components/TradingHistory_old.tsx +++ b/components/TradingHistory_old.tsx @@ -175,14 +175,4 @@ export default function TradingHistory() { )} ) -} - {trade.status} - {trade.executedAt} - - ))} - - - )} - - ) } diff --git a/lib/drift-trading.ts b/lib/drift-trading.ts index b298478..d137649 100644 --- a/lib/drift-trading.ts +++ b/lib/drift-trading.ts @@ -28,8 +28,20 @@ export interface TradeParams { stopLossType?: 'PRICE' | 'PERCENTAGE' takeProfitType?: 'PRICE' | 'PERCENTAGE' } - -export interface TradeResult { + if (localTrades.length > 0) { + console.log(`📊 Found ${localTrades.length} trades in local database`) + return localTrades.map((trade: any) => ({ + id: trade.id.toString(), + symbol: trade.symbol, + side: trade.side as 'BUY' | 'SELL', + amount: trade.amount, + price: trade.price, + status: trade.status as 'FILLED' | 'PENDING' | 'CANCELLED', + executedAt: trade.executedAt ? trade.executedAt.toISOString() : trade.createdAt.toISOString(), + pnl: trade.profit || 0, + txId: trade.driftTxId || trade.id + })) + }ace TradeResult { success: boolean txId?: string error?: string @@ -431,11 +443,51 @@ export class DriftTradingService { } } - return { + const result = { success: true, txId: txSig, conditionalOrders: conditionalOrders.length > 0 ? conditionalOrders : undefined } + + // Store the trade in local database for history tracking + try { + const { default: prisma } = await import('./prisma') + + // Get current market price (simplified - using a default for now) + let currentPrice = 160; // Default SOL price + try { + // Try to get actual market price from the market + const perpMarket = this.driftClient.getPerpMarketAccount(marketIndex) + if (perpMarket && perpMarket.amm) { + // Use oracle price or mark price if available + const oraclePrice = perpMarket.amm.historicalOracleData?.lastOraclePrice || + perpMarket.amm.lastMarkPriceTwap || + new BN(160 * PRICE_PRECISION.toNumber()) + currentPrice = convertToNumber(oraclePrice, PRICE_PRECISION) + } + } catch (priceError) { + console.log('⚠️ Could not get current market price, using default') + } + + await prisma.trade.create({ + data: { + userId: 'default-user', // TODO: Implement proper user management + symbol: params.symbol, + side: params.side, + amount: params.amount, + price: currentPrice, + status: 'FILLED', + executedAt: new Date(), + driftTxId: txSig + } + }) + console.log(`💾 Trade saved to database: ${params.side} ${params.amount} ${params.symbol} at $${currentPrice}`) + } catch (dbError) { + console.log('⚠️ Failed to save trade to database:', (dbError as Error).message) + // Don't fail the trade if database save fails + } + + return result } catch (e: any) { return { success: false, error: e.message } } finally { @@ -576,116 +628,122 @@ export class DriftTradingService { async getTradingHistory(limit: number = 50): Promise { try { - console.log('📊 Fetching trading history...') + console.log('📊 Fetching trading history from Drift...') - // Try to get order records from Drift SDK if available - if (this.driftClient && this.isInitialized) { - try { - console.log('🔍 Attempting to get order records from Drift SDK...') - await this.driftClient.subscribe() - - const user = this.driftClient.getUser() - const trades: TradeHistory[] = [] - - // Get order history - try different approaches - try { - // Method 1: Try to get order history directly - if ('getOrderHistory' in user) { - const orderHistory = (user as any).getOrderHistory() - console.log('📋 Found order history method, processing orders...') - - // Process order history into our format - for (const order of orderHistory.slice(0, limit)) { - trades.push({ - id: order.orderId?.toString() || Date.now().toString(), - symbol: this.getSymbolFromMarketIndex(order.marketIndex || 0), - side: order.direction === 0 ? 'BUY' : 'SELL', // Assuming 0 = LONG/BUY - amount: convertToNumber(order.baseAssetAmount || new BN(0), BASE_PRECISION), - price: convertToNumber(order.price || new BN(0), PRICE_PRECISION), - status: order.status === 'FILLED' ? 'FILLED' : 'PENDING', - executedAt: new Date(order.timestamp || Date.now()).toISOString(), - txId: order.txSig - }) - } - } - - // Method 2: Try to get recent transactions/fills - if (trades.length === 0 && 'getRecentFills' in user) { - console.log('📋 Trying recent fills method...') - const recentFills = (user as any).getRecentFills(limit) - - for (const fill of recentFills) { - trades.push({ - id: fill.fillId?.toString() || Date.now().toString(), - symbol: this.getSymbolFromMarketIndex(fill.marketIndex || 0), - side: fill.direction === 0 ? 'BUY' : 'SELL', - amount: convertToNumber(fill.baseAssetAmount || new BN(0), BASE_PRECISION), - price: convertToNumber(fill.fillPrice || new BN(0), PRICE_PRECISION), - status: 'FILLED', - executedAt: new Date(fill.timestamp || Date.now()).toISOString(), - txId: fill.txSig - }) - } - } - - console.log(`📊 Found ${trades.length} trades from Drift SDK`) - - } catch (sdkError: any) { - console.log('⚠️ SDK order history methods failed:', sdkError.message) - } finally { - await this.driftClient.unsubscribe() - } - - if (trades.length > 0) { - return trades.sort((a, b) => new Date(b.executedAt).getTime() - new Date(a.executedAt).getTime()) - } - - } catch (sdkError: any) { - console.log('⚠️ SDK trading history failed, using fallback:', sdkError.message) - } + if (!this.driftClient || !this.isInitialized) { + console.log('⚠️ Drift client not initialized, trying local database...') + return await this.getLocalTradingHistory(limit) } - - // Fallback: Check if we have any trades in local database (Prisma) + try { - console.log('📊 Checking local trade database...') + // Subscribe to get access to user data + await this.driftClient.subscribe() + const user = this.driftClient.getUser() - // Import Prisma here to avoid issues if it's not available - try { - const { default: prisma } = await import('./prisma') - const localTrades = await prisma.trade.findMany({ - orderBy: { executedAt: 'desc' }, - take: limit - }) - - if (localTrades.length > 0) { - console.log(`📊 Found ${localTrades.length} trades in local database`) - return localTrades.map((trade: any) => ({ - id: trade.id.toString(), - symbol: trade.symbol, - side: trade.side as 'BUY' | 'SELL', - amount: trade.amount, - price: trade.price, - status: trade.status as 'FILLED' | 'PENDING' | 'CANCELLED', - executedAt: trade.executedAt.toISOString(), - pnl: trade.pnl, - txId: trade.txId - })) + console.log('📊 Getting user order records from Drift SDK...') + + console.log('📊 Getting user account data from Drift SDK...') + + // Get user account which contains order and trade history + const userAccount = user.getUserAccount() + console.log(`📊 User account found with ${userAccount.orders?.length || 0} orders`) + + // Convert orders to trade history + const trades: TradeHistory[] = [] + + if (userAccount.orders) { + for (const order of userAccount.orders.slice(0, limit)) { + try { + // Only include filled orders (status 2 = filled) + if (order.status === 2) { + const marketIndex = order.marketIndex + const symbol = this.getSymbolFromMarketIndex(marketIndex) + const side = order.direction === 0 ? 'BUY' : 'SELL' // 0 = PositionDirection.LONG + const baseAmount = order.baseAssetAmountFilled || order.baseAssetAmount + const quoteAmount = order.quoteAssetAmountFilled || order.quoteAssetAmount + + // Calculate executed price from filled amounts + const amount = Number(baseAmount.toString()) / 1e9 // Convert from base precision + const totalValue = Number(quoteAmount.toString()) / 1e6 // Convert from quote precision + const price = amount > 0 ? totalValue / amount : 0 + + const trade: TradeHistory = { + id: order.orderId?.toString() || `order_${Date.now()}_${trades.length}`, + symbol, + side, + amount, + price, + status: 'FILLED', + executedAt: new Date().toISOString(), // Use current time as fallback + txId: order.orderId?.toString() || '', + pnl: 0 // PnL calculation would require more complex logic + } + + trades.push(trade) + console.log(`✅ Processed trade: ${symbol} ${side} ${amount.toFixed(4)} @ $${price.toFixed(2)}`) + } + } catch (orderError) { + console.warn('⚠️ Error processing order:', orderError) + continue + } } - } catch (prismaError) { - console.log('⚠️ Local database not available:', (prismaError as Error).message) } - // Return empty array instead of demo data - console.log('📊 No trading history found - returning empty array') - return [] + // Sort by execution time (newest first) + trades.sort((a, b) => new Date(b.executedAt).getTime() - new Date(a.executedAt).getTime()) - } catch (dbError: any) { - console.log('⚠️ Database query failed:', dbError.message) - return [] + console.log(`✅ Successfully fetched ${trades.length} trades from Drift`) + return trades + + } catch (sdkError: any) { + console.error('❌ Error fetching from Drift SDK:', sdkError.message) + return await this.getLocalTradingHistory(limit) + } finally { + if (this.driftClient) { + try { + await this.driftClient.unsubscribe() + } catch (e) { + // Ignore unsubscribe errors + } + } } } catch (error: any) { console.error('❌ Error getting trading history:', error) + return await this.getLocalTradingHistory(limit) + } + } + + private async getLocalTradingHistory(limit: number): Promise { + try { + console.log('📊 Checking local trade database...') + + const { default: prisma } = await import('./prisma') + const localTrades = await prisma.trade.findMany({ + orderBy: { executedAt: 'desc' }, + take: limit + }) + + if (localTrades.length > 0) { + console.log(`📊 Found ${localTrades.length} trades in local database`) + return localTrades.map((trade: any) => ({ + id: trade.id.toString(), + symbol: trade.symbol, + side: trade.side as 'BUY' | 'SELL', + amount: trade.amount, + price: trade.price, + status: trade.status as 'FILLED' | 'PENDING' | 'CANCELLED', + executedAt: trade.executedAt.toISOString(), + pnl: trade.pnl || 0, + txId: trade.driftTxId || trade.txId || '' + })) + } + + console.log('📊 No local trades found') + return [] + + } catch (prismaError) { + console.log('⚠️ Local database not available:', (prismaError as Error).message) return [] } } diff --git a/lib/tradingview-automation.ts b/lib/tradingview-automation.ts index 05a6cb2..9b4b020 100644 --- a/lib/tradingview-automation.ts +++ b/lib/tradingview-automation.ts @@ -144,7 +144,7 @@ export class TradingViewAutomation { console.error('ERROR: Failed to launch browser:', error) // Cleanup any partial state await this.forceCleanup() - throw new Error(`Failed to launch browser: ${error) + ")" + throw new Error('Failed to launch browser: ' + error) } if (!this.browser) { @@ -402,7 +402,7 @@ export class TradingViewAutomation { for (const selector of anonymousSelectors) { try { if (await this.page.locator(selector).isVisible({ timeout: 1500 })) { - console.log("ERROR: Found anonymous indicator: " + selector} - not logged in`) + console.log(`ERROR: Found anonymous indicator: ${selector} - not logged in`) foundAnonymousElement = true break } @@ -450,7 +450,7 @@ export class TradingViewAutomation { } } - console.log("DATA: 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 @@ -628,7 +628,7 @@ export class TradingViewAutomation { } } catch (e) { - console.log("ERROR: Failed to load " + url}:`, e) + console.log(`ERROR: Failed to load ${url}:`, e) continue } } @@ -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("CHECKING: 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,7 +695,7 @@ export class TradingViewAutomation { const text = await button.textContent() || '' const trimmedText = text.trim().toLowerCase() - console.log(`INFO: + console.log(`INFO: Button ${i + 1}: "${trimmedText}"`) if (trimmedText.includes('email') || trimmedText.includes('continue with email') || @@ -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("CHECKING: 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("INFO: 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("TARGET: 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 } @@ -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("CHECKING: 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("INFO: 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("TARGET: Found submit button manually: "" + text}"`) + console.log(`TARGET: Found submit button manually: "${text}"`) submitButton = `button:nth-of-type(${i + 1})` break } @@ -1026,7 +1026,7 @@ export class TradingViewAutomation { await this.page.waitForTimeout(1000) // Wait 1 second attempts++ - console.log("🔄 Login check attempt ${attempts}/" + maxAttempts) + ")" + console.log('Login check attempt ' + attempts + '/' + maxAttempts) // Check if we navigated away from login page const currentUrl = await this.page.url() @@ -1059,8 +1059,8 @@ 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("ERROR: Login error detected: " + errorText) + ")" - throw new Error(`Login failed: ${errorText) + ")" + console.log('ERROR: Login error detected: ' + errorText) + throw new Error('Login failed: ' + errorText) } } } catch (e) { @@ -1312,17 +1312,17 @@ export class TradingViewAutomation { // Change symbol if not BTC if (symbol !== 'BTCUSD') { - console.log("Changing symbol to " + symbol}...`) + console.log(`Changing symbol to ${symbol}...`) await this.changeSymbol(symbol) } // Change timeframe if specified if (timeframe) { - console.log("Setting timeframe to " + timeframe}...`) + console.log(`Setting timeframe to ${timeframe}...`) await this.changeTimeframe(timeframe) } - console.log("Successfully navigated to ${symbol} chart with " + timeframe} timeframe`) + console.log(`Successfully navigated to ${symbol} chart with ${timeframe} timeframe`) return true } catch (error) { @@ -1352,7 +1352,7 @@ export class TradingViewAutomation { symbolElement = selector break } catch (e) { - console.log("Symbol selector " + selector} not found, trying next...`) + console.log(`Symbol selector ${selector} not found, trying next...`) } } @@ -1377,7 +1377,7 @@ export class TradingViewAutomation { searchInput = selector break } catch (e) { - console.log("Search input selector " + selector} not found, trying next...`) + console.log(`Search input selector ${selector} not found, trying next...`) } } @@ -1409,7 +1409,7 @@ export class TradingViewAutomation { break } } catch (e) { - console.log("Result selector " + selector} not found, trying next...`) + console.log(`Result selector ${selector} not found, trying next...`) } } @@ -1481,7 +1481,7 @@ export class TradingViewAutomation { break } } catch (e) { - console.log("Interval legend selector " + selector} not found`) + console.log(`Interval legend selector ${selector} not found`) } } @@ -1539,7 +1539,7 @@ export class TradingViewAutomation { break } } catch (e) { - console.log("Timeframe option selector " + selector} not found or not clickable`) + console.log(`Timeframe option selector ${selector} not found or not clickable`) } } if (found) break @@ -1572,7 +1572,7 @@ export class TradingViewAutomation { console.log("SUCCESS: Successfully changed timeframe to " + timeframe) + ")" await this.takeDebugScreenshot('after_timeframe_change') } else { - console.log("ERROR: 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') @@ -1848,7 +1848,7 @@ export class TradingViewAutomation { const cookiesData = await fs.readFile(COOKIES_FILE, 'utf8') const cookies = JSON.parse(cookiesData) await this.context!.addCookies(cookies) - console.log("SUCCESS: 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 @@ -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("SUCCESS: Saved " + cookies.length} cookies`) + console.log(`SUCCESS: Saved ${cookies.length} cookies`) // Save session storage and localStorage const sessionData = await this.page.evaluate(() => { @@ -2072,7 +2072,7 @@ export class TradingViewAutomation { if (!this.humanBehaviorEnabled) return const delay = Math.random() * (maxMs - minMs) + minMs - console.log("⏱️ Human-like delay: " + Math.round(delay)}ms`) + console.log(`⏱️ Human-like delay: ${Math.round(delay)}ms`) await new Promise(resolve => setTimeout(resolve, delay)) } @@ -2129,7 +2129,7 @@ export class TradingViewAutomation { if (timeSinceLastRequest < minInterval) { const waitTime = minInterval - timeSinceLastRequest - console.log("🚦 Throttling request: waiting ${Math.round(waitTime / 1000)}s before next request (request #" + this.requestCount + 1})`) + console.log(`🚦 Throttling request: waiting ${Math.round(waitTime / 1000)}s before next request (request #${this.requestCount + 1})`) await new Promise(resolve => setTimeout(resolve, waitTime)) } @@ -2288,7 +2288,7 @@ export class TradingViewAutomation { } await fs.writeFile(captchaMarkerFile, JSON.stringify(markerData, null, 2)) - console.log("INFO: Marked captcha detection #${markerData.count} at " + markerData.timestamp) + ")" + console.log('INFO: Marked captcha detection #' + markerData.count + ' at ' + markerData.timestamp) } catch (error) { console.log('WARNING: Error marking captcha detection:', error) }