tradingview-mcp 26.2.0__py3-none-any.whl → 26.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
File without changes
@@ -0,0 +1,70 @@
1
+ from __future__ import annotations
2
+ from typing import Any, Optional
3
+
4
+ from tradingview_mcp.docs_data import (
5
+ get_ai_quick_reference,
6
+ search_fields,
7
+ get_screener_code_examples,
8
+ get_valid_fields_for_market,
9
+ get_common_fields,
10
+ lookup_field,
11
+ get_field_summary,
12
+ get_filter_format,
13
+ validate_market,
14
+ get_quick_reference,
15
+ get_screener_presets,
16
+ get_metainfo
17
+ )
18
+
19
+ def ai_get_reference() -> dict[str, Any]:
20
+ """Get AI quick reference for using this MCP."""
21
+ return get_ai_quick_reference()
22
+
23
+ def search_available_fields(query: str, market: str = None) -> list[dict[str, Any]]:
24
+ """Search for available fields/columns."""
25
+ return search_fields(query, market)
26
+
27
+ def get_code_example(name: str) -> str:
28
+ """Get code example by name."""
29
+ examples = get_screener_code_examples()
30
+ return examples.get(name, "Example not found.")
31
+
32
+ def list_fields_for_market(market: str) -> list[str]:
33
+ """List valid fields for a specific market."""
34
+ return get_valid_fields_for_market(market)
35
+
36
+ def get_common_fields_summary() -> dict[str, Any]:
37
+ """Get summary of common fields."""
38
+ return get_common_fields()
39
+
40
+ def lookup_single_field(name: str) -> dict[str, Any]:
41
+ """Lookup details for a single field."""
42
+ return lookup_field(name)
43
+
44
+ def get_field_info(name: str) -> dict[str, Any]:
45
+ """Get info for a field."""
46
+ return get_field_summary(name) or {"error": "Field not found"}
47
+
48
+ def get_filter_example(type: str = "number") -> dict[str, Any]:
49
+ """Get example filter format."""
50
+ return get_filter_format(type)
51
+
52
+ def check_market(market: str) -> dict[str, Any]:
53
+ """Validate a market name."""
54
+ return validate_market(market)
55
+
56
+ def get_help() -> dict[str, Any]:
57
+ """Get help and usage info."""
58
+ return get_quick_reference()
59
+
60
+ def get_screener_preset(name: str) -> dict[str, Any]:
61
+ """Get a screener preset."""
62
+ presets = get_screener_presets()
63
+ for p in presets:
64
+ if p.get("name") == name:
65
+ return p
66
+ return {"error": "Preset not found"}
67
+
68
+ def get_market_metainfo(market: str) -> dict[str, Any]:
69
+ """Get metainfo for a market."""
70
+ return get_metainfo(market)
@@ -0,0 +1,87 @@
1
+ from __future__ import annotations
2
+ from typing import Any, Optional
3
+
4
+ from tradingview_mcp.column import Column
5
+ from tradingview_mcp.constants import DEFAULT_COLUMNS, get_column_name
6
+ from tradingview_mcp.query import Query
7
+ from tradingview_mcp.utils import sanitize_market
8
+
9
+ def screen_market(
10
+ market: str = "america",
11
+ columns: Optional[list[str]] = None,
12
+ sort_by: str = "volume",
13
+ ascending: bool = False,
14
+ limit: int = 25,
15
+ filters: Optional[list[dict[str, Any]]] = None,
16
+ ) -> dict[str, Any]:
17
+ """Run a custom market screening query."""
18
+ market = sanitize_market(market)
19
+ limit = max(1, min(limit, 500))
20
+
21
+ # Ensure description is always included
22
+ cols = columns or DEFAULT_COLUMNS
23
+ if "description" not in cols:
24
+ cols = ["description"] + list(cols)
25
+
26
+ query = Query().set_markets(market).select(*cols).order_by(sort_by, ascending=ascending).limit(limit)
27
+
28
+ # Apply filters if provided
29
+ if filters:
30
+ filter_expressions = []
31
+ for f in filters:
32
+ # Automatic translation of human-readable column names
33
+ col_name = get_column_name(f.get("column", "close"))
34
+ col = Column(col_name)
35
+ op = f.get("operation", "gt")
36
+ val = f.get("value")
37
+
38
+ if op == "gt":
39
+ filter_expressions.append(col > val)
40
+ elif op == "gte":
41
+ filter_expressions.append(col >= val)
42
+ elif op == "lt":
43
+ filter_expressions.append(col < val)
44
+ elif op == "lte":
45
+ filter_expressions.append(col <= val)
46
+ elif op == "eq":
47
+ filter_expressions.append(col == val)
48
+ elif op == "neq":
49
+ filter_expressions.append(col != val)
50
+ elif op == "between" and isinstance(val, (list, tuple)) and len(val) == 2:
51
+ filter_expressions.append(col.between(val[0], val[1]))
52
+ elif op == "isin" and isinstance(val, (list, tuple)):
53
+ filter_expressions.append(col.isin(val))
54
+
55
+ if filter_expressions:
56
+ query = query.where(*filter_expressions)
57
+
58
+ try:
59
+ total_count, df = query.get_scanner_data()
60
+ results = df.to_dict("records")
61
+
62
+ return {
63
+ "total_count": total_count,
64
+ "returned": len(results),
65
+ "market": market,
66
+ "data": results,
67
+ }
68
+ except Exception as e:
69
+ return {"error": str(e), "market": market}
70
+
71
+
72
+ def get_top_gainers(market: str = "america", limit: int = 25) -> dict[str, Any]:
73
+ """Get top gainers for a market."""
74
+ market = sanitize_market(market)
75
+ return screen_market(market, sort_by="change", ascending=False, limit=limit)
76
+
77
+
78
+ def get_top_losers(market: str = "america", limit: int = 25) -> dict[str, Any]:
79
+ """Get top losers for a market."""
80
+ market = sanitize_market(market)
81
+ return screen_market(market, sort_by="change", ascending=True, limit=limit)
82
+
83
+
84
+ def get_most_active(market: str = "america", limit: int = 25) -> dict[str, Any]:
85
+ """Get most active symbols by volume."""
86
+ market = sanitize_market(market)
87
+ return screen_market(market, sort_by="volume", ascending=False, limit=limit)
@@ -0,0 +1,326 @@
1
+ from __future__ import annotations
2
+ from typing import Any
3
+ import concurrent.futures
4
+
5
+ from mcp.server.fastmcp import Context
6
+
7
+ from tradingview_mcp.column import Column
8
+ from tradingview_mcp.constants import EXCHANGE_SCREENER
9
+ from tradingview_mcp.docs_data import get_default_columns_for_market, STOCK_MARKETS
10
+ from tradingview_mcp.query import Query
11
+ from tradingview_mcp.utils import sanitize_market
12
+
13
+ def search_symbols(
14
+ query: str,
15
+ market: str = "america",
16
+ limit: int = 25,
17
+ ) -> dict[str, Any]:
18
+ """
19
+ Search symbols by name or ticker.
20
+ If default market returns no results, automatically searches crypto and forex.
21
+ """
22
+ market = sanitize_market(market)
23
+ limit = max(1, min(limit, 100))
24
+
25
+ # Use dynamic default columns for this market
26
+ cols = get_default_columns_for_market(market)
27
+
28
+ # Determine sort column
29
+ sort_col = "market_cap_basic" if "market_cap_basic" in cols else "name"
30
+
31
+ try:
32
+ # Standard search in requested market
33
+ results = _execute_search(query, market, limit, cols, sort_col)
34
+
35
+ # Smart Fallback: If default market ('america') yielded no results, try others
36
+ if not results["results"] and market == "america":
37
+
38
+ # 1. Asian Numeric Heuristic (Prioritized for speed/accuracy)
39
+ if query.isdigit() and len(query) in [4, 5, 6]:
40
+ asian_markets = ["taiwan", "hongkong", "japan", "china", "korea"]
41
+ for asian_market in asian_markets:
42
+ asian_cols = get_default_columns_for_market(asian_market)
43
+ asian_sort = "volume" # Volume is good for general Asian scanners
44
+ asian_res = _execute_search(query, asian_market, 5, asian_cols, asian_sort)
45
+ if asian_res["results"]:
46
+ return {**asian_res, "note": f"No results in 'america', found matches in '{asian_market}' (numeric heuristic)"}
47
+
48
+ # 2. True Global Search (Check ALL 68+ Stock Markets)
49
+ try:
50
+ # Use standard global columns safe for all
51
+ global_cols = ["name", "description", "close", "change", "volume", "market_cap_basic", "exchange", "type"]
52
+
53
+ # Check Description First (often better for "Maybank")
54
+ q = (
55
+ Query()
56
+ .set_markets(*STOCK_MARKETS)
57
+ .select(*global_cols)
58
+ .where(Column("description").like(query))
59
+ .order_by("volume", ascending=False)
60
+ .limit(5)
61
+ )
62
+ _, df = q.get_scanner_data()
63
+
64
+ if df.empty:
65
+ # Check Name (Ticker)
66
+ q = (
67
+ Query()
68
+ .set_markets(*STOCK_MARKETS)
69
+ .select(*global_cols)
70
+ .where(Column("name").like(query))
71
+ .order_by("volume", ascending=False)
72
+ .limit(5)
73
+ )
74
+ _, df = q.get_scanner_data()
75
+
76
+ if not df.empty:
77
+ # Basic Global Result
78
+ total = len(df) # Roughly
79
+ return {
80
+ "query": query,
81
+ "market": "global",
82
+ "total_found": total,
83
+ "returned": len(df),
84
+ "results": df.to_dict("records"),
85
+ "note": "No results in 'america', found matches in global stock markets."
86
+ }
87
+
88
+ except Exception:
89
+ pass # Continue to other fallbacks
90
+
91
+ # 3. Check Crypto/Forex
92
+ for other in ["crypto", "forex"]:
93
+ if other == market: continue
94
+
95
+ cols = get_default_columns_for_market(other)
96
+ sort = "market_cap_basic" if "market_cap_basic" in cols else "name"
97
+ if other == "forex": sort = "name"
98
+
99
+ res = _execute_search(query, other, 5, cols, sort)
100
+ if res["results"]:
101
+ return {**res, "note": f"No results in stocks, found matches in '{other}'"}
102
+
103
+ return results
104
+
105
+ except Exception as e:
106
+ return _search_symbols_fallback(query, market, limit, cols, str(e))
107
+
108
+
109
+ def _execute_search(query: str, market: str, limit: int, cols: list[str], sort_col: str) -> dict[str, Any]:
110
+ """Execute a single search query against a market."""
111
+ try:
112
+ # 1. Search description (company name)
113
+ query_obj = (
114
+ Query()
115
+ .set_markets(market)
116
+ .select(*cols)
117
+ .where(Column("description").like(query))
118
+ .order_by(sort_col, ascending=False)
119
+ .limit(limit)
120
+ )
121
+ total, df = query_obj.get_scanner_data()
122
+ results = df.to_dict("records")
123
+
124
+ # 2. If nothing found, search name (ticker)
125
+ if not results:
126
+ query_obj2 = (
127
+ Query()
128
+ .set_markets(market)
129
+ .select(*cols)
130
+ .where(Column("name").like(query))
131
+ .order_by(sort_col, ascending=False)
132
+ .limit(limit)
133
+ )
134
+ total, df = query_obj2.get_scanner_data()
135
+ results = df.to_dict("records")
136
+
137
+ return {
138
+ "query": query,
139
+ "market": market,
140
+ "total_found": total if results else 0,
141
+ "returned": len(results),
142
+ "results": results,
143
+ "hint": "Use 'name' field as symbol for other tools" if results else "No matches found.",
144
+ }
145
+ except Exception:
146
+ return {"results": [], "market": market}
147
+
148
+
149
+ def _search_symbols_fallback(query: str, market: str, limit: int, cols: list[str], error: str) -> dict[str, Any]:
150
+ """Fallback search when API operations fail."""
151
+ try:
152
+ q = Query().set_markets(market).select(*cols).limit(100)
153
+ _, df = q.get_scanner_data()
154
+ q_lower = query.lower()
155
+ mask = df["name"].str.lower().str.contains(q_lower) | df["description"].str.lower().str.contains(q_lower)
156
+ df_filtered = df[mask].head(limit)
157
+ return {
158
+ "query": query,
159
+ "market": market,
160
+ "returned": len(df_filtered),
161
+ "results": df_filtered.to_dict("records"),
162
+ "note": "Used fallback local search.",
163
+ "original_error": error,
164
+ }
165
+ except Exception as e:
166
+ return {"error": f"Search failed: {str(e)}", "original_error": error}
167
+
168
+
169
+ def get_symbol_info(symbol: str, include_technical: bool = False) -> dict[str, Any]:
170
+ """
171
+ Get detailed information for a symbol.
172
+
173
+ Modes:
174
+ 1. Strict: 'EXCHANGE:SYMBOL' (e.g. 'NASDAQ:AAPL') - searches only that exchange/market.
175
+ 2. Universal: 'SYMBOL' (e.g. 'AAA') - searches ALL global markets, Crypto, and Forex.
176
+ Returns ALL matches found to verify ambiguity.
177
+ """
178
+ technical_cols = [
179
+ "RSI", "RSI7", "MACD.macd", "MACD.signal", "SMA20", "SMA50", "SMA200",
180
+ "EMA20", "EMA50", "EMA200", "BB.upper", "BB.lower", "ATR", "ADX",
181
+ "Recommend.All", "Recommend.MA", "Recommend.Other"
182
+ ]
183
+
184
+ try:
185
+ # --- Strict Mode (Exchange Specified) ---
186
+ if ":" in symbol:
187
+ exchange, ticker = symbol.split(":", 1)
188
+ market = EXCHANGE_SCREENER.get(exchange.lower()) or "america"
189
+
190
+ # Setup Columns
191
+ cols = get_default_columns_for_market(market)
192
+ if include_technical: cols.extend(technical_cols)
193
+ cols = list(dict.fromkeys(cols))
194
+
195
+ # Query
196
+ q = (
197
+ Query()
198
+ .set_markets(market)
199
+ .select(*cols)
200
+ .where(Column("name").isin([symbol, ticker, symbol.upper(), ticker.upper()]))
201
+ .limit(5)
202
+ )
203
+ _, df = q.get_scanner_data()
204
+ results = df.to_dict("records")
205
+
206
+ if results:
207
+ if len(results) == 1:
208
+ return {"symbol": symbol, "found": True, "market": market, "data": results[0]}
209
+ return {"symbol": symbol, "found": True, "market": market, "matches": results}
210
+ else:
211
+ return {"symbol": symbol, "found": False, "hint": f"Symbol not found in {market} ({exchange}). Check format."}
212
+
213
+ # --- Universal Mode (Implicit Market) ---
214
+ # We search Stocks (Global), Crypto, vs Forex in parallel using ThreadPoolExecutor
215
+ all_matches = []
216
+
217
+ def check_global_stocks():
218
+ try:
219
+ stock_cols = ["name", "description", "close", "change", "volume", "market_cap_basic", "exchange", "type"]
220
+ if include_technical: stock_cols.extend(technical_cols)
221
+ stock_cols = list(dict.fromkeys(stock_cols))
222
+
223
+ q_stocks = (
224
+ Query()
225
+ .set_markets(*STOCK_MARKETS)
226
+ .select(*stock_cols)
227
+ .where(Column("name").isin([symbol, symbol.upper()]))
228
+ .order_by("market_cap_basic", ascending=False)
229
+ .limit(10)
230
+ )
231
+ _, df_stocks = q_stocks.get_scanner_data()
232
+ if not df_stocks.empty:
233
+ matches = df_stocks.to_dict("records")
234
+ for m in matches: m["_category"] = "stock"
235
+ return matches
236
+ except Exception:
237
+ pass
238
+ return []
239
+
240
+ def check_crypto():
241
+ try:
242
+ crypto_cols = get_default_columns_for_market("crypto")
243
+ if include_technical: crypto_cols.extend(technical_cols)
244
+ crypto_cols = list(dict.fromkeys(crypto_cols))
245
+
246
+ q_crypto = (
247
+ Query()
248
+ .set_markets("crypto")
249
+ .select(*crypto_cols)
250
+ .where(Column("name").isin([symbol, symbol.upper(), f"{symbol}USDT", f"{symbol}USD"]))
251
+ .limit(5)
252
+ )
253
+ _, df_crypto = q_crypto.get_scanner_data()
254
+ if not df_crypto.empty:
255
+ matches = df_crypto.to_dict("records")
256
+ for m in matches: m["_category"] = "crypto"
257
+ return matches
258
+ except Exception:
259
+ pass
260
+ return []
261
+
262
+ def check_forex():
263
+ try:
264
+ forex_cols = get_default_columns_for_market("forex")
265
+ if include_technical: forex_cols.extend(technical_cols)
266
+ forex_cols = list(dict.fromkeys(forex_cols))
267
+
268
+ q_forex = (
269
+ Query()
270
+ .set_markets("forex")
271
+ .select(*forex_cols)
272
+ .where(Column("name").isin([symbol, symbol.upper()]))
273
+ .limit(5)
274
+ )
275
+ _, df_forex = q_forex.get_scanner_data()
276
+ if not df_forex.empty:
277
+ matches = df_forex.to_dict("records")
278
+ for m in matches: m["_category"] = "forex"
279
+ return matches
280
+ except Exception:
281
+ pass
282
+ return []
283
+
284
+ # Execute in parallel
285
+ with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
286
+ futures = [
287
+ executor.submit(check_global_stocks),
288
+ executor.submit(check_crypto),
289
+ executor.submit(check_forex)
290
+ ]
291
+ for future in concurrent.futures.as_completed(futures):
292
+ all_matches.extend(future.result())
293
+
294
+ # --- Aggregate Results ---
295
+ if not all_matches:
296
+ # Try search_symbols as last resort (fuzzy search)
297
+ return search_symbols(symbol, "america", 5)
298
+
299
+ # Remove duplicates based on ticker
300
+ unique_matches = {}
301
+ for m in all_matches:
302
+ key = m.get("ticker", m.get("name"))
303
+ if key not in unique_matches:
304
+ unique_matches[key] = m
305
+
306
+ final_matches = list(unique_matches.values())
307
+
308
+ if len(final_matches) == 1:
309
+ first = final_matches[0]
310
+ cat = first.pop("_category", "global")
311
+ return {"symbol": symbol, "found": True, "market": cat, "data": first}
312
+
313
+ return {
314
+ "symbol": symbol,
315
+ "found": True,
316
+ "market": "global",
317
+ "count": len(final_matches),
318
+ "matches": final_matches,
319
+ "note": "Multiple matches found across global markets."
320
+ }
321
+
322
+ except Exception as e:
323
+ return {
324
+ "error": f"Failed to get symbol info: {str(e)}",
325
+ "hint": "Try using search_symbols to find the correct symbol format",
326
+ }
@@ -0,0 +1,113 @@
1
+ from __future__ import annotations
2
+ from typing import Any
3
+
4
+ from tradingview_mcp.column import Column
5
+ from tradingview_mcp.constants import TECHNICAL_COLUMNS
6
+ from tradingview_mcp.query import Query
7
+ from tradingview_mcp.utils import sanitize_market
8
+
9
+ def get_technical_analysis(symbol: str, market: str = "america") -> dict[str, Any]:
10
+ """Get technical indicators for a symbol."""
11
+ market = sanitize_market(market)
12
+
13
+ # Use standard technical columns
14
+ cols = list(TECHNICAL_COLUMNS)
15
+
16
+ try:
17
+ q = (
18
+ Query()
19
+ .set_markets(market)
20
+ .select(*cols)
21
+ .where(Column("name").isin([symbol, symbol.upper()]))
22
+ .limit(1)
23
+ )
24
+ _, df = q.get_scanner_data()
25
+
26
+ if df.empty:
27
+ return {"error": f"Symbol {symbol} not found in {market}"}
28
+
29
+ data = df.iloc[0].to_dict()
30
+ return {
31
+ "symbol": symbol,
32
+ "market": market,
33
+ "indicators": data
34
+ }
35
+ except Exception as e:
36
+ return {"error": str(e)}
37
+
38
+ def scan_rsi_extremes(market: str = "america", limit: int = 25) -> dict[str, Any]:
39
+ """Find symbols with extreme RSI values (<30 or >70)."""
40
+ market = sanitize_market(market)
41
+
42
+ q = (
43
+ Query()
44
+ .set_markets(market)
45
+ .select("name", "close", "RSI", "volume")
46
+ # RSI > 70 OR RSI < 30. Note: Current Query builder supports AND by default.
47
+ # For OR logic, we might need multiple queries or where2 if supported.
48
+ # Let's simple check oversold first (<30)
49
+ .where(Column("RSI") < 30)
50
+ .order_by("RSI", ascending=True)
51
+ .limit(limit)
52
+ )
53
+
54
+ try:
55
+ _, df_oversold = q.get_scanner_data()
56
+ oversold = df_oversold.to_dict("records")
57
+
58
+ # Overbought
59
+ q2 = (
60
+ Query()
61
+ .set_markets(market)
62
+ .select("name", "close", "RSI", "volume")
63
+ .where(Column("RSI") > 70)
64
+ .order_by("RSI", ascending=False)
65
+ .limit(limit)
66
+ )
67
+ _, df_overbought = q2.get_scanner_data()
68
+ overbought = df_overbought.to_dict("records")
69
+
70
+ return {
71
+ "market": market,
72
+ "oversold": oversold,
73
+ "overbought": overbought
74
+ }
75
+ except Exception as e:
76
+ return {"error": str(e)}
77
+
78
+ def scan_bollinger_bands(market: str = "america", limit: int = 25) -> dict[str, Any]:
79
+ """Find symbols trading outside Bollinger Bands."""
80
+ market = sanitize_market(market)
81
+ # This is complex to do with simple filters.
82
+ # We'll just return basic BB values for top volume stocks.
83
+
84
+ q = (
85
+ Query()
86
+ .set_markets(market)
87
+ .select("name", "close", "BB.upper", "BB.lower")
88
+ .order_by("volume", ascending=False)
89
+ .limit(limit)
90
+ )
91
+
92
+ try:
93
+ _, df = q.get_scanner_data()
94
+ return {"data": df.to_dict("records")}
95
+ except Exception as e:
96
+ return {"error": str(e)}
97
+
98
+ def scan_macd_crossover(market: str = "america", limit: int = 25) -> dict[str, Any]:
99
+ """scan for MACD crossovers."""
100
+ market = sanitize_market(market)
101
+ q = (
102
+ Query()
103
+ .set_markets(market)
104
+ .select("name", "close", "MACD.macd", "MACD.signal")
105
+ .where(Column("MACD.macd") > Column("MACD.signal")) # Bullish crossoverish (simple comparison)
106
+ .order_by("volume", ascending=False)
107
+ .limit(limit)
108
+ )
109
+ try:
110
+ _, df = q.get_scanner_data()
111
+ return {"bullish_macd_momentum": df.to_dict("records")}
112
+ except Exception as e:
113
+ return {"error": str(e)}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tradingview-mcp
3
- Version: 26.2.0
3
+ Version: 26.3.0
4
4
  Summary: A comprehensive MCP server for TradingView market screening with integrated screener functionality
