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:
- Add technical indicators: Integrate TA-Lib for RSI, MACD, Bollinger Bands
- Build a trading bot: Implement automated trading strategies
- Create a web dashboard: Use Flask/Django to visualize data
- Add WebSocket support: Stream real-time data with websockets
- Implement backtesting: Test strategies on historical data
Resources
- Complete Code on GitHub - Full source code
- API Documentation - Complete API reference
- Interactive Playground - Test API endpoints
- [Get Your API Key](https://rapidapi.com/hypier/api/tradingview-data1Start building
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.

