Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,6 @@ ENV/
env.bak/
venv.bak/
tvDatafeed/symbols.pkl
tvDatafeed/beta.py
tvDatafeed/beta.py
.opencode
implementation_plan.md
112 changes: 73 additions & 39 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,24 @@
# **NOTE**
# TvDatafeed

This is a fork of the original [TvDatafeed](https://github.com/rongardF/tvdatafeed.git) project by StreamAlpha. This fork has live data retrieving feature implemented.
More information about this will be found in the TvDatafeedLive section down below in the README.
This is an improved fork of the original [TvDatafeed](https://github.com/rongardF/tvdatafeed.git) project.

# **TvDatafeed**
Key changes in this fork:
- Windows compatibility: dates before 1970 work correctly when fetching historical data.
- Improved `nologin`: can fetch more than 5000 bars for some symbols (typically daily timeframe, e.g. `XAUUSD:OANDA`).
- Batch real-time quotes: `TvDatafeed.get_quotes()` fetches many symbols over a single Quote Session WebSocket.
- Bar-based live feed: `TvDatafeedLive` can monitor symbols and invoke callbacks when a new bar is produced.

A simple TradingView historical Data Downloader. Tvdatafeed allows downloading upto 5000 bars on any of the supported timeframe.

If you found the content useful and want to support my work, you can buy me a coffee!
[![](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/StreamAlpha)

## Installation

This module can be installed from github repo
This module can be installed from a Git repo.

```sh
pip install --upgrade --no-cache-dir git+https://github.com/rongardF/tvdatafeed.git
pip install --upgrade --no-cache-dir git+https://github.com/gezmisozkan/tvdatafeed.git
```

For usage instructions, watch these videos-

v1.2 tutorial with installation and backtrader usage

[![Watch the video](https://img.youtube.com/vi/f76dOZW2gwI/hqdefault.jpg)](https://youtu.be/f76dOZW2gwI)

Full tutorial

[![Watch the video](https://img.youtube.com/vi/qDrXmb2ZRjo/hqdefault.jpg)](https://youtu.be/qDrXmb2ZRjo)

---

## About release 2.0.0

Version 2.0.0 is a major release and is not backward compatible. make sure you update your code accordingly. Thanks to [stefanomorni](https://github.com/stefanomorni) for contributing and removing selenium dependancy.
If you are using a fork, replace the URL with your fork URL.

## Usage

Expand All @@ -57,6 +43,10 @@ tv = TvDatafeed()

when using without login, following warning will be shown `you are using nologin method, data you access may be limited`

**Note:** The nologin method now works for more than 5000 bars for some symbols (e.g., `XAUUSD:OANDA`). Try your symbol to check availability.

This extended limit is typically available for the daily timeframe. Other intervals may still be restricted.

---

## Getting Data
Expand Down Expand Up @@ -87,6 +77,44 @@ extended_price_data = tv.get_hist(symbol="EICHERMOT",exchange="NSE",interval=Int

---

## Real-time Quotes

For high-throughput real-time price checks across many assets, prefer `get_quotes()` over calling `get_hist()` in a loop.

`get_quotes()` uses the TradingView Quote Session protocol and a single WebSocket connection for the full batch.

```python
quotes = tv.get_quotes([
'BINANCE:BTCUSDT',
'NASDAQ:AAPL',
'FX:USDTRY',
])

print(quotes['NASDAQ:AAPL'])
```

Return format:

```python
{
'NASDAQ:AAPL': {
'lp': 276.49,
'lp_time': 1770253196,
'ch': 7.01,
'chp': 2.6,
'status': 'ok'
},
'INVALID:SYMBOL': {
'status': 'error',
'error': '...'
}
}
```

Fields requested: `lp`, `lp_time`, `ch`, `chp`, `status`.

---

## Search Symbol

To find the exact symbols for an instrument you can use `tv.search_symbol` method.
Expand All @@ -111,6 +139,8 @@ Indicators data is not downloaded from tradingview. For that you can use [TA-Lib

### Description

Note: for simple real-time price retrieval (many symbols), use `TvDatafeed.get_quotes()`.

**TvDatafeedLive** is a sub-class of **TvDatafeed** to extend the functionality and provide live data feed feature. The live data feed feature means that the user can specify
symbol, exchange and interval set (also called as seis) for which they want the new data bar to be retrieved from TradingView whenever it is produced. The user can then
provide any number of callback functions for that seis which will be called with the newly retrieved data bar. Callback functions and retrieving data from TradingView is
Expand Down Expand Up @@ -225,6 +255,22 @@ data=seis.get_hist(n_bars=10, timeout=-1)

---

## Performance & Benchmarks

`benchmark_realtime.py` compares:
- Method A: loop `get_hist(..., n_bars=1)` for spot prices (slow; new WS per symbol)
- Method B: single `get_quotes([...])` call (fast; single WS)

Run:

```sh
python benchmark_realtime.py
```

Typical results show a large speedup (often 10x+), depending on network conditions and symbol mix.

---

## Supported Time Intervals

Following timeframes intervals are supported-
Expand Down Expand Up @@ -259,18 +305,6 @@ Following timeframes intervals are supported-

## Read this before creating an issue

Before creating an issue in this library, please follow the following steps.

1. Search the problem you are facing is already asked by someone else. There might be some issues already there, either solved/unsolved related to your problem. Go to [issues](https://github.com/StreamAlpha/tvdatafeed/issues) page, use `is:issue` as filter and search your problem. ![image](https://user-images.githubusercontent.com/59556194/128167319-2654cfa1-f718-4a52-82f8-b0c0d26bf4ef.png)
2. If you feel your problem is not asked by anyone or no issues are related to your problem, then create a new issue.
3. Describe your problem in detail while creating the issue. If you don't have time to detail/describe the problem you are facing, assume that I also won't be having time to respond to your problem.
4. Post a sample code of the problem you are facing. If I copy paste the code directly from issue, I should be able to reproduce the problem you are facing.
5. Before posting the sample code, test your sample code yourself once. Only sample code should be tested, no other addition should be there while you are testing.
6. Have some print() function calls to display the values of some variables related to your problem.
7. Post the results of print() functions also in the issue.
8. Use the insert code feature of github to inset code and print outputs, so that the code is displyed neat. !
9. If you have multiple lines of code, use tripple grave accent ( ``` ) to insert multiple lines of code.

[Example:](https://docs.github.com/en/github/writing-on-github/creating-and-highlighting-code-blocks)

![1659809630082](image/README/1659809630082.png)
- Search existing issues first.
- Include a minimal reproducible snippet (symbol/exchange/interval, login/nologin) and the full traceback/output.
- Confirm the snippet reproduces on a clean environment (fresh venv).
73 changes: 73 additions & 0 deletions benchmark_realtime.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import time
import logging
from tvDatafeed import TvDatafeed, Interval

# Configure logging to suppress debug output during benchmark
logging.basicConfig(level=logging.INFO)

def benchmark():
tv = TvDatafeed()

# 20 diverse symbols (Indices, Stocks, Crypto, Forex)
# Using specific exchanges to ensure they work
symbols = [
"NSE:RELIANCE", "NSE:TCS", "NSE:INFY", "NSE:HDFCBANK", "NSE:ICICIBANK",
"NASDAQ:AAPL", "NASDAQ:MSFT", "NASDAQ:GOOGL", "NASDAQ:AMZN", "NASDAQ:TSLA",
"NYSE:BABA", "NYSE:NIO", "NYSE:F", "NYSE:GE", "NYSE:T",
"BINANCE:BTCUSDT", "BINANCE:ETHUSDT", "BINANCE:BNBUSDT", "BINANCE:ADAUSDT", "BINANCE:XRPUSDT"
]

print(f"Benchmarking with {len(symbols)} symbols...")

# Method A: Loop get_hist
print("\nMethod A: Loop get_hist (1 bar)...")
start_time_a = time.time()
for symbol in symbols:
try:
# parsing exchange and symbol
if ":" in symbol:
exchange, sym = symbol.split(":")
else:
exchange = "NSE" # Default
sym = symbol

# get_hist takes symbol and exchange
# We request 1 bar to be as fast as possible
tv.get_hist(symbol=sym, exchange=exchange, n_bars=1, interval=Interval.in_daily)
# print(f"Fetched {symbol}")
except Exception as e:
print(f"Failed {symbol}: {e}")
end_time_a = time.time()
duration_a = end_time_a - start_time_a
print(f"Method A took {duration_a:.2f} seconds")

# Method B: Batch get_quotes
print("\nMethod B: Batch get_quotes...")
start_time_b = time.time()
try:
quotes = tv.get_quotes(symbols, timeout=10.0) # slightly larger timeout for benchmark safety
print(f"Fetched {len(quotes)} quotes")
# Optional: print one to verify structure
if quotes:
first_key = list(quotes.keys())[0]
print(f"Sample quote for {first_key}: {quotes[first_key]}")
except AttributeError:
print("get_quotes not implemented yet")
duration_b = 9999
except Exception as e:
print(f"Method B failed: {e}")
duration_b = 9999
else:
end_time_b = time.time()
duration_b = end_time_b - start_time_b
print(f"Method B took {duration_b:.2f} seconds")

# Comparison
if duration_b < duration_a:
speedup = duration_a / duration_b
print(f"\nSpeedup: {speedup:.2f}x")
else:
print("\nNo speedup or failure.")

if __name__ == "__main__":
benchmark()
14 changes: 14 additions & 0 deletions test_exchange.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

from tvDatafeed import TvDatafeed

tv = TvDatafeed()

print("Testing find_exchange:")
symbols = ['AAPL', 'MSFT', 'BTCUSDT', 'UNKNOWNKEYWORD123', "THYAO"]

for s in symbols:
ex = tv.find_exchange(s)
print(f"Symbol: {s}, Exchange: {ex}")
13 changes: 13 additions & 0 deletions test_search.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import sys
import os
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

from tvDatafeed import TvDatafeed
tv = TvDatafeed()

# Check valid ticker
matches = tv.search_symbol(symbol='AAPL')
if matches:
print("Found:", matches[0]['symbol'])
else:
print("Ticker not found")
Loading