5
5
  Project-URL: Homepage, https://github.com/k73a/tradingview-mcp
6
6
  Project-URL: Documentation, https://github.com/k73a/tradingview-mcp#readme
@@ -43,7 +43,6 @@ Description-Content-Type: text/markdown
43
43
  MCP server for TradingView market screening. Supports stocks, crypto, forex, futures, bonds across 76+ markets.
44
44
 
45
45
  ## Quick Start
46
-
47
46
  ```json
48
47
  {
49
48
  "mcpServers": {
@@ -55,6 +54,12 @@ MCP server for TradingView market screening. Supports stocks, crypto, forex, fut
55
54
  }
56
55
  ```
57
56
 
57
+ ## Smart Features
58
+
59
+ - **Auto-Market Detection**: If you search for `EURUSD` or `BTCUSDT`, the server automatically checks Forex and Crypto markets if not found in stocks.
60
+ - **Strict Exchange Support**: Use `EXCHANGE:SYMBOL` format (e.g., `BINANCE:BTCUSDT`, `FX:EURUSD`) to target specific markets.
61
+ - **Smart Filters**: You can use human-readable names in filters (e.g., `"Relative Strength Index (14)"` instead of `"RSI"`).
62
+
58
63
  ## Main Tools
59
64
 
60
65
  | Tool | Description |
