Back to Blog
Python Stock Market API Integration: Complete Guide with TradingView

Python Stock Market API Integration: Complete Guide with TradingView

Python Stock Market API Integration: Complete Guide with TradingView

Executive Summary

Last Updated: March 13, 2026

This comprehensive guide teaches Python developers how to integrate TradingView Data API for professional stock market data access. Build production-ready applications with real-time quotes, historical OHLCV data, and portfolio tracking.

Key Statistics:

  • Setup time: <5 minutes (3 pip install commands)
  • Code provided: 400+ lines of production-ready Python
  • API coverage: 160,000+ instruments, 353+ exchanges, 8 asset types
  • Performance: <50ms WebSocket latency, 1-5s REST API updates
  • Cost: Free tier 500 requests/month, paid plans from $9.99/month
  • Python version: 3.8+ required

What you’ll build: Complete Python library with TradingViewClient class, custom exceptions, rate limiting, retry logic, caching, async support, and 3 real-world examples (basic quotes, historical analysis, portfolio tracker).

Python has become the go-to language for financial data analysis, algorithmic trading, and market research. Its rich ecosystem of libraries like pandas, numpy, and matplotlib makes it perfect for working with stock market data.

In this comprehensive guide, you’ll learn how to integrate the TradingView Data API with Python to build production-ready applications that fetch, analyze, and visualize real-time and historical stock market data.

What you’ll build: A complete Python library for fetching stock quotes, historical data, and company fundamentals, with proper error handling, caching, and rate limit management.

Why Python for Stock Market APIs?

Python dominates the financial technology space for several compelling reasons:

1. Rich Data Science Ecosystem

  • pandas: DataFrames for time-series analysis
  • numpy: Fast numerical computations
  • matplotlib/plotly: Professional data visualization
  • scikit-learn: Machine learning for predictions

2. Simple, Readable Syntax Python’s clean syntax lets you focus on financial logic rather than language complexity:

# Fetch and analyze in just a few lines
quotes = api.get_quotes(["AAPL", "MSFT", "GOOGL"])
avg_price = quotes['price'].mean()

3. Extensive Financial Libraries

  • TA-Lib: Technical analysis indicators
  • Backtrader: Backtesting trading strategies
  • Zipline: Algorithmic trading library
  • yfinance: Yahoo Finance data (complementary to TradingView)

4. Rapid Prototyping Test trading ideas quickly with Jupyter notebooks before deploying to production.

Prerequisites

Before starting, ensure you have:

# Python 3.8 or higher
python --version

# Install required packages
pip install requests pandas python-dotenv

