Trend Analyzer for TradingView

Analyzes market trends and provides insights on TradingView charts

Size

13.7 KB

Version

1.0.1

Created

Oct 22, 2025

Updated

1 day ago

1// ==UserScript==
2// @name		Trend Analyzer for TradingView
3// @description		Analyzes market trends and provides insights on TradingView charts
4// @version		1.0.1
5// @match		https://*.tradingview.com/*
6// @icon		https://static.tradingview.com/static/images/favicon.ico
7// ==/UserScript==
8(function() {
9    'use strict';
10
11    console.log('Trend Analyzer for TradingView initialized');
12
13    // Utility function to debounce
14    function debounce(func, wait) {
15        let timeout;
16        return function executedFunction(...args) {
17            const later = () => {
18                clearTimeout(timeout);
19                func(...args);
20            };
21            clearTimeout(timeout);
22            timeout = setTimeout(later, wait);
23        };
24    }
25
26    // Create the analyzer panel
27    function createAnalyzerPanel() {
28        const panel = document.createElement('div');
29        panel.id = 'trend-analyzer-panel';
30        panel.style.cssText = `
31            position: fixed;
32            top: 80px;
33            right: 20px;
34            width: 350px;
35            background: linear-gradient(135deg, #1e222d 0%, #2a2e39 100%);
36            border: 1px solid #3a3e49;
37            border-radius: 12px;
38            padding: 20px;
39            z-index: 10000;
40            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
41            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
42            color: #d1d4dc;
43            max-height: 80vh;
44            overflow-y: auto;
45        `;
46
47        panel.innerHTML = `
48            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
49                <h3 style="margin: 0; color: #fff; font-size: 18px; font-weight: 600;">📊 Trend Analyzer</h3>
50                <button id="close-analyzer" style="background: none; border: none; color: #d1d4dc; cursor: pointer; font-size: 20px; padding: 0; width: 24px; height: 24px;">×</button>
51            </div>
52            
53            <div style="margin-bottom: 15px;">
54                <div style="display: flex; align-items: center; gap: 8px; margin-bottom: 10px;">
55                    <span style="font-size: 14px; font-weight: 500;">Symbol:</span>
56                    <span id="current-symbol" style="color: #2962ff; font-weight: 600; font-size: 14px;">Loading...</span>
57                </div>
58            </div>
59
60            <button id="analyze-trend-btn" style="
61                width: 100%;
62                padding: 12px;
63                background: linear-gradient(135deg, #2962ff 0%, #1e4db7 100%);
64                color: white;
65                border: none;
66                border-radius: 8px;
67                cursor: pointer;
68                font-size: 14px;
69                font-weight: 600;
70                margin-bottom: 15px;
71                transition: all 0.3s ease;
72            ">
73                🔍 Analyze Trend
74            </button>
75
76            <div id="analysis-result" style="
77                background: #131722;
78                border-radius: 8px;
79                padding: 15px;
80                margin-top: 15px;
81                display: none;
82                border: 1px solid #2a2e39;
83            ">
84                <div id="loading-indicator" style="text-align: center; padding: 20px; display: none;">
85                    <div style="display: inline-block; width: 30px; height: 30px; border: 3px solid #2a2e39; border-top-color: #2962ff; border-radius: 50%; animation: spin 1s linear infinite;"></div>
86                    <p style="margin-top: 10px; color: #787b86;">Analyzing market data...</p>
87                </div>
88                <div id="analysis-content"></div>
89            </div>
90        `;
91
92        // Add CSS animation for loading spinner
93        const style = document.createElement('style');
94        style.textContent = `
95            @keyframes spin {
96                to { transform: rotate(360deg); }
97            }
98            #trend-analyzer-panel::-webkit-scrollbar {
99                width: 8px;
100            }
101            #trend-analyzer-panel::-webkit-scrollbar-track {
102                background: #1e222d;
103                border-radius: 4px;
104            }
105            #trend-analyzer-panel::-webkit-scrollbar-thumb {
106                background: #3a3e49;
107                border-radius: 4px;
108            }
109            #trend-analyzer-panel::-webkit-scrollbar-thumb:hover {
110                background: #4a4e59;
111            }
112            #analyze-trend-btn:hover {
113                transform: translateY(-2px);
114                box-shadow: 0 4px 12px rgba(41, 98, 255, 0.4);
115            }
116            #analyze-trend-btn:active {
117                transform: translateY(0);
118            }
119        `;
120        document.head.appendChild(style);
121
122        document.body.appendChild(panel);
123
124        // Event listeners
125        document.getElementById('close-analyzer').addEventListener('click', () => {
126            panel.style.display = 'none';
127        });
128
129        document.getElementById('analyze-trend-btn').addEventListener('click', analyzeTrend);
130
131        return panel;
132    }
133
134    // Get current symbol from TradingView
135    function getCurrentSymbol() {
136        try {
137            // Try multiple selectors to find the symbol
138            const symbolButton = document.querySelector('button[aria-label="Change symbol"]');
139            if (symbolButton) {
140                return symbolButton.textContent.trim();
141            }
142
143            const symbolLink = document.querySelector('a[data-qa-id="details-element description"] .text-eFCYpbUa');
144            if (symbolLink) {
145                return symbolLink.textContent.trim();
146            }
147
148            const symbolInToolbar = document.querySelector('#header-toolbar-symbol-search .text-cq__ntSC');
149            if (symbolInToolbar) {
150                return symbolInToolbar.textContent.trim();
151            }
152
153            // Fallback to page title
154            const titleMatch = document.title.match(/^([A-Z0-9]+)/);
155            if (titleMatch) {
156                return titleMatch[1];
157            }
158
159            return 'Unknown';
160        } catch (error) {
161            console.error('Error getting symbol:', error);
162            return 'Unknown';
163        }
164    }
165
166    // Get visible chart data
167    function getChartData() {
168        try {
169            const symbol = getCurrentSymbol();
170            
171            // Get price information from legend
172            const legendItems = document.querySelectorAll('.valueItem-l31H9iuA');
173            const priceData = {};
174            
175            legendItems.forEach(item => {
176                const title = item.querySelector('.valueTitle-l31H9iuA');
177                const value = item.querySelector('.valueValue-l31H9iuA');
178                if (title && value) {
179                    priceData[title.textContent.trim()] = value.textContent.trim();
180                }
181            });
182
183            // Get current price and change
184            const priceElement = document.querySelector('.lastContainer-JWoJqCpY');
185            const changeElement = document.querySelector('.changePercent-JWoJqCpY');
186            
187            let currentPrice = 'N/A';
188            let priceChange = 'N/A';
189            
190            if (priceElement) {
191                currentPrice = priceElement.textContent.trim();
192            }
193            
194            if (changeElement) {
195                priceChange = changeElement.textContent.trim();
196            }
197
198            // Get interval
199            const intervalButton = document.querySelector('button[aria-label="Chart interval"]');
200            const interval = intervalButton ? intervalButton.textContent.trim() : 'Unknown';
201
202            return {
203                symbol,
204                currentPrice,
205                priceChange,
206                interval,
207                priceData,
208                timestamp: new Date().toISOString()
209            };
210        } catch (error) {
211            console.error('Error getting chart data:', error);
212            return {
213                symbol: getCurrentSymbol(),
214                error: 'Could not extract chart data'
215            };
216        }
217    }
218
219    // Analyze trend using AI
220    async function analyzeTrend() {
221        const resultDiv = document.getElementById('analysis-result');
222        const loadingDiv = document.getElementById('loading-indicator');
223        const contentDiv = document.getElementById('analysis-content');
224        
225        resultDiv.style.display = 'block';
226        loadingDiv.style.display = 'block';
227        contentDiv.innerHTML = '';
228
229        try {
230            const chartData = getChartData();
231            console.log('Chart data collected:', chartData);
232
233            // Create analysis prompt
234            const prompt = `Analyze the following trading data and provide insights:
235
236Symbol: ${chartData.symbol}
237Current Price: ${chartData.currentPrice}
238Price Change: ${chartData.priceChange}
239Timeframe: ${chartData.interval}
240Additional Data: ${JSON.stringify(chartData.priceData)}
241
242Please provide:
2431. Overall trend direction (bullish, bearish, or neutral)
2442. Key support and resistance levels if identifiable
2453. Market sentiment analysis
2464. Potential trading opportunities or risks
2475. Short-term outlook
248
249Format your response in a clear, structured way.`;
250
251            const analysis = await RM.aiCall(prompt);
252            
253            loadingDiv.style.display = 'none';
254            
255            // Display analysis
256            contentDiv.innerHTML = `
257                <div style="color: #d1d4dc; line-height: 1.6; font-size: 13px;">
258                    <div style="background: #1e222d; padding: 12px; border-radius: 6px; margin-bottom: 12px;">
259                        <div style="color: #787b86; font-size: 11px; margin-bottom: 8px;">ANALYSIS FOR ${chartData.symbol}</div>
260                        <div style="color: #fff; font-size: 16px; font-weight: 600;">${chartData.currentPrice}</div>
261                        <div style="color: ${chartData.priceChange.includes('-') ? '#f23645' : '#089981'}; font-size: 13px; margin-top: 4px;">${chartData.priceChange}</div>
262                    </div>
263                    <div style="white-space: pre-wrap; word-wrap: break-word;">${formatAnalysis(analysis)}</div>
264                    <div style="margin-top: 15px; padding-top: 15px; border-top: 1px solid #2a2e39; font-size: 11px; color: #787b86;">
265                        Generated at ${new Date().toLocaleTimeString()}
266                    </div>
267                </div>
268            `;
269
270            // Save analysis to storage
271            await GM.setValue('last_analysis_' + chartData.symbol, {
272                analysis,
273                chartData,
274                timestamp: Date.now()
275            });
276
277        } catch (error) {
278            console.error('Analysis error:', error);
279            loadingDiv.style.display = 'none';
280            contentDiv.innerHTML = `
281                <div style="color: #f23645; padding: 15px; text-align: center;">
282                    <div style="font-size: 24px; margin-bottom: 8px;">⚠️</div>
283                    <div style="font-size: 14px; font-weight: 600; margin-bottom: 8px;">Analysis Failed</div>
284                    <div style="font-size: 12px; color: #787b86;">Unable to analyze the trend. Please try again.</div>
285                </div>
286            `;
287        }
288    }
289
290    // Format analysis text for better readability
291    function formatAnalysis(text) {
292        return text
293            .replace(/\*\*(.*?)\*\*/g, '<strong style="color: #fff;">$1</strong>')
294            .replace(/\n\n/g, '</p><p style="margin: 12px 0;">')
295            .replace(/\n/g, '<br>')
296            .replace(/^(.+)$/, '<p style="margin: 12px 0;">$1</p>')
297            .replace(/(\d+\.)\s/g, '<br><strong style="color: #2962ff;">$1</strong> ')
298            .replace(/(bullish|uptrend|buy)/gi, '<span style="color: #089981; font-weight: 600;">$1</span>')
299            .replace(/(bearish|downtrend|sell)/gi, '<span style="color: #f23645; font-weight: 600;">$1</span>')
300            .replace(/(neutral|sideways|hold)/gi, '<span style="color: #f0b90b; font-weight: 600;">$1</span>');
301    }
302
303    // Update symbol display
304    function updateSymbolDisplay() {
305        const symbolElement = document.getElementById('current-symbol');
306        if (symbolElement) {
307            const symbol = getCurrentSymbol();
308            symbolElement.textContent = symbol;
309        }
310    }
311
312    // Initialize the extension
313    function init() {
314        console.log('Initializing Trend Analyzer...');
315
316        // Wait for TradingView to load
317        const checkTradingViewLoaded = setInterval(() => {
318            const chartContainer = document.querySelector('.chart-container');
319            if (chartContainer) {
320                clearInterval(checkTradingViewLoaded);
321                
322                // Create the analyzer panel
323                setTimeout(() => {
324                    createAnalyzerPanel();
325                    updateSymbolDisplay();
326                    
327                    // Update symbol when it changes
328                    const debouncedUpdate = debounce(updateSymbolDisplay, 1000);
329                    const observer = new MutationObserver(debouncedUpdate);
330                    
331                    const symbolButton = document.querySelector('button[aria-label="Change symbol"]');
332                    if (symbolButton) {
333                        observer.observe(symbolButton, { 
334                            childList: true, 
335                            subtree: true, 
336                            characterData: true 
337                        });
338                    }
339                    
340                    console.log('Trend Analyzer panel created successfully');
341                }, 2000);
342            }
343        }, 1000);
344
345        // Cleanup after 30 seconds if not loaded
346        setTimeout(() => {
347            clearInterval(checkTradingViewLoaded);
348        }, 30000);
349    }
350
351    // Start the extension
352    if (document.readyState === 'loading') {
353        document.addEventListener('DOMContentLoaded', init);
354    } else {
355        init();
356    }
357
358})();
Trend Analyzer for TradingView | Robomonkey