Metadata-Version: 2.4
Name: tradingview-api-python
Version: 1.0.0
Summary: Python port of TradingView real-time stock/crypto WebSocket API and Indicators scraper.
Home-page: https://github.com/0xAllan123/TradingView-API-Python
Author: Mathieu Colmon
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: websocket-client>=1.8.0
Requires-Dist: requests>=2.32.0
Dynamic: author
Dynamic: classifier
Dynamic: description
Dynamic: description-content-type
Dynamic: home-page
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary

# TradingView API Python

Get realtime market prices, quote ticks, drawing elements, backtest results, and indicator values from Tradingview in Python!

This is a 100% complete Python port of the popular Node.js library [TradingView-API](https://github.com/0xAllan123/TradingView-API). It covers all WebSocket messages, HTTP REST methods, session structures, and custom packet framing logic in Python.

---

## 🟢 Features & Mapped Coverage

Our Python library implements **100% of the features** contained in the original Node.js version, wrapped with Pythonic improvements like callback decorators:

- [x] **Real-time Chart Data**: Stream live price bar updates (OHLCV) on any timeframe.
- [x] **Technical Indicators**: Stream outputs of standard and custom community Pine Script indicators (e.g. Nadaraya-Watson).
- [x] **Strategy Backtesting**: Extract full backtest strategy reports (trades log, cumulative profit, performance metrics, Sharpe ratio).
- [x] **Quotes & Tickers**: Subscribe to ask, bid, volume, and sector/industry metrics.
- [x] **Drawings Scraper**: Retrieve drawing lines, boxes, labels, and polygons you made on your chart layout.
- [x] **Private & Invite-Only Indicators**: Read/manage invite-only indicator lists and access them.
- [x] **Timeframe Replay**: Control replay mode step-by-step or automatically.
- [x] **Lightweight & Thread-Safe**: Handles the WebSocket loop in a background daemon thread with safe automatic heartbeat ping-pong framing.

---

## 🔑 How to Get `sessionid` and `sessionid_sign` (Signature)

To access intraday charts, private indicators, or to override general API rate limits, the library needs to authenticate using your active TradingView browser session cookies: `sessionid` and `sessionid_sign` (signature).

### Why are these credentials needed?
*   **Intraday Timeframes**: Free connections are restricted to daily/weekly/monthly charts. Paid accounts require session tokens to access 1-minute, 5-minute, or 1-hour feeds.
*   **Custom/Private Indicators**: Bypasses limits and resolves invite-only Pine Scripts.
*   **Cloudflare & CAPTCHA Bypass**: Prevents connection blocks by establishing a logged-in socket session.

### Steps to retrieve cookies:
1.  Open your web browser and go to [TradingView](https://www.tradingview.com/).
2.  Log in to your account.
3.  Open Developer Tools: press **F12** (Windows) or **Cmd + Option + I** (Mac), or right-click and select **Inspect**.
4.  Navigate to the **Application** (or **Storage**) tab.
5.  On the left panel, expand **Cookies** and select `https://www.tradingview.com`.
6.  Locate the following two keys in the table and copy their values:
    *   `sessionid` (This is your `sessionid` / token value)
    *   `sessionid_sign` (This is your `signature` value)
7.  Pass them into the `Client` constructor.

> [!WARNING]
> Keep these credentials private as they allow access to your TradingView account.
> If you click **Log Out** on the TradingView website, these tokens immediately expire, and you will need to retrieve new ones. Closing the browser tab does not invalidate them.

---

## Installation

Install the package directly from PyPI:

```bash
pip install tradingview-api-python
```

Or install it from the local source directory:

```bash
pip install .
```

### Dependencies
- `requests>=2.32.0`
- `websocket-client>=1.8.0`

---

## 🚀 Scenario Code Examples

### 1. Real-time Prices (Chart Session)
Create a daily chart session and update on each new candle tick:

```python
import time
from tradingviewApiPython import Client

client = Client()  # Public connection
chart = client.Session.Chart()

chart.set_market('BINANCE:BTCEUR', {
    'timeframe': 'D',
    'range': 100
})

@chart.on_symbol_loaded
def on_loaded():
    print(f"Market \"{chart.infos['description']}\" resolved!")

@chart.on_update
def on_update(changes):
    if chart.periods:
        last_bar = chart.periods[0]
        print(f"Last candle close: {last_bar['close']} | Open: {last_bar['open']}")

time.sleep(10)
chart.delete()
client.end()
```

### 2. Fetch Exactly 100 Bars (Historical Pull & Exit)
Connects to the feed, waits until 100 historical periods are loaded, extracts them, and exits immediately. This is useful for building data downloaders:

```python
import time
from tradingviewApiPython import Client

client = Client()
chart = client.Session.Chart()

state = {'completed': False}

# Set range to 100 and symbol
chart.set_market('BINANCE:BTCUSDT', {
    'timeframe': 'D',
    'range': 100
})

@chart.on_update
def on_update(changes):
    # Wait until we have at least 100 bars loaded
    if len(chart.periods) >= 100 and not state['completed']:
        state['completed'] = True
        
        # Slice exactly the last 100 bars
        data = chart.periods[:100]
        print(f"Successfully fetched {len(data)} bars!")
        for idx, bar in enumerate(data[:3]):
            print(f"Bar {idx}: Timestamp {bar['time']} | Close: {bar['close']}")
        
        chart.delete()
        client.end()

# Bounded wait loop
timeout = 10
start_time = time.time()
while not state['completed'] and (time.time() - start_time) < timeout:
    time.sleep(0.1)
```

### 3. Extract and Align Prices + Indicators into a Pandas DataFrame
This scenario fetches price candle data and combines it with custom indicator values (e.g., Nadaraya-Watson) to build a unified Pandas DataFrame for ML/Deep Learning training features:

```python
import time
import pandas as pd
from tradingviewApiPython import Client, get_indicator

# Session credentials (optional but recommended for custom indicators)
client = Client(token="sessionid", signature="sessionid_sign")
chart = client.Session.Chart()

chart.set_market('BINANCE:ETHUSDT', {'timeframe': 'D', 'range': 100})

state = {'completed': False}

@chart.on_symbol_loaded
def loaded():
    # Load Nadaraya-Watson indicator details by public ID
    indicator = get_indicator('PUB;c2a817e7470b41c2bed3d9fe8ed1a18a', '1')
    study = chart.Study(indicator)

    @study.on_ready
    def ready():
        print("Indicator is loaded and ready!")

    @study.on_update
    def update(changes):
        # Once both candles and indicator periods are loaded
        if len(chart.periods) >= 100 and len(study.periods) >= 100 and not state['completed']:
            state['completed'] = True
            
            # Map indicator values by their timestamp
            ind_map = {p['$time']: p for p in study.periods}
            
            rows = []
            for bar in chart.periods:
                t = bar['time']
                ind_val = ind_map.get(t, {})
                
                rows.append({
                    'timestamp': pd.to_datetime(t, unit='s'),
                    'open': bar['open'],
                    'high': bar['max'],
                    'low': bar['min'],
                    'close': bar['close'],
                    'volume': bar['volume'],
                    # Map indicator plot outputs (Nadaraya-Watson upper/lower envelopes)
                    'nw_upper': ind_val.get('Plot_0'),
                    'nw_lower': ind_val.get('Plot_1')
                })
            
            df = pd.DataFrame(rows).sort_values('timestamp').reset_index(drop=True)
            print("\nAligned Pandas DataFrame:")
            print(df.tail(5))
            
            chart.delete()
            client.end()

timeout = 15
start_time = time.time()
while not state['completed'] and (time.time() - start_time) < timeout:
    time.sleep(0.1)
```

### 4. Sequential Batch Fetcher for Multiple Timeframes
Iterate through multiple symbols and timeframes sequentially to download historical price datasets:

```python
import time
import os
import json
from tradingviewApiPython import Client

symbols = ['BIST:XU100', 'NASDAQ:NDX', 'TVC:GOLD']
timeframes = ['D', '1H']
client = Client()

def fetch_symbol(symbol, timeframe):
    chart = client.Session.Chart()
    chart.set_market(symbol, {
        'timeframe': timeframe,
        'range': 200
    })
    
    state = {'saved': False}
    
    @chart.on_update
    def on_update(changes):
        if len(chart.periods) >= 200 and not state['saved']:
            state['saved'] = True
            data = chart.periods
            file_name = f"{symbol.replace(':', '_')}_{timeframe}.json"
            
            with open(file_name, 'w') as f:
                json.dump(data, f, indent=2)
            print(f"Saved {file_name} ({len(data)} periods)")
            chart.delete()

    # Block until saved or timeout (10 seconds)
    start_time = time.time()
    while not state['saved'] and (time.time() - start_time) < 10:
        time.sleep(0.1)
    if not state['saved']:
        print(f"Timeout/Error fetching {symbol} {timeframe}")
        chart.delete()

for s in symbols:
    for tf in timeframes:
        fetch_symbol(s, tf)

client.end()
```

### 5. Multi-Timeframe Technical Analysis Scanner (REST)
Fetch overall TradingView Technical Analysis recommendations (Strong Buy, Buy, Sell, etc.) across multiple periods:

```python
from tradingviewApiPython import get_ta

# Fetch recommendations for BIST100
ta_advices = get_ta('BIST:XU100')

if ta_advices:
    for timeframe, recommendations in ta_advices.items():
        print(f"\nTimeframe: {timeframe}")
        print(f" - Summary: {recommendations.get('All')}")
        print(f" - Moving Averages: {recommendations.get('MA')}")
        print(f" - Oscillators: {recommendations.get('Other')}")
```

### 6. Retrieve Private Indicators Saved in Your Account
Query and load custom indicators saved under your private TradingView account:

```python
import time
from tradingviewApiPython import Client, get_private_indicators

SESSION_ID = "your_sessionid_cookie"
SIGNATURE = "your_sessionid_sign"

client = Client(token=SESSION_ID, signature=SIGNATURE)

# Retrieve list of saved private indicators
saved_indicators = get_private_indicators(SESSION_ID, SIGNATURE)
print("Found Private Indicators:")
for ind in saved_indicators:
    print(f" - Name: {ind['name']} | ID: {ind['id']}")

if saved_indicators:
    chart = client.Session.Chart()
    chart.set_market('BINANCE:BTCUSDT', {'timeframe': 'D'})
    
    @chart.on_symbol_loaded
    def loaded():
        # Compile and load the first private indicator
        target_indicator = saved_indicators[0]['get']()
        study = chart.Study(target_indicator)
        
        @study.on_update
        def on_update(changes):
            print("Private indicator values:", study.periods[0])

    time.sleep(10)
    chart.delete()

client.end()
```

### 7. Manage Access Permissions for Invite-Only Indicators
If you publish invite-only indicators, manage who can access them using your session cookies:

```python
from datetime import datetime, timedelta
from tradingviewApiPython import PinePermManager

SESSION_ID = "your_sessionid_cookie"
SIGNATURE = "your_sessionid_sign"
PINE_SCRIPT_ID = "PUB;XXXXXXXXXXXXXXXXXXXXX"

perm_manager = PinePermManager(SESSION_ID, SIGNATURE, PINE_SCRIPT_ID)

# 1. Add username to authorized list for 30 days
expire_date = datetime.now() + timedelta(days=30)
status = perm_manager.add_user("test_trader_username", expiration=expire_date)
print("User authorized:", status)

# 2. Get list of all currently authorized users
users = perm_manager.get_users(limit=10)
for u in users:
    print(f"User: {u['username']} | Expiration: {u.get('expiration')}")

# 3. Remove user access
remove_status = perm_manager.remove_user("test_trader_username")
print("User access revoked:", remove_status)
```

### 8. Interactive Replay Mode
Fetch candle history and manually step forward bar by bar:

```python
import time
from tradingviewApiPython import Client

client = Client()
chart = client.Session.Chart()

# Enable replay starting from a timestamp (milliseconds)
chart.set_market('BINANCE:BTCUSDT', {
    'timeframe': 'D',
    'replay': 1672531200000  # Jan 1st 2023 00:00:00 UTC
})

@chart.on_replay_loaded
def replay_loaded(instance_id):
    print("Replay session loaded!")
    
    # Step forward 1 bar (returns when the websocket has completed calculations)
    chart.replay_step(1)
    print("Close after Step 1:", chart.periods[0]['close'])
    
    chart.replay_step(1)
    print("Close after Step 2:", chart.periods[0]['close'])

time.sleep(10)
chart.delete()
client.end()
```

---

## 💬 Issue & Bug Reports

If you run into console warnings or unexpected results, please open an issue in the GitHub repository. Contributions and suggestions are always welcome!