@@ -87,7 +92,9 @@ MCP server for TradingView market screening. Supports stocks, crypto, forex, fut
87
92
  | `list_fields_for_market` | List fields for a market |
88
93
  | `get_screener_preset` | Get predefined screener presets |
89
94
 
90
- ## Resources
95
+ ## Reference Resources
96
+
97
+ These resources provide raw lists of available markets and fields for reference.
91
98
 
92
99
  | Resource | Description |
93
100
  |----------|-------------|
@@ -1,11 +1,12 @@
1
1
  tradingview_mcp/__init__.py,sha256=V7RLq22Qp1rsMhDYNlXfWkiNaXlo7s4KkNUmSvbGKIM,455
2
2
  tradingview_mcp/column.py,sha256=MC7lWksmyaYF4SkVm97Apr8httwip-N-4aVTSyS0CQo,8871
3
- tradingview_mcp/constants.py,sha256=kQUhcG0U1cVLiN6LGgzWPjCGhXh_-jvB5lF15QIX1_4,12927
4
- tradingview_mcp/docs_data.py,sha256=4mhaO-far90SSXzSl1fLZIzNBe0lOTxFeX7ITzYTBpo,17698
3
+ tradingview_mcp/constants.py,sha256=RlhAbBSbOUUJejyTiYozNjCD29TimVTC-ok2HkDzi_s,5417
4
+ tradingview_mcp/docs_data.py,sha256=PYMZxC2Y6Xqcv4XP2Z7pIKzNSokW440Zq68H5fgSASs,19118
5
5
  tradingview_mcp/models.py,sha256=CHSQ46A2ljhvzI6YP8XRItUdoDJw1yYebiBANt9xeD0,3366
