Skip to main content
Glama
patch-ridermg48

TradingView MCP Server

bollinger_scan

Identify cryptocurrency trading opportunities by scanning for coins with low Bollinger Band Width, indicating potential volatility breakouts.

Instructions

Scan for coins with low Bollinger Band Width (squeeze detection).

Args:
    exchange: Exchange name like KUCOIN, BINANCE, BYBIT, etc.
    timeframe: One of 5m, 15m, 1h, 4h, 1D, 1W, 1M  
    bbw_threshold: Maximum BBW value to filter (default 0.04)
    limit: Number of rows to return (max 100)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
exchangeNoKUCOIN
timeframeNo4h
bbw_thresholdNo
limitNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • The primary handler function for the 'bollinger_scan' tool. Registered via @mcp.tool() decorator. Sanitizes inputs, fetches data via helper, and returns formatted list of results.
    @mcp.tool()
    def bollinger_scan(exchange: str = "KUCOIN", timeframe: str = "4h", bbw_threshold: float = 0.04, limit: int = 50) -> list[dict]:
        """Scan for coins with low Bollinger Band Width (squeeze detection).
        
        Args:
            exchange: Exchange name like KUCOIN, BINANCE, BYBIT, etc.
            timeframe: One of 5m, 15m, 1h, 4h, 1D, 1W, 1M  
            bbw_threshold: Maximum BBW value to filter (default 0.04)
            limit: Number of rows to return (max 100)
        """
        exchange = sanitize_exchange(exchange, "KUCOIN")
        timeframe = sanitize_timeframe(timeframe, "4h")
        limit = max(1, min(limit, 100))
        
        rows = _fetch_bollinger_analysis(exchange, timeframe=timeframe, bbw_filter=bbw_threshold, limit=limit)
        # Convert Row objects to dicts
        return [{
            "symbol": row["symbol"],
            "changePercent": row["changePercent"],
            "indicators": dict(row["indicators"])
        } for row in rows]
  • Core helper function that loads symbols, fetches TradingView analysis, computes metrics, applies BBW threshold filter, and returns sorted rows of results.
    def _fetch_bollinger_analysis(exchange: str, timeframe: str = "4h", limit: int = 50, bbw_filter: float = None) -> List[Row]:
        """Fetch analysis using tradingview_ta with bollinger band logic from the original screener."""
        if not TRADINGVIEW_TA_AVAILABLE:
            raise RuntimeError("tradingview_ta is missing; run `uv sync`.")
        
        # Load symbols from coinlist files
        symbols = load_symbols(exchange)
        if not symbols:
            raise RuntimeError(f"No symbols found for exchange: {exchange}")
        
        # Limit symbols for performance
        symbols = symbols[:limit * 2]  # Get more to filter later
        
        # Get screener type based on exchange
        screener = EXCHANGE_SCREENER.get(exchange, "crypto")
        
        try:
            analysis = get_multiple_analysis(screener=screener, interval=timeframe, symbols=symbols)
        except Exception as e:
            raise RuntimeError(f"Analysis failed: {str(e)}")
        
        rows: List[Row] = []
        
        for key, value in analysis.items():
            try:
                if value is None:
                    continue
                    
                indicators = value.indicators
                metrics = compute_metrics(indicators)
                
                if not metrics or metrics.get('bbw') is None:
                    continue
                
                # Apply BBW filter if specified
                if bbw_filter is not None and (metrics['bbw'] >= bbw_filter or metrics['bbw'] <= 0):
                    continue
                
                # Check if we have required indicators
                if not (indicators.get("EMA50") and indicators.get("RSI")):
                    continue
                    
                rows.append(Row(
                    symbol=key,
                    changePercent=metrics['change'],
                    indicators=IndicatorMap(
                        open=metrics.get('open'),
                        close=metrics.get('price'),
                        SMA20=indicators.get("SMA20"),
                        BB_upper=indicators.get("BB.upper"),
                        BB_lower=indicators.get("BB.lower"),
                        EMA50=indicators.get("EMA50"),
                        RSI=indicators.get("RSI"),
                        volume=indicators.get("volume"),
                    )
                ))
                    
            except (TypeError, ZeroDivisionError, KeyError):
                continue
        
        # Sort by change percentage in descending order (highest gainers first)
        rows.sort(key=lambda x: x["changePercent"], reverse=True)
        
        # Return the requested limit
        return rows[:limit]
  • Computes essential metrics for Bollinger Band analysis including price change, BBW (Bollinger Band Width), rating, and signal, crucial for filtering in bollinger_scan.
    def compute_metrics(indicators: Dict) -> Optional[Dict]:
        try:
            open_price = indicators["open"]
            close = indicators["close"]
            sma = indicators["SMA20"]
            bb_upper = indicators["BB.upper"]
            bb_lower = indicators["BB.lower"]
            bb_middle = sma
    
            change = compute_change(open_price, close)
            bbw = compute_bbw(sma, bb_upper, bb_lower)
            rating, signal = compute_bb_rating_signal(close, bb_upper, bb_middle, bb_lower)
    
            return {
                "price": round(close, 4),
                "change": round(change, 3),
                "bbw": round(bbw, 4) if bbw is not None else None,
                "rating": rating,
                "signal": signal,
            }
        except (KeyError, TypeError):
            return None
  • Input validation functions for timeframe and exchange parameters used in bollinger_scan to sanitize user inputs.
    def sanitize_timeframe(tf: str, default: str = "5m") -> str:
        if not tf:
            return default
        tfs = tf.strip()
        return tfs if tfs in ALLOWED_TIMEFRAMES else default
    
    
    def sanitize_exchange(ex: str, default: str = "kucoin") -> str:
        if not ex:
            return default
        exs = ex.strip().lower()
        return exs if exs in EXCHANGE_SCREENER else default
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It mentions scanning and filtering based on BBW threshold, but doesn't describe what the scan returns (e.g., list of coins, data format), potential rate limits, authentication needs, or whether it's a read-only operation. For a tool with no annotation coverage, this is a significant gap in transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is appropriately sized and front-loaded: the first sentence states the core purpose, followed by a clear 'Args:' section listing parameters with brief explanations. Every sentence earns its place without redundancy, making it efficient and easy to parse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (technical analysis scan with 4 parameters), no annotations, and an output schema (which reduces need to describe return values), the description is moderately complete. It covers parameter semantics well but lacks behavioral context and usage guidelines. This is adequate as a minimum viable description but has clear gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description adds meaningful context beyond the input schema, which has 0% description coverage. It explains that 'exchange' accepts names like KUCOIN, BINANCE, BYBIT; 'timeframe' includes specific intervals (5m to 1M); 'bbw_threshold' is a maximum value for filtering; and 'limit' caps rows returned. This compensates well for the schema's lack of descriptions, though it doesn't detail parameter interactions or validation rules.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: 'Scan for coins with low Bollinger Band Width (squeeze detection).' It specifies the verb ('scan'), resource ('coins'), and technical indicator ('Bollinger Band Width'), making the intent understandable. However, it doesn't explicitly differentiate this squeeze detection tool from sibling tools like 'advanced_candle_pattern' or 'volume_breakout_scanner', which prevents a perfect score.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention sibling tools or contexts where this scan is preferred over other analysis tools (e.g., 'coin_analysis' or 'rating_filter'), nor does it specify prerequisites or exclusions. This leaves the agent without usage context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/patch-ridermg48/tradingview-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server