Get your API key: Sign up at [RapidAPI TradingView Data API](https://rapidapi.com/hypier/api/tradingview-data1d copy your API key.

Project Setup

Let’s create a well-structured Python project:

# Create project directory
mkdir tradingview-python
cd tradingview-python

# Create virtual environment
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install dependencies
pip install requests pandas python-dotenv

# Create project structure
mkdir tradingview_api
touch tradingview_api/__init__.py
touch tradingview_api/client.py
touch tradingview_api/exceptions.py
touch .env

Project structure:

tradingview-python/
├── venv/
├── tradingview_api/
│   ├── __init__.py
│   ├── client.py
│   └── exceptions.py
├── .env
├── examples/
│   ├── basic_quotes.py
│   ├── historical_data.py
│   └── portfolio_tracker.py
└── requirements.txt

Building the API Client

Step 1: Environment Configuration

Create a .env file to store your API key securely:

# .env
RAPIDAPI_KEY=your_api_key_here

Important: Add .env to your .gitignore to prevent committing secrets:

echo ".env" >> .gitignore

Step 2: Custom Exceptions

Create tradingview_api/exceptions.py:

"""Custom exceptions for TradingView API client."""

class TradingViewAPIError(Exception):
    """Base exception for TradingView API errors."""
    pass

class AuthenticationError(TradingViewAPIError):
    """Raised when API key is invalid or missing."""
    pass

class RateLimitError(TradingViewAPIError):
    """Raised when rate limit is exceeded."""
    def __init__(self, retry_after=None):
        self.retry_after = retry_after
        message = f"Rate limit exceeded. Retry after {retry_after} seconds." if retry_after else "Rate limit exceeded."
        super().__init__(message)

class SymbolNotFoundError(TradingViewAPIError):
    """Raised when requested symbol doesn't exist."""
    pass

class APIConnectionError(TradingViewAPIError):
    """Raised when connection to API fails."""
    pass

Step 3: Core API Client

Create tradingview_api/client.py:

"""TradingView Data API client for Python."""

import os
import time
import requests
from typing import List, Dict, Optional, Union
from datetime import datetime, timedelta
import pandas as pd
from dotenv import load_dotenv

from .exceptions import (
    TradingViewAPIError,
    AuthenticationError,
    RateLimitError,
    SymbolNotFoundError,
    APIConnectionError
)

# Load environment variables
load_dotenv()

class TradingViewClient:
    """Client for interacting with TradingView Data API."""

    BASE_URL = "https://tradingview-data1.p.rapidapi.com/api"

    def __init__(self, api_key: Optional[str] = None):
        """
        Initialize TradingView API client.

        Args:
            api_key: RapidAPI key. If not provided, reads from RAPIDAPI_KEY env variable.

        Raises:
            AuthenticationError: If API key is not provided or found.
        """
        self.api_key = api_key or os.getenv("RAPIDAPI_KEY")
        if not self.api_key:
            raise AuthenticationError(
                "API key not found. Provide api_key parameter or set RAPIDAPI_KEY environment variable."
            )

        self.headers = {
            "X-RapidAPI-Key": self.api_key,
            "X-RapidAPI-Host": "tradingview-data1.p.rapidapi.com"
        }
        self.session = requests.Session()
        self.session.headers.update(self.headers)

        # Rate limiting
        self._last_request_time = 0
        self._min_request_interval = 0.1  # 100ms between requests

    def _wait_for_rate_limit(self):
        """Ensure minimum time between requests."""
        elapsed = time.time() - self._last_request_time
        if elapsed < self._min_request_interval:
            time.sleep(self._min_request_interval - elapsed)
        self._last_request_time = time.time()

    def _make_request(self, endpoint: str, params: Optional[Dict] = None, max_retries: int = 3) -> Dict:
        """
        Make HTTP request with error handling and retries.

        Args:
            endpoint: API endpoint path
            params: Query parameters
            max_retries: Maximum number of retry attempts

        Returns:
            JSON response as dictionary

        Raises:
            Various TradingViewAPIError subclasses
        """
        url = f"{self.BASE_URL}/{endpoint}"

        for attempt in range(max_retries):
            try:
                self._wait_for_rate_limit()
                response = self.session.get(url, params=params, timeout=10)

                # Handle different status codes
                if response.status_code == 200:
                    return response.json()
                elif response.status_code == 401:
                    raise AuthenticationError("Invalid API key")
                elif response.status_code == 404:
                    raise SymbolNotFoundError(f"Symbol not found: {params}")
                elif response.status_code == 429:
                    retry_after = int(response.headers.get("Retry-After", 60))
                    if attempt < max_retries - 1:
                        time.sleep(retry_after)
                        continue
                    raise RateLimitError(retry_after)
                else:
                    response.raise_for_status()

            except requests.exceptions.Timeout:
                if attempt < max_retries - 1:
                    time.sleep(2 ** attempt)  # Exponential backoff
                    continue
                raise APIConnectionError("Request timeout")
            except requests.exceptions.ConnectionError:
                if attempt < max_retries - 1:
                    time.sleep(2 ** attempt)
                    continue
                raise APIConnectionError("Connection failed")
            except requests.exceptions.RequestException as e:
                raise TradingViewAPIError(f"Request failed: {str(e)}")

        raise TradingViewAPIError("Max retries exceeded")

    def get_quote(self, symbol: str, session: str = "regular", fields: str = "all") -> Dict:
        """
        Get real-time quote for a single symbol.

        Args:
            symbol: Symbol in format "EXCHANGE:TICKER" (e.g., "NASDAQ:AAPL")
            session: Trading session ("regular", "extended", "pre", "post")
            fields: Fields to return ("all", "basic", "extended")

        Returns:
            Dictionary with quote data

        Example:
            >>> client = TradingViewClient()
            >>> quote = client.get_quote("NASDAQ:AAPL")
            >>> print(f"Price: ${quote['price']}")
        """
        endpoint = f"quote/{symbol}"
        params = {"session": session, "fields": fields}
        return self._make_request(endpoint, params)

    def get_quotes(self, symbols: List[str], session: str = "regular") -> pd.DataFrame:
        """
        Get quotes for multiple symbols.

        Args:
            symbols: List of symbols in format "EXCHANGE:TICKER"
            session: Trading session

        Returns:
            pandas DataFrame with quote data

        Example:
            >>> symbols = ["NASDAQ:AAPL", "NYSE:MSFT", "NASDAQ:GOOGL"]
            >>> df = client.get_quotes(symbols)
            >>> print(df[['symbol', 'price', 'change_percent']])
        """
        quotes = []
        for symbol in symbols:
            try:
                quote = self.get_quote(symbol, session)
                quotes.append(quote)
            except SymbolNotFoundError:
                print(f"Warning: Symbol {symbol} not found, skipping")
                continue

        return pd.DataFrame(quotes)

    def get_history(
        self,
        symbol: str,
        interval: str = "1D",
        range: str = "1M",
        to: Optional[int] = None
    ) -> pd.DataFrame:
        """
        Get historical OHLCV data.

        Args:
            symbol: Symbol in format "EXCHANGE:TICKER"
            interval: Time interval ("1", "5", "15", "30", "60", "1D", "1W", "1M")
            range: Time range ("1D", "5D", "1M", "3M", "6M", "1Y", "5Y", "MAX")
            to: End timestamp (Unix timestamp in seconds)

        Returns:
            pandas DataFrame with OHLCV data and datetime index

        Example:
            >>> df = client.get_history("NASDAQ:AAPL", interval="1D", range="1Y")
            >>> print(df.head())
        """
        endpoint = f"history/{symbol}"
        params = {"interval": interval, "range": range}
        if to:
            params["to"] = to

        data = self._make_request(endpoint, params)

        # Convert to DataFrame
        df = pd.DataFrame(data.get("bars", []))
        if not df.empty and "time" in df.columns:
            df["datetime"] = pd.to_datetime(df["time"], unit="s")
            df.set_index("datetime", inplace=True)
            df.sort_index(inplace=True)

        return df

    def search_symbols(self, query: str, type: Optional[str] = None) -> List[Dict]:
        """
        Search for symbols by name or ticker.

        Args:
            query: Search query (company name or ticker)
            type: Filter by type ("stock", "crypto", "forex", "futures")

        Returns:
            List of matching symbols

        Example:
            >>> results = client.search_symbols("Apple")
            >>> for symbol in results[:5]:
            ...     print(f"{symbol['symbol']}: {symbol['description']}")
        """
        endpoint = "search"
        params = {"query": query}
        if type:
            params["type"] = type

        data = self._make_request(endpoint, params)
        return data.get("symbols", [])

    def get_fundamentals(self, symbol: str) -> Dict:
        """
        Get company fundamentals and financial metrics.

        Args:
            symbol: Symbol in format "EXCHANGE:TICKER"

        Returns:
            Dictionary with fundamental data

        Example:
            >>> fundamentals = client.get_fundamentals("NASDAQ:AAPL")
            >>> print(f"P/E Ratio: {fundamentals.get('pe_ratio')}")
            >>> print(f"Market Cap: ${fundamentals.get('market_cap'):,.0f}")
        """
        endpoint = f"fundamentals/{symbol}"
        return self._make_request(endpoint)

    def close(self):
        """Close the HTTP session."""
        self.session.close()

    def __enter__(self):
        """Context manager entry."""
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        """Context manager exit."""
        self.close()

Step 4: Package Initialization

Create tradingview_api/__init__.py:

"""TradingView Data API Python client."""

from .client import TradingViewClient
from .exceptions import (
    TradingViewAPIError,
    AuthenticationError,
    RateLimitError,
    SymbolNotFoundError,
    APIConnectionError
)

__version__ = "1.0.0"
__all__ = [
    "TradingViewClient",
    "TradingViewAPIError",
    "AuthenticationError",
    "RateLimitError",
    "SymbolNotFoundError",
    "APIConnectionError"
]

Real-World Examples

Example 1: Basic Stock Quotes

Create examples/basic_quotes.py:

"""Fetch and display real-time stock quotes."""

from tradingview_api import TradingViewClient

def main():
    # Initialize client (reads API key from .env)
    with TradingViewClient() as client:
        # Single quote
        quote = client.get_quote("NASDAQ:AAPL")
        print(f"\n{quote['symbol']}")
        print(f"Price: ${quote['price']:.2f}")
        print(f"Change: {quote['change']:+.2f} ({quote['change_percent']:+.2f}%)")
        print(f"Volume: {quote['volume']:,}")

        # Multiple quotes as DataFrame
        symbols = ["NASDAQ:AAPL", "NYSE:MSFT", "NASDAQ:GOOGL", "NASDAQ:TSLA"]
        df = client.get_quotes(symbols)

        print("\n" + "="*60)
        print("Portfolio Summary")
        print("="*60)
        print(df[['symbol', 'price', 'change_percent', 'volume']].to_string(index=False))

if __name__ == "__main__":
    main()

Example 2: Historical Data Analysis

Create examples/historical_data.py:

"""Analyze historical stock data with pandas."""

import matplotlib.pyplot as plt
from tradingview_api import TradingViewClient

def calculate_moving_averages(df, windows=[20, 50, 200]):
    """Calculate simple moving averages."""
    for window in windows:
        df[f'SMA_{window}'] = df['close'].rolling(window=window).mean()
    return df

def main():
    with TradingViewClient() as client:
        # Fetch 1 year of daily data
        df = client.get_history("NASDAQ:AAPL", interval="1D", range="1Y")

        # Calculate moving averages
        df = calculate_moving_averages(df)

        # Print statistics
        print("\nAAPL - 1 Year Statistics")
        print("="*50)
        print(f"Current Price: ${df['close'].iloc[-1]:.2f}")
        print(f"52-Week High: ${df['high'].max():.2f}")
        print(f"52-Week Low: ${df['low'].min():.2f}")
        print(f"Average Volume: {df['volume'].mean():,.0f}")
        print(f"YTD Return: {((df['close'].iloc[-1] / df['close'].iloc[0]) - 1) * 100:.2f}%")

        # Plot price and moving averages
        plt.figure(figsize=(12, 6))
        plt.plot(df.index, df['close'], label='Close Price', linewidth=2)
        plt.plot(df.index, df['SMA_20'], label='20-day SMA', alpha=0.7)
        plt.plot(df.index, df['SMA_50'], label='50-day SMA', alpha=0.7)
        plt.plot(df.index, df['SMA_200'], label='200-day SMA', alpha=0.7)

        plt.title('AAPL - Price and Moving Averages', fontsize=14, fontweight='bold')
        plt.xlabel('Date')
        plt.ylabel('Price ($)')
        plt.legend()
        plt.grid(True, alpha=0.3)
        plt.tight_layout()
        plt.savefig('aapl_analysis.png', dpi=300)
        print("\nChart saved as 'aapl_analysis.png'")

if __name__ == "__main__":
    main()

Example 3: Portfolio Tracker

Create examples/portfolio_tracker.py:

"""Track portfolio performance in real-time."""

import time
from datetime import datetime
from tradingview_api import TradingViewClient

class Portfolio:
    """Simple portfolio tracker."""

    def __init__(self, holdings):
        """
        Initialize portfolio.

        Args:
            holdings: Dict of {symbol: shares} pairs
        """
        self.holdings = holdings
        self.client = TradingViewClient()

    def get_value(self):
        """Calculate current portfolio value."""
        symbols = list(self.holdings.keys())
        df = self.client.get_quotes(symbols)

        total_value = 0
        positions = []

        for _, row in df.iterrows():
            symbol = row['symbol']
            shares = self.holdings[symbol]
            price = row['price']
            value = shares * price
            change_pct = row['change_percent']

            total_value += value
            positions.append({
                'symbol': symbol,
                'shares': shares,
                'price': price,
                'value': value,
                'change_pct': change_pct
            })

        return total_value, positions

    def display(self):
        """Display portfolio summary."""
        total_value, positions = self.get_value()

        print(f"\n{'='*70}")
        print(f"Portfolio Summary - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        print(f"{'='*70}")
        print(f"{'Symbol':<12} {'Shares':>8} {'Price':>10} {'Value':>12} {'Change':>10}")
        print(f"{'-'*70}")

        for pos in positions:
            print(f"{pos['symbol']:<12} {pos['shares']:>8.0f} "
                  f"${pos['price']:>9.2f} ${pos['value']:>11.2f} "
                  f"{pos['change_pct']:>9.2f}%")

        print(f"{'-'*70}")
        print(f"{'Total Portfolio Value:':<44} ${total_value:>11.2f}")
        print(f"{'='*70}\n")

    def monitor(self, interval=60):
        """Monitor portfolio with auto-refresh."""
        try:
            while True:
                self.display()
                print(f"Refreshing in {interval} seconds... (Ctrl+C to stop)")
                time.sleep(interval)
        except KeyboardInterrupt:
            print("\nMonitoring stopped.")
            self.client.close()

def main():
    # Define your portfolio
    portfolio = Portfolio({
        "NASDAQ:AAPL": 50,
        "NYSE:MSFT": 30,
        "NASDAQ:GOOGL": 20,
        "NASDAQ:TSLA": 10,
        "NYSE:JPM": 40
    })

    # Display once
    portfolio.display()

    # Or monitor continuously (uncomment to enable)
    # portfolio.monitor(interval=60)

if __name__ == "__main__":
    main()

Advanced Features

Caching for Performance

Add caching to reduce API calls:

from functools import lru_cache
from datetime import datetime, timedelta

class CachedTradingViewClient(TradingViewClient):
    """Client with built-in caching."""

    def __init__(self, *args, cache_ttl=60, **kwargs):
        super().__init__(*args, **kwargs)
        self.cache_ttl = cache_ttl
        self._cache = {}

    def _get_cached(self, key):
        """Get cached value if not expired."""
        if key in self._cache:
            value, timestamp = self._cache[key]
            if datetime.now() - timestamp < timedelta(seconds=self.cache_ttl):
                return value
        return None

    def _set_cache(self, key, value):
        """Store value in cache."""
        self._cache[key] = (value, datetime.now())

    def get_quote(self, symbol, **kwargs):
        """Get quote with caching."""
        cache_key = f"quote:{symbol}"
        cached = self._get_cached(cache_key)
        if cached:
            return cached

        quote = super().get_quote(symbol, **kwargs)
        self._set_cache(cache_key, quote)
        return quote

Async Support with aiohttp

For high-performance applications:

import aiohttp
import asyncio

class AsyncTradingViewClient:
    """Async client for concurrent requests."""

    def __init__(self, api_key):
        self.api_key = api_key
        self.base_url = "https://tradingview-data1.p.rapidapi.com/api"
        self.headers = {
            "X-RapidAPI-Key": api_key,
            "X-RapidAPI-Host": "tradingview-data1.p.rapidapi.com"
        }

    async def get_quote(self, session, symbol):
        """Fetch single quote asynchronously."""
        url = f"{self.base_url}/quote/{symbol}"
        params = {"session": "regular", "fields": "all"}

        async with session.get(url, headers=self.headers, params=params) as response:
            return await response.json()

    async def get_quotes(self, symbols):
        """Fetch multiple quotes concurrently."""
        async with aiohttp.ClientSession() as session:
            tasks = [self.get_quote(session, symbol) for symbol in symbols]
            return await asyncio.gather(*tasks)

# Usage
async def main():
    client = AsyncTradingViewClient(api_key="your-key")
    symbols = ["NASDAQ:AAPL", "NYSE:MSFT", "NASDAQ:GOOGL"]
    quotes = await client.get_quotes(symbols)
    for quote in quotes:
        print(f"{quote['symbol']}: ${quote['price']}")

# asyncio.run(main())

Best Practices

1. Error Handling

Always handle exceptions gracefully:

from tradingview_api import TradingViewClient, RateLimitError, SymbolNotFoundError

try:
    client = TradingViewClient()
    quote = client.get_quote("INVALID:SYMBOL")
except SymbolNotFoundError:
    print("Symbol not found. Please check the symbol format.")
except RateLimitError as e:
    print(f"Rate limit exceeded. Retry after {e.retry_after} seconds.")
except Exception as e:
    print(f"Unexpected error: {e}")

2. Rate Limit Management

Respect API rate limits:

import time

def batch_fetch_with_delay(client, symbols, delay=0.2):
    """Fetch symbols with delay between requests."""
    results = []
    for symbol in symbols:
        results.append(client.get_quote(symbol))
        time.sleep(delay)  # 200ms delay
    return results

3. Environment Variables

Never hardcode API keys:

# ❌ Bad
client = TradingViewClient(api_key="abc123...")

# ✅ Good
client = TradingViewClient()  # Reads from .env

4. Context Managers

Use context managers for automatic cleanup:

# ✅ Automatically closes session
with TradingViewClient() as client:
    quote = client.get_quote("NASDAQ:AAPL")

Testing Your Integration

Create tests/test_client.py:

import unittest
from tradingview_api import TradingViewClient, SymbolNotFoundError

class TestTradingViewClient(unittest.TestCase):

    def setUp(self):
        self.client = TradingViewClient()

    def test_get_quote(self):
        """Test fetching a single quote."""
        quote = self.client.get_quote("NASDAQ:AAPL")
        self.assertIn("symbol", quote)
        self.assertIn("price", quote)
        self.assertIsInstance(quote["price"], (int, float))

    def test_invalid_symbol(self):
        """Test handling of invalid symbol."""
        with self.assertRaises(SymbolNotFoundError):
            self.client.get_quote("INVALID:SYMBOL")

    def test_get_history(self):
        """Test fetching historical data."""
        df = self.client.get_history("NASDAQ:AAPL", interval="1D", range="5D")
        self.assertFalse(df.empty)
        self.assertIn("close", df.columns)

    def tearDown(self):
        self.client.close()

if __name__ == "__main__":
    unittest.run()

Deployment Considerations

Requirements File

Create requirements.txt:

requests>=2.31.0
pandas>=2.0.0
python-dotenv>=1.0.0
matplotlib>=3.7.0
aiohttp>=3.9.0

Docker Support

Create Dockerfile:

FROM python:3.11-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["python", "examples/portfolio_tracker.py"]

Next Steps

You now have a production-ready Python library for TradingView API integration. Here are some ideas to extend it:

  1. Add technical indicators: Integrate TA-Lib for RSI, MACD, Bollinger Bands
  2. Build a trading bot: Implement automated trading strategies
  3. Create a web dashboard: Use Flask/Django to visualize data
  4. Add WebSocket support: Stream real-time data with websockets
  5. Implement backtesting: Test strategies on historical data

Resources

Ready to build more advanced features? Check out our WebSocket vs REST guide for real-time streaming data.

Frequently Asked Questions

Integration requires 3 steps: (1) Install dependencies with 'pip install requests pandas python-dotenv' (Python 3.8+ required); (2) Get API key from RapidAPI TradingView Data API marketplace; (3) Create TradingViewClient class with proper error handling, rate limiting, and retry logic. The client uses requests library for HTTP calls, pandas for data manipulation, and python-dotenv for secure API key management. Complete implementation includes custom exceptions (AuthenticationError, RateLimitError, SymbolNotFoundError, APIConnectionError), automatic rate limiting (100ms between requests), exponential backoff retry (max 3 attempts), and context manager support for automatic session cleanup. Example: 'with TradingViewClient() as client: quote = client.get_quote("NASDAQ:AAPL")'. Installation time: <5 minutes. Full code provided in tutorial with 400+ lines of production-ready implementation.

Essential libraries for TradingView API integration: (1) requests (v2.31.0+) - HTTP client for API calls with session management and retry logic; (2) pandas (v2.0.0+) - DataFrame manipulation for time-series analysis, OHLCV data processing, moving averages calculation; (3) python-dotenv (v1.0.0+) - secure environment variable management for API keys; (4) matplotlib (v3.7.0+) - data visualization for price charts, technical indicators, candlestick plots; Optional advanced libraries: (5) aiohttp (v3.9.0+) - async HTTP client for concurrent requests (10x faster for batch operations); (6) TA-Lib - 150+ technical indicators (RSI, MACD, Bollinger Bands); (7) numpy - numerical computations for custom indicators; (8) plotly - interactive charts. Installation: 'pip install requests pandas python-dotenv matplotlib'. Virtual environment recommended: 'python -m venv venv && source venv/bin/activate'. Total installation size: ~200MB.

Rate limit management requires 4 strategies: (1) Request throttling - implement minimum interval between requests (100ms default) using time.sleep() and timestamp tracking; (2) Exponential backoff - retry failed requests with increasing delays (2^attempt seconds) for transient errors; (3) 429 status code handling - parse 'Retry-After' header and wait specified duration before retry; (4) Request batching - group multiple symbol requests to reduce API calls. Implementation: Track '_last_request_time' and '_min_request_interval' in client class, call '_wait_for_rate_limit()' before each request. TradingView API limits: Free tier 500 requests/month, Basic $9.99/month 10,000 requests, Pro $49.99/month 100,000 requests. Best practice: Use caching (60-second TTL for quotes) to reduce redundant calls. Example: 'def _wait_for_rate_limit(self): elapsed = time.time() - self._last_request_time; if elapsed < self._min_request_interval: time.sleep(self._min_request_interval - elapsed)'. Async alternative: Use aiohttp with semaphore for concurrent request limiting.

Yes, Python supports real-time streaming via two methods: (1) WebSocket streaming - TradingView API provides WebSocket endpoint with <50ms latency for real-time price updates, quote data, and multi-symbol subscriptions. Implementation: Use 'websockets' library (async) or 'websocket-client' (sync), authenticate with JWT token from '/api/token/generate' endpoint, subscribe to symbols with JSON messages, handle heartbeat keep-alive. Example: 'async with websockets.connect("wss://ws.tradingviewapi.com/ws?token=JWT") as ws: await ws.send(json.dumps({"action": "subscribe", "symbol": "NASDAQ:AAPL"}))'. (2) REST API polling - fetch quotes every 1-5 seconds using async requests with aiohttp for minimal latency. WebSocket advantages: Lower latency (<50ms vs 1-5s), reduced API calls (persistent connection vs repeated requests), real-time updates (push vs pull). Use cases: High-frequency trading, real-time dashboards, price alerts, algorithmic trading. Performance: WebSocket handles 1000+ symbols simultaneously, REST polling limited by rate limits.

Historical data fetching uses 'get_history()' method with 3 parameters: (1) symbol - format 'EXCHANGE:TICKER' (e.g., 'NASDAQ:AAPL'); (2) interval - timeframe options: '1' (1-minute), '5' (5-minute), '15', '30', '60' (1-hour), '1D' (daily), '1W' (weekly), '1M' (monthly); (3) range - time period: '1D', '5D', '1M', '3M', '6M', '1Y', '5Y', 'MAX'. Returns pandas DataFrame with OHLCV columns (open, high, low, close, volume) and datetime index. Example: 'df = client.get_history("NASDAQ:AAPL", interval="1D", range="1Y")' fetches 252 trading days of daily data. Data processing: Calculate moving averages with 'df["SMA_20"] = df["close"].rolling(window=20).mean()', compute returns with 'df["returns"] = df["close"].pct_change()', resample timeframes with 'df.resample("W").agg({"open": "first", "high": "max", "low": "min", "close": "last", "volume": "sum"})'. Visualization: Use matplotlib for price charts, candlestick plots with mplfinance library. Maximum data: 5000 bars per request, use pagination for longer periods.

Production-ready integration requires 8 best practices: (1) Secure API key management - use python-dotenv to load from .env file, never hardcode keys, add .env to .gitignore; (2) Error handling - implement custom exceptions (AuthenticationError, RateLimitError, SymbolNotFoundError, APIConnectionError) with specific error messages and retry logic; (3) Rate limiting - respect API limits with request throttling (100ms intervals), exponential backoff (2^attempt), and 429 status code handling; (4) Context managers - use 'with TradingViewClient() as client:' for automatic session cleanup and resource management; (5) Caching - implement TTL-based caching (60s for quotes, 5min for historical data) to reduce API calls and improve performance; (6) Async operations - use aiohttp for concurrent requests when fetching multiple symbols (10x faster than sequential); (7) Data validation - verify symbol format ('EXCHANGE:TICKER'), validate response structure, handle missing fields gracefully; (8) Testing - write unit tests for API methods, mock responses for CI/CD, test error scenarios. Code structure: Separate client class, custom exceptions module, example scripts. Documentation: Type hints, docstrings, usage examples.

Portfolio tracker implementation requires 4 components: (1) Portfolio class - stores holdings as dict of {symbol: shares} pairs, initializes TradingViewClient, calculates total value and individual positions; (2) Real-time valuation - fetch current quotes with 'get_quotes(symbols)' returning pandas DataFrame, multiply shares × price for each position, sum for total portfolio value; (3) Performance metrics - calculate daily P&L with 'change_percent' field, track position weights (position_value / total_value), compute portfolio returns; (4) Display/monitoring - format output with f-strings, auto-refresh every 60 seconds with 'time.sleep(interval)', handle KeyboardInterrupt for graceful shutdown. Example: 'portfolio = Portfolio({"NASDAQ:AAPL": 50, "NYSE:MSFT": 30}); portfolio.display()' shows current value, individual positions, daily changes. Advanced features: Historical performance tracking (store daily snapshots), risk metrics (volatility, Sharpe ratio, max drawdown), alerts (price thresholds, percentage changes), export to CSV/Excel. Deployment: Run as background service with systemd, Docker container for cloud deployment, web dashboard with Flask/Django. Complete 100-line implementation provided in tutorial.