6
6
  tradingview_mcp/query.py,sha256=gkC4t-2_jtuUK3KgzU62wrIcGoaOmY--1EwAshGQb0Q,10871
7
+ tradingview_mcp/resources.py,sha256=6cbsPhXsq6SFh3bmmSnMtrVkyCx1_xpWWiyqNLCCULk,1910
7
8
  tradingview_mcp/scanner.py,sha256=oEfMzaYhQ7ggBdLlPLqKZCMxHkd6MBMaUMcm3p-YvPA,7649
8
- tradingview_mcp/server.py,sha256=WdBov_EoJGA_BNurf1PJ6m6_ZayztjqqniItOvudkPY,51698
9
+ tradingview_mcp/server.py,sha256=opC61fKfchYn3-XL5ZlPGvsPRZZoLXe-VqGSulhrJHA,7165
9
10
  tradingview_mcp/utils.py,sha256=6O89qIaZ_eYoN3m12r2q4-D8VpJajP5WuwKQbj4ZVHo,10238
10
11
  tradingview_mcp/data/__init__.py,sha256=3kot_ZG4a6jbZgyksE9z56n3skI407lsd4y2ThHotKY,298
11
12
  tradingview_mcp/data/column_display_names.json,sha256=AFdo6Q2n-wSXWHi2wEExOd2pTItyjocRbrnxqYpCa94,30137
