tradingview-mcp 1.0.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.
- tradingview_mcp/__init__.py +14 -0
- tradingview_mcp/column.py +231 -0
- tradingview_mcp/constants.py +425 -0
- tradingview_mcp/models.py +154 -0
- tradingview_mcp/query.py +367 -0
- tradingview_mcp/scanner.py +256 -0
- tradingview_mcp/server.py +1361 -0
- tradingview_mcp/utils.py +382 -0
- tradingview_mcp-1.0.0.dist-info/METADATA +182 -0
- tradingview_mcp-1.0.0.dist-info/RECORD +13 -0
- tradingview_mcp-1.0.0.dist-info/WHEEL +4 -0
- tradingview_mcp-1.0.0.dist-info/entry_points.txt +2 -0
- tradingview_mcp-1.0.0.dist-info/licenses/LICENSE +23 -0
tradingview_mcp/utils.py
ADDED
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Utility functions for TradingView MCP.
|
|
3
|
+
|
|
4
|
+
Provides helper functions for data processing, validation, and technical analysis.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Any, Optional
|
|
10
|
+
|
|
11
|
+
from tradingview_mcp.constants import (
|
|
12
|
+
ALLOWED_TIMEFRAMES,
|
|
13
|
+
EXCHANGE_SCREENER,
|
|
14
|
+
MARKETS,
|
|
15
|
+
TIMEFRAME_MAP,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def sanitize_timeframe(tf: str | None, default: str = "15m") -> str:
|
|
20
|
+
"""
|
|
21
|
+
Validate and sanitize a timeframe string.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
tf: Timeframe to validate
|
|
25
|
+
default: Default value if invalid
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
Valid timeframe string
|
|
29
|
+
"""
|
|
30
|
+
if not tf:
|
|
31
|
+
return default
|
|
32
|
+
tf = tf.strip()
|
|
33
|
+
return tf if tf in ALLOWED_TIMEFRAMES else default
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def sanitize_exchange(ex: str | None, default: str = "america") -> str:
|
|
37
|
+
"""
|
|
38
|
+
Validate and sanitize an exchange name.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
ex: Exchange to validate
|
|
42
|
+
default: Default value if invalid
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
Valid exchange/market string
|
|
46
|
+
"""
|
|
47
|
+
if not ex:
|
|
48
|
+
return default
|
|
49
|
+
ex = ex.strip().lower()
|
|
50
|
+
if ex in EXCHANGE_SCREENER:
|
|
51
|
+
return ex
|
|
52
|
+
if ex in MARKETS:
|
|
53
|
+
return ex
|
|
54
|
+
return default
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def sanitize_market(market: str | None, default: str = "america") -> str:
|
|
58
|
+
"""
|
|
59
|
+
Validate and sanitize a market name.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
market: Market to validate
|
|
63
|
+
default: Default value if invalid
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
Valid market string
|
|
67
|
+
"""
|
|
68
|
+
if not market:
|
|
69
|
+
return default
|
|
70
|
+
market = market.strip().lower()
|
|
71
|
+
return market if market in MARKETS else default
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def timeframe_to_resolution(tf: str) -> str:
|
|
75
|
+
"""
|
|
76
|
+
Convert timeframe to TradingView API resolution.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
tf: Timeframe string (e.g., '15m', '1h', '4h', '1D')
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
TradingView resolution string
|
|
83
|
+
"""
|
|
84
|
+
return TIMEFRAME_MAP.get(tf, tf)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def get_screener_for_exchange(exchange: str) -> str:
|
|
88
|
+
"""
|
|
89
|
+
Get the screener market for an exchange.
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
exchange: Exchange name (e.g., 'binance', 'nasdaq')
|
|
93
|
+
|
|
94
|
+
Returns:
|
|
95
|
+
Screener market (e.g., 'crypto', 'america')
|
|
96
|
+
"""
|
|
97
|
+
return EXCHANGE_SCREENER.get(exchange.lower(), "america")
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def format_technical_rating(rating: float) -> str:
|
|
101
|
+
"""
|
|
102
|
+
Convert numeric technical rating to human-readable format.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
rating: Rating value (-1 to 1)
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
Rating label (Strong Buy, Buy, Neutral, Sell, Strong Sell)
|
|
109
|
+
"""
|
|
110
|
+
if rating >= 0.5:
|
|
111
|
+
return "Strong Buy"
|
|
112
|
+
elif rating >= 0.1:
|
|
113
|
+
return "Buy"
|
|
114
|
+
elif rating >= -0.1:
|
|
115
|
+
return "Neutral"
|
|
116
|
+
elif rating >= -0.5:
|
|
117
|
+
return "Sell"
|
|
118
|
+
else:
|
|
119
|
+
return "Strong Sell"
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def compute_percent_change(open_price: float, close_price: float) -> float:
|
|
123
|
+
"""
|
|
124
|
+
Calculate percentage change.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
open_price: Starting price
|
|
128
|
+
close_price: Ending price
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
Percentage change
|
|
132
|
+
"""
|
|
133
|
+
if not open_price or open_price == 0:
|
|
134
|
+
return 0.0
|
|
135
|
+
return ((close_price - open_price) / open_price) * 100
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def compute_bollinger_band_width(sma: float, bb_upper: float, bb_lower: float) -> Optional[float]:
|
|
139
|
+
"""
|
|
140
|
+
Calculate Bollinger Band Width (BBW).
|
|
141
|
+
|
|
142
|
+
BBW = (Upper Band - Lower Band) / SMA20
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
sma: SMA20 (middle band)
|
|
146
|
+
bb_upper: Upper Bollinger Band
|
|
147
|
+
bb_lower: Lower Bollinger Band
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
BBW value or None if calculation fails
|
|
151
|
+
"""
|
|
152
|
+
if not sma or sma == 0:
|
|
153
|
+
return None
|
|
154
|
+
try:
|
|
155
|
+
return (bb_upper - bb_lower) / sma
|
|
156
|
+
except (TypeError, ZeroDivisionError):
|
|
157
|
+
return None
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def compute_bollinger_rating(
|
|
161
|
+
close: float, bb_upper: float, bb_middle: float, bb_lower: float
|
|
162
|
+
) -> tuple[int, str]:
|
|
163
|
+
"""
|
|
164
|
+
Calculate Bollinger Band position rating and signal.
|
|
165
|
+
|
|
166
|
+
Rating scale:
|
|
167
|
+
- +3: Price above upper band (Strong overbought)
|
|
168
|
+
- +2: Price in upper half above middle (Overbought)
|
|
169
|
+
- +1: Price slightly above middle (Weak bullish)
|
|
170
|
+
- -1: Price slightly below middle (Weak bearish)
|
|
171
|
+
- -2: Price in lower half below middle (Oversold)
|
|
172
|
+
- -3: Price below lower band (Strong oversold)
|
|
173
|
+
|
|
174
|
+
Args:
|
|
175
|
+
close: Current price
|
|
176
|
+
bb_upper: Upper band
|
|
177
|
+
bb_middle: Middle band (SMA20)
|
|
178
|
+
bb_lower: Lower band
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
Tuple of (rating, signal)
|
|
182
|
+
"""
|
|
183
|
+
rating = 0
|
|
184
|
+
signal = "NEUTRAL"
|
|
185
|
+
|
|
186
|
+
if close > bb_upper:
|
|
187
|
+
rating = 3
|
|
188
|
+
signal = "STRONG_OVERBOUGHT"
|
|
189
|
+
elif close > bb_middle + ((bb_upper - bb_middle) / 2):
|
|
190
|
+
rating = 2
|
|
191
|
+
signal = "BUY"
|
|
192
|
+
elif close > bb_middle:
|
|
193
|
+
rating = 1
|
|
194
|
+
signal = "WEAK_BUY"
|
|
195
|
+
elif close < bb_lower:
|
|
196
|
+
rating = -3
|
|
197
|
+
signal = "STRONG_OVERSOLD"
|
|
198
|
+
elif close < bb_middle - ((bb_middle - bb_lower) / 2):
|
|
199
|
+
rating = -2
|
|
200
|
+
signal = "SELL"
|
|
201
|
+
elif close < bb_middle:
|
|
202
|
+
rating = -1
|
|
203
|
+
signal = "WEAK_SELL"
|
|
204
|
+
|
|
205
|
+
return rating, signal
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def compute_rsi_signal(rsi: float) -> str:
|
|
209
|
+
"""
|
|
210
|
+
Determine RSI signal.
|
|
211
|
+
|
|
212
|
+
Args:
|
|
213
|
+
rsi: RSI value (0-100)
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
Signal string
|
|
217
|
+
"""
|
|
218
|
+
if rsi >= 80:
|
|
219
|
+
return "EXTREMELY_OVERBOUGHT"
|
|
220
|
+
elif rsi >= 70:
|
|
221
|
+
return "OVERBOUGHT"
|
|
222
|
+
elif rsi >= 60:
|
|
223
|
+
return "BULLISH"
|
|
224
|
+
elif rsi <= 20:
|
|
225
|
+
return "EXTREMELY_OVERSOLD"
|
|
226
|
+
elif rsi <= 30:
|
|
227
|
+
return "OVERSOLD"
|
|
228
|
+
elif rsi <= 40:
|
|
229
|
+
return "BEARISH"
|
|
230
|
+
else:
|
|
231
|
+
return "NEUTRAL"
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
def compute_macd_signal(macd: float, signal: float) -> str:
|
|
235
|
+
"""
|
|
236
|
+
Determine MACD signal.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
macd: MACD line value
|
|
240
|
+
signal: Signal line value
|
|
241
|
+
|
|
242
|
+
Returns:
|
|
243
|
+
Signal string
|
|
244
|
+
"""
|
|
245
|
+
diff = macd - signal
|
|
246
|
+
if diff > 0:
|
|
247
|
+
if macd > 0:
|
|
248
|
+
return "STRONG_BULLISH"
|
|
249
|
+
return "BULLISH"
|
|
250
|
+
elif diff < 0:
|
|
251
|
+
if macd < 0:
|
|
252
|
+
return "STRONG_BEARISH"
|
|
253
|
+
return "BEARISH"
|
|
254
|
+
return "NEUTRAL"
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def analyze_indicators(indicators: dict[str, Any]) -> dict[str, Any]:
|
|
258
|
+
"""
|
|
259
|
+
Perform comprehensive technical analysis on indicator data.
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
indicators: Dictionary of indicator values
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
Analysis results with signals and ratings
|
|
266
|
+
"""
|
|
267
|
+
result: dict[str, Any] = {"signals": [], "rating": 0, "recommendation": "NEUTRAL"}
|
|
268
|
+
|
|
269
|
+
# Extract values
|
|
270
|
+
close = indicators.get("close", 0)
|
|
271
|
+
open_price = indicators.get("open", 0)
|
|
272
|
+
high = indicators.get("high", 0)
|
|
273
|
+
low = indicators.get("low", 0)
|
|
274
|
+
volume = indicators.get("volume", 0)
|
|
275
|
+
rsi = indicators.get("RSI", 50)
|
|
276
|
+
macd = indicators.get("MACD.macd", 0)
|
|
277
|
+
macd_signal = indicators.get("MACD.signal", 0)
|
|
278
|
+
bb_upper = indicators.get("BB.upper", 0)
|
|
279
|
+
bb_lower = indicators.get("BB.lower", 0)
|
|
280
|
+
sma20 = indicators.get("SMA20", close)
|
|
281
|
+
ema50 = indicators.get("EMA50", close)
|
|
282
|
+
ema200 = indicators.get("EMA200", close)
|
|
283
|
+
adx = indicators.get("ADX", 0)
|
|
284
|
+
|
|
285
|
+
# Price change
|
|
286
|
+
if open_price and close:
|
|
287
|
+
change = compute_percent_change(open_price, close)
|
|
288
|
+
result["change_percent"] = round(change, 2)
|
|
289
|
+
|
|
290
|
+
# RSI Analysis
|
|
291
|
+
if rsi:
|
|
292
|
+
rsi_signal = compute_rsi_signal(rsi)
|
|
293
|
+
result["rsi_signal"] = rsi_signal
|
|
294
|
+
if "OVERBOUGHT" in rsi_signal:
|
|
295
|
+
result["signals"].append(f"RSI Overbought ({rsi:.1f})")
|
|
296
|
+
result["rating"] -= 1
|
|
297
|
+
elif "OVERSOLD" in rsi_signal:
|
|
298
|
+
result["signals"].append(f"RSI Oversold ({rsi:.1f})")
|
|
299
|
+
result["rating"] += 1
|
|
300
|
+
|
|
301
|
+
# MACD Analysis
|
|
302
|
+
if macd and macd_signal:
|
|
303
|
+
macd_sig = compute_macd_signal(macd, macd_signal)
|
|
304
|
+
result["macd_signal"] = macd_sig
|
|
305
|
+
if "BULLISH" in macd_sig:
|
|
306
|
+
result["signals"].append(f"MACD Bullish")
|
|
307
|
+
result["rating"] += 1
|
|
308
|
+
elif "BEARISH" in macd_sig:
|
|
309
|
+
result["signals"].append(f"MACD Bearish")
|
|
310
|
+
result["rating"] -= 1
|
|
311
|
+
|
|
312
|
+
# Bollinger Band Analysis
|
|
313
|
+
if bb_upper and bb_lower and sma20 and close:
|
|
314
|
+
bb_rating, bb_signal = compute_bollinger_rating(close, bb_upper, sma20, bb_lower)
|
|
315
|
+
bbw = compute_bollinger_band_width(sma20, bb_upper, bb_lower)
|
|
316
|
+
result["bb_rating"] = bb_rating
|
|
317
|
+
result["bb_signal"] = bb_signal
|
|
318
|
+
result["bbw"] = round(bbw, 4) if bbw else None
|
|
319
|
+
|
|
320
|
+
if bb_rating >= 2:
|
|
321
|
+
result["signals"].append("Price near/above upper BB")
|
|
322
|
+
result["rating"] -= 1
|
|
323
|
+
elif bb_rating <= -2:
|
|
324
|
+
result["signals"].append("Price near/below lower BB")
|
|
325
|
+
result["rating"] += 1
|
|
326
|
+
|
|
327
|
+
if bbw and bbw < 0.02:
|
|
328
|
+
result["signals"].append("BB Squeeze (low volatility)")
|
|
329
|
+
|
|
330
|
+
# Moving Average Analysis
|
|
331
|
+
if close and sma20 and ema50 and ema200:
|
|
332
|
+
if close > sma20 > ema50 > ema200:
|
|
333
|
+
result["signals"].append("Strong uptrend (above all MAs)")
|
|
334
|
+
result["rating"] += 2
|
|
335
|
+
elif close < sma20 < ema50 < ema200:
|
|
336
|
+
result["signals"].append("Strong downtrend (below all MAs)")
|
|
337
|
+
result["rating"] -= 2
|
|
338
|
+
elif close > ema200:
|
|
339
|
+
result["signals"].append("Above EMA200 (long-term bullish)")
|
|
340
|
+
result["rating"] += 1
|
|
341
|
+
elif close < ema200:
|
|
342
|
+
result["signals"].append("Below EMA200 (long-term bearish)")
|
|
343
|
+
result["rating"] -= 1
|
|
344
|
+
|
|
345
|
+
# ADX Trend Strength
|
|
346
|
+
if adx:
|
|
347
|
+
if adx > 50:
|
|
348
|
+
result["signals"].append(f"Very strong trend (ADX: {adx:.1f})")
|
|
349
|
+
elif adx > 25:
|
|
350
|
+
result["signals"].append(f"Trending market (ADX: {adx:.1f})")
|
|
351
|
+
else:
|
|
352
|
+
result["signals"].append(f"Ranging/weak trend (ADX: {adx:.1f})")
|
|
353
|
+
|
|
354
|
+
# Final recommendation
|
|
355
|
+
if result["rating"] >= 3:
|
|
356
|
+
result["recommendation"] = "STRONG_BUY"
|
|
357
|
+
elif result["rating"] >= 1:
|
|
358
|
+
result["recommendation"] = "BUY"
|
|
359
|
+
elif result["rating"] <= -3:
|
|
360
|
+
result["recommendation"] = "STRONG_SELL"
|
|
361
|
+
elif result["rating"] <= -1:
|
|
362
|
+
result["recommendation"] = "SELL"
|
|
363
|
+
else:
|
|
364
|
+
result["recommendation"] = "NEUTRAL"
|
|
365
|
+
|
|
366
|
+
return result
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def format_symbol(symbol: str, exchange: str) -> str:
|
|
370
|
+
"""
|
|
371
|
+
Format a symbol with exchange prefix if needed.
|
|
372
|
+
|
|
373
|
+
Args:
|
|
374
|
+
symbol: Symbol (e.g., 'BTCUSDT' or 'BINANCE:BTCUSDT')
|
|
375
|
+
exchange: Exchange name
|
|
376
|
+
|
|
377
|
+
Returns:
|
|
378
|
+
Formatted symbol (e.g., 'BINANCE:BTCUSDT')
|
|
379
|
+
"""
|
|
380
|
+
if ":" in symbol:
|
|
381
|
+
return symbol.upper()
|
|
382
|
+
return f"{exchange.upper()}:{symbol.upper()}"
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tradingview-mcp
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A comprehensive MCP server for TradingView market screening with integrated screener functionality
|
|
5
|
+
Author: TradingView MCP Team
|
|
6
|
+
License: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Keywords: crypto,mcp,screener,stocks,technical-analysis,trading,tradingview
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Office/Business :: Financial :: Investment
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Requires-Dist: httpx>=0.24.0
|
|
20
|
+
Requires-Dist: mcp>=1.0.0
|
|
21
|
+
Requires-Dist: pandas>=2.0.0
|
|
22
|
+
Requires-Dist: requests>=2.28.0
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pyright>=1.1.0; extra == 'dev'
|
|
25
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == 'dev'
|
|
26
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# TradingView MCP Server
|
|
31
|
+
|
|
32
|
+
A comprehensive Model Context Protocol (MCP) server for TradingView market screening with fully integrated screener functionality. This server provides powerful tools for cryptocurrency and stock market analysis directly through the MCP interface.
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
### Core Screener Functionality
|
|
37
|
+
- **Direct TradingView API Integration**: Query the TradingView scanner API without external dependencies
|
|
38
|
+
- **Multi-Market Support**: 76+ markets including crypto, stocks, forex, futures, and bonds
|
|
39
|
+
- **SQL-like Query Interface**: Build complex queries with filtering, sorting, and pagination
|
|
40
|
+
- **250+ Technical Indicators**: Access a comprehensive set of technical analysis columns
|
|
41
|
+
|
|
42
|
+
### MCP Tools
|
|
43
|
+
- `screen_market`: Execute custom market screening queries
|
|
44
|
+
- `get_top_gainers`: Find top gaining assets in any market
|
|
45
|
+
- `get_top_losers`: Find top losing assets in any market
|
|
46
|
+
- `get_premarket_movers`: Pre-market gainers, losers, and most active
|
|
47
|
+
- `get_postmarket_movers`: Post-market activity analysis
|
|
48
|
+
- `get_technical_analysis`: Detailed technical analysis for specific symbols
|
|
49
|
+
- `scan_bollinger_bands`: Bollinger Band squeeze detection
|
|
50
|
+
- `scan_volume_breakout`: Volume breakout detection
|
|
51
|
+
- `scan_rsi_extremes`: RSI overbought/oversold scanner
|
|
52
|
+
- `scan_macd_crossover`: MACD crossover detection
|
|
53
|
+
- `get_all_symbols`: Retrieve all symbols for a market
|
|
54
|
+
- `advanced_query`: Execute advanced queries with AND/OR logic
|
|
55
|
+
|
|
56
|
+
### MCP Resources
|
|
57
|
+
- `markets://list`: List all available markets
|
|
58
|
+
- `columns://list`: List all available technical indicator columns
|
|
59
|
+
- `exchanges://crypto`: List cryptocurrency exchanges
|
|
60
|
+
- `presets://list`: List predefined screening presets
|
|
61
|
+
|
|
62
|
+
## Installation
|
|
63
|
+
|
|
64
|
+
### Using uv (Recommended)
|
|
65
|
+
```bash
|
|
66
|
+
uv add tradingview-mcp
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Using pip
|
|
70
|
+
```bash
|
|
71
|
+
pip install tradingview-mcp
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### From Source
|
|
75
|
+
```bash
|
|
76
|
+
git clone https://github.com/your-repo/tradingview-mcp.git
|
|
77
|
+
cd tradingview-mcp
|
|
78
|
+
uv sync
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Usage
|
|
82
|
+
|
|
83
|
+
### Running the MCP Server
|
|
84
|
+
|
|
85
|
+
#### Stdio Transport (Default)
|
|
86
|
+
```bash
|
|
87
|
+
tradingview-mcp
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
#### HTTP Transport
|
|
91
|
+
```bash
|
|
92
|
+
tradingview-mcp streamable-http --host 127.0.0.1 --port 8000
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### MCP Client Configuration
|
|
96
|
+
|
|
97
|
+
Add to your MCP client configuration:
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"mcpServers": {
|
|
102
|
+
"tradingview": {
|
|
103
|
+
"command": "tradingview-mcp",
|
|
104
|
+
"args": []
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Example Queries
|
|
111
|
+
|
|
112
|
+
#### Basic Market Screening
|
|
113
|
+
```python
|
|
114
|
+
# Get top 50 stocks by trading volume
|
|
115
|
+
await client.call_tool("screen_market", {
|
|
116
|
+
"market": "america",
|
|
117
|
+
"columns": ["name", "close", "volume", "change"],
|
|
118
|
+
"sort_by": "volume",
|
|
119
|
+
"ascending": False,
|
|
120
|
+
"limit": 50
|
|
121
|
+
})
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
#### Technical Analysis Screening
|
|
125
|
+
```python
|
|
126
|
+
# Find stocks with RSI below 30 (oversold)
|
|
127
|
+
await client.call_tool("scan_rsi_extremes", {
|
|
128
|
+
"market": "america",
|
|
129
|
+
"condition": "oversold",
|
|
130
|
+
"threshold": 30,
|
|
131
|
+
"limit": 20
|
|
132
|
+
})
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
#### Cryptocurrency Screening
|
|
136
|
+
```python
|
|
137
|
+
# Get top crypto gainers
|
|
138
|
+
await client.call_tool("get_top_gainers", {
|
|
139
|
+
"market": "crypto",
|
|
140
|
+
"limit": 25
|
|
141
|
+
})
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## API Reference
|
|
145
|
+
|
|
146
|
+
### Markets
|
|
147
|
+
The following markets are supported:
|
|
148
|
+
- **Crypto**: `crypto`, `coin`
|
|
149
|
+
- **Traditional Finance**: `america`, `uk`, `germany`, `japan`, etc. (67 countries)
|
|
150
|
+
- **Other**: `forex`, `futures`, `bonds`, `cfd`, `options`
|
|
151
|
+
|
|
152
|
+
### Technical Indicators
|
|
153
|
+
Common indicators include:
|
|
154
|
+
- Price: `open`, `high`, `low`, `close`, `volume`
|
|
155
|
+
- Moving Averages: `SMA5`, `SMA10`, `SMA20`, `SMA50`, `SMA100`, `SMA200`, `EMA5`, `EMA10`, `EMA20`, `EMA50`, `EMA100`, `EMA200`
|
|
156
|
+
- Oscillators: `RSI`, `RSI7`, `MACD.macd`, `MACD.signal`, `Stoch.K`, `Stoch.D`
|
|
157
|
+
- Bollinger Bands: `BB.upper`, `BB.lower`
|
|
158
|
+
- Others: `VWAP`, `ATR`, `ADX`, `CCI20`, etc.
|
|
159
|
+
|
|
160
|
+
See `columns://list` resource for the complete list.
|
|
161
|
+
|
|
162
|
+
## Development
|
|
163
|
+
|
|
164
|
+
### Running Tests
|
|
165
|
+
```bash
|
|
166
|
+
uv run pytest tests/
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Code Formatting
|
|
170
|
+
```bash
|
|
171
|
+
uv run ruff format .
|
|
172
|
+
uv run ruff check . --fix
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Type Checking
|
|
176
|
+
```bash
|
|
177
|
+
uv run pyright
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
## License
|
|
181
|
+
|
|
182
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
tradingview_mcp/__init__.py,sha256=V7RLq22Qp1rsMhDYNlXfWkiNaXlo7s4KkNUmSvbGKIM,455
|
|
2
|
+
tradingview_mcp/column.py,sha256=MC7lWksmyaYF4SkVm97Apr8httwip-N-4aVTSyS0CQo,8871
|
|
3
|
+
tradingview_mcp/constants.py,sha256=yGzC9Zie825JqqHKGWukTz4HicGKn0pDiUn8op_Me2Y,12749
|
|
4
|
+
tradingview_mcp/models.py,sha256=CHSQ46A2ljhvzI6YP8XRItUdoDJw1yYebiBANt9xeD0,3366
|
|
5
|
+
tradingview_mcp/query.py,sha256=gkC4t-2_jtuUK3KgzU62wrIcGoaOmY--1EwAshGQb0Q,10871
|
|
6
|
+
tradingview_mcp/scanner.py,sha256=CA8GP-N8uCYacpuUzll9IfalKK0hEUSU9ViVEAO8mwU,7535
|
|
7
|
+
tradingview_mcp/server.py,sha256=xOZ0Vm_RicRVMCyq6y0DKUPpE5gUtAVrERdItmHLdUs,40516
|
|
8
|
+
tradingview_mcp/utils.py,sha256=6O89qIaZ_eYoN3m12r2q4-D8VpJajP5WuwKQbj4ZVHo,10238
|
|
9
|
+
tradingview_mcp-1.0.0.dist-info/METADATA,sha256=vfzUAYJaI5uIz1tPVq1zmjiaU1zK1nAZlhoRLDldk_o,5097
|
|
10
|
+
tradingview_mcp-1.0.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
11
|
+
tradingview_mcp-1.0.0.dist-info/entry_points.txt,sha256=GZxjGqgVbUlWDp5OzFQoCN_g1UBLyOmfVqCR5uzscnU,57
|
|
12
|
+
tradingview_mcp-1.0.0.dist-info/licenses/LICENSE,sha256=ma04jhucIafnA2IaYn--PlxmCUpqhESjKAu4d0c_Ib4,1141
|
|
13
|
+
tradingview_mcp-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Shneor Elmaleh
|
|
4
|
+
Copyright (c) 2025 Ahmet Taner Atila
|
|
5
|
+
Copyright (c) 2026 Henrik (k73a)
|
|
6
|
+
|
|
7
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
8
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
9
|
+
in the Software without restriction, including without limitation the rights
|
|
10
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
11
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
12
|
+
furnished to do so, subject to the following conditions:
|
|
13
|
+
|
|
14
|
+
The above copyright notice and this permission notice shall be included in all
|
|
15
|
+
copies or substantial portions of the Software.
|
|
16
|
+
|
|
17
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
18
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
19
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
20
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
21
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
22
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
23
|
+
SOFTWARE.
|