@@ -31,8 +32,13 @@ tradingview_mcp/data/screeners/main_screeners.json,sha256=kU_xGJ7ePoGN3s8g9PwGrc
31
32
  tradingview_mcp/data/screeners/markets.json,sha256=vpdrAKg4E_lgg4FxeX2GHNbnSsKQDmgfnyr2ziSdQsk,1004
32
33
  tradingview_mcp/data/screeners/stocks.json,sha256=gCnntHTJKJ7n7IqY72fZ4EuBfthtnWUpfHvPqNOvnXo,8843
33
34
  tradingview_mcp/data/screeners/stocks_failed.json,sha256=RqBp9XCZ3xvdWZMwuVGysEE2Er_XOQvBZoUHo9uyj6k,1084574
34
- tradingview_mcp-26.2.0.dist-info/METADATA,sha256=ayxnek_OIGlG_IpQZTsE_jmR7J0LljnN1STnzVQxC3o,4303
35
- tradingview_mcp-26.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
36
- tradingview_mcp-26.2.0.dist-info/entry_points.txt,sha256=GZxjGqgVbUlWDp5OzFQoCN_g1UBLyOmfVqCR5uzscnU,57
37
- tradingview_mcp-26.2.0.dist-info/licenses/LICENSE,sha256=1Hdpp7qGWCXVw1BP6vpdAPO4KrgO0T_c0N3ipkYHKAo,1070
38
- tradingview_mcp-26.2.0.dist-info/RECORD,,
35
+ tradingview_mcp/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
36
+ tradingview_mcp/tools/reference.py,sha256=BPip9ntzyRwIyE0SoD8TWqSGLYj7Evt-OM1SQ1uPG8o,2160
37
+ tradingview_mcp/tools/screener.py,sha256=K6uOUFq4GzPeCE4w2oa1LkAHbodQdQcmexw0W3sofeo,3188
38
+ tradingview_mcp/tools/search.py,sha256=40Wpcf-noEkcB8Yv3f1NPd0UtmixWEf_AZoGf_GGibM,12970
39
+ tradingview_mcp/tools/technical.py,sha256=l5nhXLQu-5iGJ0G-pdVFAghQsXv7JqoEGlphqrEjxQ8,3620
40
+ tradingview_mcp-26.3.0.dist-info/METADATA,sha256=pBPcg95atEn_vedXIz7dwJ3WWeVgCv6HCT1xWjsQ3bU,4818
41
+ tradingview_mcp-26.3.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
42
+ tradingview_mcp-26.3.0.dist-info/entry_points.txt,sha256=GZxjGqgVbUlWDp5OzFQoCN_g1UBLyOmfVqCR5uzscnU,57
43
+ tradingview_mcp-26.3.0.dist-info/licenses/LICENSE,sha256=1Hdpp7qGWCXVw1BP6vpdAPO4KrgO0T_c0N3ipkYHKAo,1070
44
+ tradingview_mcp-26.3.0.dist-info/RECORD,,