Repository: brian-the-dev/python-tradingview-ta Branch: main Commit: 4a113824cae1 Files: 24 Total size: 75.7 KB Directory structure: gitextract_93dvnwww/ ├── .gitattributes ├── .github/ │ ├── FUNDING.yml │ └── ISSUE_TEMPLATE/ │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── docs/ │ ├── Makefile │ ├── changelog.rst │ ├── conf.py │ ├── faq.rst │ ├── index.rst │ ├── make.bat │ ├── overview.rst │ └── usage.rst ├── requirements.txt ├── setup.cfg ├── setup.py ├── test.py └── tradingview_ta/ ├── __init__.py ├── main.py └── technicals.py ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ # Auto detect text files and perform LF normalization * text=auto ================================================ FILE: .github/FUNDING.yml ================================================ ko_fi: brianthedev ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.md ================================================ --- name: Bug report about: Submit a bug report title: '' labels: bug assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior. **Expected behavior** A clear and concise description of what you expected to happen. **Code/Screenshots** If applicable, attach your code or add screenshots to help explain your problem. **Version** - OS: [e.g. Ubuntu 21.04, Windows 10] - Python: [e.g. 3.8.6] - TradingView-TA: [e.g. 3.2.4] ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.md ================================================ --- name: Feature request about: Submit a feature request title: '' labels: enhancement assignees: '' --- **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] **Describe the solution you'd like** A clear and concise description of what you want to happen. ================================================ FILE: .gitignore ================================================ # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class # C extensions *.so # Distribution / packaging .Python build/ develop-eggs/ dist/ downloads/ eggs/ .eggs/ lib/ lib64/ parts/ sdist/ var/ wheels/ pip-wheel-metadata/ share/python-wheels/ *.egg-info/ .installed.cfg *.egg MANIFEST # PyInstaller # Usually these files are written by a python script from a template # before PyInstaller builds the exe, so as to inject date/other infos into it. *.manifest *.spec # Installer logs pip-log.txt pip-delete-this-directory.txt # Unit test / coverage reports htmlcov/ .tox/ .nox/ .coverage .coverage.* .cache nosetests.xml coverage.xml *.cover *.py,cover .hypothesis/ .pytest_cache/ # Translations *.mo *.pot # Django stuff: *.log local_settings.py db.sqlite3 db.sqlite3-journal # Flask stuff: instance/ .webassets-cache # Scrapy stuff: .scrapy # Sphinx documentation docs/_build/ # PyBuilder target/ # Jupyter Notebook .ipynb_checkpoints # IPython profile_default/ ipython_config.py # pyenv .python-version # pipenv # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. # However, in case of collaboration, if having platform-specific dependencies or dependencies # having no cross-platform support, pipenv may install dependencies that don't work, or not # install all needed dependencies. #Pipfile.lock # celery beat schedule file celerybeat-schedule # SageMath parsed files *.sage.py # Environments .env .venv env/ venv/ ENV/ env.bak/ venv.bak/ # Spyder project settings .spyderproject .spyproject # Rope project settings .ropeproject # mkdocs documentation /site # mypy .mypy_cache/ .dmypy.json dmypy.json # Pyre type checker .pyre/ # VSCode settings .vscode/ ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. ## Our Standards Examples of behavior that contributes to a positive environment for our community include: * Demonstrating empathy and kindness toward other people * Being respectful of differing opinions, viewpoints, and experiences * Giving and gracefully accepting constructive feedback * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience * Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: * The use of sexualized language or imagery, and sexual attention or advances of any kind * Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or email address, without their explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. ## Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at brian@brianthe.dev. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. ## Enforcement Guidelines Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: ### 1. Correction **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. ### 2. Warning **Community Impact**: A violation through a single incident or series of actions. **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. ### 3. Temporary Ban **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within the community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to python-tradingview-ta By contributing to python-tradingview-ta, you accept and agree to the Code of Conduct below. Your contribution (code) are licensed under the MIT license. Please follow this contribution guidelines before submitting a pull request. ## Pull Request Process - Fork and clone this repository to your system. - Install the requirements using `pip install -r requirements.txt`. - Edit the code/docs. - If you edit the code, run the `test.py` file. - You DON'T need to increment the version, the maintainer will change it and publish your contribution. - Create a pull request. The maintainer will decide to merge it or not. ## Contributor Covenant Code of Conduct ### Our Pledge We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. ### Our Standards Examples of behavior that contributes to a positive environment for our community include: * Demonstrating empathy and kindness toward other people * Being respectful of differing opinions, viewpoints, and experiences * Giving and gracefully accepting constructive feedback * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience * Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: * The use of sexualized language or imagery, and sexual attention or advances of any kind * Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or email address, without their explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ### Enforcement Responsibilities Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. ### Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. ### Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at brian@brianthe.dev. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. ### Enforcement Guidelines Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: #### 1. Correction **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. #### 2. Warning **Community Impact**: A violation through a single incident or series of actions. **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. #### 3. Temporary Ban **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. #### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within the community. ### Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2020 Brian Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================

Python TradingView TA by Analyzer.REST


An unofficial API wrapper for TradingView that allows you to fetch technical analysis data, now under new management.

Brought to you by Analyzer.REST, which provides Technical Analysis-as-a-Service (TAaaS) through an intuitive and affordable API. Join the waitlist!

## Important - Keep tradingview-ta up to date for new features and bug fixes: `pip install -U tradingview_ta` - Technical analysis for indices (index) is not supported by both TradingView and tradingview-ta, see issue [#67](https://github.com/analyzerrest/python-tradingview-ta/issues/67) and [#84](https://github.com/analyzerrest/python-tradingview-ta/issues/84). ## Features * Faster response (older version of tradingview-ta requires Selenium) * [Support for multiple symbols](https://python-tradingview-ta.readthedocs.io/en/latest/usage.html#retrieving-multiple-analysis) * Indicators (Only TradingView built-in, does not support Pine Script/custom indicators) ## Demo You can try tradingview-ta online without installing Python: https://tvta-demo.analyzer.rest/. ## Requirements - Python 3.6 or newer. - [Requests](https://pypi.org/project/requests/), included in installation. ## Installation [PyPI](https://pypi.org/project/tradingview-ta/) (stable, recommended): ```pip install tradingview_ta``` GitHub (latest): ```pip install git+https://github.com/analyzerrest/python-tradingview-ta.git``` ## Example ```python from tradingview_ta import TA_Handler, Interval, Exchange tesla = TA_Handler( symbol="TSLA", screener="america", exchange="NASDAQ", interval=Interval.INTERVAL_1_DAY, # proxies={'http': 'http://example.com:8080'} # Uncomment to enable proxy (replace the URL). ) print(tesla.get_analysis().summary) # Example output: {"RECOMMENDATION": "BUY", "BUY": 8, "NEUTRAL": 6, "SELL": 3} ``` Tip: Use https://tvdb.analyzer.rest/ if you don't know what symbol, screener, and exchange to use. ## Documentation [Read The Docs](https://python-tradingview-ta.readthedocs.io) ## Issue If you found a bug or have a question, please open an issue. Email will not be replied. ## Warning Trading is a risky activity, especially when done using an automated program. Never trade automatically without your supervision using results provided by tradingview-ta. Any monetary losses are not my fault. ## Contributing Pull requests (docs, bug fix, features) are welcomed! Any pull request (documentation, bug fix, features, etc) are welcomed. Please follow the [guidelines](https://github.com/analyzerrest/python-tradingview-ta/blob/main/CONTRIBUTING.md) and the [code of conduct](https://github.com/analyzerrest/python-tradingview-ta/blob/main/CODE_OF_CONDUCT.md). ## License Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: docs/Makefile ================================================ # Minimal makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build SOURCEDIR = . BUILDDIR = _build # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) ================================================ FILE: docs/changelog.rst ================================================ Changelog ========= 3.3.0 ----- New: * Symbol search 3.2.10 ------ New: * Support for proxy * Additional indicators support for ``get_multiple_analysis()`` 3.2.9 ----- New: * Interval: 30 minutes and 2 hours 3.2.8 ----- New: * Indicators: change, low, high 3.2.7 ----- Bug fix: * ``get_multiple_analysis()`` will now return ``None`` if there is no analysis for a certain symbol. See `#55 `_ for more details. 3.2.6 ----- Bug fix: * Add indicators * Get multiple analysis 3.2.5 ----- New: * Retrieve indicators ``TA_Handler.get_indicators()`` * Add custom indicators ``TA_Handler.add_indicators()`` * Indicators: volume Bug fix: * Update RSI algorithms 3.2.4 ----- New: * Retrieve multiple analysis Bug fix: * Update compute algorithms 3.2.3 ----- New: * Timeout * Indicators: BBUpper and BBLower * Test script (test.py) 3.2.2 ----- New: * Indicators: open and P.SAR 3.2.1 ----- New: * Removed EMA5 and SMA5 from analysis Bug fix: * Switched buy/sell on momentum 3.2.0 ----- New: * Instantiate ``TA_Handler`` using parameters 3.1.6 ----- New: * Set interval to ``"1d"`` if invalid 3.1.5 ----- New: * Move indicators to ``Analysis`` class 3.1.4 ----- Bug fix: * Pull request `#19 `_ 3.1.3 ----- New: * Added user agent * Added ``__version__`` attribute 3.1.1 ----- Bug fix: * Pull request `#7 `_ 3.1.0 ----- New: * Set symbol/exchange/screener/interval using functions 3.0.0 ----- New: * Use scanner (https://scanner.tradingview.com/america/scan) instead of selenium * Indicators 2.5.0 ----- New: * Support for Heroku 2.2.0 ----- New: * Rename ``pair`` to ``symbol`` * Support for Python 3.4 * Added warnings 2.1.0 ----- Bug fix: * Requirements 2.0.0 ----- New: * Use class * Use headless selenium webdriver ================================================ FILE: docs/conf.py ================================================ # -*- coding: utf-8 -*- # # Configuration file for the Sphinx documentation builder. # # This file does only contain a selection of the most common options. For a # full list see the documentation: # http://www.sphinx-doc.org/en/master/config # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # # import os # import sys # sys.path.insert(0, os.path.abspath('.')) # -- Imports ----------------------------------------------------- import sphinx import sphinx_rtd_theme from recommonmark.transform import AutoStructify # -- Project information ----------------------------------------------------- project = u'python-tradingview-ta' copyright = u'2021, deathlyface (Brian)' author = u'deathlyface (Brian)' # The short X.Y version version = u'' # The full version, including alpha/beta/rc tags release = u'' # -- General configuration --------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. # # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ 'sphinx.ext.autodoc', 'recommonmark' ] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. # You can specify multiple suffix as a list of string: # source_suffix = ['.rst', '.md'] # source_suffix = '.rst' # The master toctree document. master_doc = 'index' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. exclude_patterns = [u'_build', 'Thumbs.db', '.DS_Store'] # The name of the Pygments (syntax highlighting) style to use. pygments_style = None # -- Options for HTML output ------------------------------------------------- pygments_style = 'sphinx' html_theme = 'sphinx_rtd_theme' html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] #html_static_path = [str(Path(__file__).parent.parent / 'assets')] #html_logo = str(Path(__file__).parent.parent / 'logo.png') html_theme_options = { 'logo_only': True, 'display_version': False, 'style_external_links': False, 'style_nav_header_background': '#2c3e50', } # -- Options for HTMLHelp output --------------------------------------------- # Output file base name for HTML help builder. htmlhelp_basename = 'python-tradingview-tadoc' # -- Options for LaTeX output ------------------------------------------------ latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # # 'preamble': '', # Latex figure (float) alignment # # 'figure_align': 'htbp', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ (master_doc, 'python-tradingview-ta.tex', u'python-tradingview-ta Documentation', u'deathlyface (Brian)', 'manual'), ] # -- Options for manual page output ------------------------------------------ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ (master_doc, 'python-tradingview-ta', u'python-tradingview-ta Documentation', [author], 1) ] # -- Options for Texinfo output ---------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ (master_doc, 'python-tradingview-ta', u'python-tradingview-ta Documentation', author, 'python-tradingview-ta', 'One line description of project.', 'Miscellaneous'), ] # -- Options for Epub output ------------------------------------------------- # Bibliographic Dublin Core info. epub_title = project # The unique identifier of the text. This can be a ISBN number # or the project homepage. # # epub_identifier = '' # A unique identification for the text. # # epub_uid = '' # A list of files that should not be packed into the epub file. epub_exclude_files = ['search.html'] # -- Extension configuration ------------------------------------------------- # app setup hook def setup(app): app.add_config_value('recommonmark_config', { #'url_resolver': lambda url: github_doc_root + url, 'auto_toc_tree_section': 'Contents', 'auto_toc_maxdepth': 2, }, True) app.add_transform(AutoStructify) ================================================ FILE: docs/faq.rst ================================================ FAQ === Is the data delayed? -------------------- Yes and no. Quoted from TradingView: We provide real-time data for free whenever we're allowed. However, some data is delayed due to specific exchange regulations. Because of this, real-time data must be purchased separately using the page below. US stock market data is real-time and provided by CBOE BZX. .. note:: TradingView_TA does not support paid real-time data at the moment. .. note:: Please refer to `TradingView's website `_ to see whether the data is delayed or not. How do I get past data? ----------------------- Retrieving past data is currently not supported. How do I create a trading bot? ------------------------------ .. warning:: Trading (especially using bots) is very risky. I won't be responsible for any financial loss. You have been warned. The pseudocode below should help you get started in creating your own trading bot. .. code-block:: python3 # Import packages. from tradingview_ta import TA_Handler, Interval, Exchange import time # Store the last order. last_order = "sell" # Instantiate TA_Handler. handler = TA_Handler( symbol="SYMBOL", exchange="EXCHANGE", screener="SCREENER", interval="INTERVAL", ) # Repeat forever. while True: # Retrieve recommendation. rec = handler.get_analysis()["RECOMMENDATION"] # Create a buy order if the recommendation is "BUY" or "STRONG_BUY" and the last order is "sell". # Create a sell order if the recommendation is "SELL" or "STRONG_SELL" and the last order is "buy". if "BUY" in rec and last_order == "sell": # REPLACE COMMENT: Create a buy order using your exchange's API. last_order = "buy" elif "SELL" in rec and last_order == "buy": # REPLACE COMMENT: Create a sell order using your exchange's API. last_order = "sell" # Wait for x seconds before retrieving new analysis. # The time should be the same as the interval. time.sleep(x) .. warning:: ``last_order`` won't be saved when the program exit. When the bot restarts, it will always create a new buy order. .. tip:: Always paper trade before risking your money. How can I get involved? ----------------------- If you found a bug, please `create an issue `_ on the GitHub repository. You can contribute (new features, bug fix, typo, etc) through the `GitHub repository `_. Please follow the `guidelines `_ and don't send spammy pull requests. How does TradingView_TA works? ------------------------------ A simple network inspection on TradingView's website revealed that the data is retrieved through an `undocumented API `_. TradingView_TA works by calculating similar data using `algorithms `_ reverse-engineered from their `JavaScript code `_. Why do I get 4XX error? ----------------------- 400 error indicates that the request is invalid. Usually, this is caused when the indicators does not exist. See https://pastebin.com/1DjWv2Hd for valid indicators. 404 error indicates that the webpage does not exist. Usually, this is caused when the screener does not exist. Check if the screener, symbol, and exchange are correct using this tool: https://tvdb.brianthe.dev. ================================================ FILE: docs/index.rst ================================================ Welcome to TradingView-TA's documentation! ========================================== TradingView_TA is an unofficial Python API wrapper to retrieve technical analysis from TradingView. This documentation will help you to understand and use TradingView-TA. .. toctree:: :maxdepth: 2 overview.md usage.md changelog.rst faq.rst ================================================ FILE: docs/make.bat ================================================ @ECHO OFF pushd %~dp0 REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set SOURCEDIR=. set BUILDDIR=_build if "%1" == "" goto help %SPHINXBUILD% >NUL 2>NUL if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% goto end :help %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% :end popd ================================================ FILE: docs/overview.rst ================================================ Getting Started =============== This guide will help you understand the basics of TradingView_TA package. Requirements ------------ * Python 3.6 or newer * Internet access Installation ------------ TradingView_TA is available on `PyPI `_. .. code-block:: console pip install tradingview-ta Quick Start ----------- .. code-block:: python3 from tradingview_ta import TA_Handler, Interval, Exchange tesla = TA_Handler( symbol="TSLA", screener="america", exchange="NASDAQ", interval=Interval.INTERVAL_1_DAY ) print(tesla.get_analysis().summary) # Example output: {"RECOMMENDATION": "BUY", "BUY": 8, "NEUTRAL": 6, "SELL": 3} ================================================ FILE: docs/usage.rst ================================================ Usage ===== .. note:: Please install or update TradingView_TA to the latest version. Please read the `getting started `_ guide before continuing. .. warning:: TradingView_TA older than v3.2.0 is no longer supported. Please update using ``pip install tradingview_ta --upgrade``. Importing TradingView_TA ------------------------ .. code-block:: python3 from tradingview_ta import TA_Handler, Interval, Exchange import tradingview_ta Checking the version -------------------- Starting from version 3.1.3, you can retrieve the version of TradingView_TA through the ``__version__`` attribute. .. code-block:: python3 print(tradingview_ta.__version__) # Example output: 3.1.3 Instantiating TA_Handler ------------------------ .. code-block:: python3 handler = TA_Handler( symbol="", exchange="", screener="", interval="", timeout=None ) Parameters: .. tip:: You can search on https://tvdb.brianthe.dev to see which symbol, exchange, and screener to use. .. image:: https://raw.githubusercontent.com/brian-the-dev/python-tradingview-ta/main/images/tv-list.png * symbol (``str``) – Ticker symbol (e.g., ``"AAPL"``, ``"TLKM"``, ``"USDEUR"``, ``"BTCUSDT"``). * exchange (``str``) – Exchange (e.g., ``"nasdaq"``, ``"idx"``, ``Exchange.FOREX``, ``"binance"``). * screener (``str``) – Screener (e.g., ``"america"``, ``"indonesia"``, ``"forex"``, ``"crypto"``). .. note:: * If you're looking for stocks, enter the exchange's country as the screener. * If you're looking for cryptocurrency, enter ``"crypto"`` as the screener. * If you're looking for forex, enter ``"forex"`` as the screener. * interval (``str``) – Time frame .. note:: Please see the Interval class for available intervals. .. code-block:: python3 class Interval: INTERVAL_1_MINUTE = "1m" INTERVAL_5_MINUTES = "5m" INTERVAL_15_MINUTES = "15m" INTERVAL_30_MINUTES = "30m" INTERVAL_1_HOUR = "1h" INTERVAL_2_HOURS = "2h" INTERVAL_4_HOURS = "4h" INTERVAL_1_DAY = "1d" INTERVAL_1_WEEK = "1W" INTERVAL_1_MONTH = "1M" * timeout (``float``, optional) – How long to wait (in seconds) for the server to return a response. Retrieving the analysis ----------------------- .. code-block:: python3 analysis = handler.get_analysis() .. note:: ``analysis`` is an instance of Analysis class. It contains information such as the exchange, symbol, screener, interval, local time (datetime.datetime), etc. Attributes: * symbol (``str``) – The symbol set earlier. * exchange (``str``) – The exchange set earlier. * screener (``str``) – The screener set earlier. * interval (``str``) – The interval set earlier. * time (``datetime.datetime``) – The time when the data is retrieved. * summary (``dict``) – Technical analysis (based on both oscillators and moving averages). .. code-block:: python3 # Example {'RECOMMENDATION': 'BUY', 'BUY': 12, 'SELL': 7, 'NEUTRAL': 9} * oscillators (``dict``) – Technical analysis (based on oscillators). .. code-block:: python3 # Example {'RECOMMENDATION': 'BUY', 'BUY': 2, 'SELL': 1, 'NEUTRAL': 8, 'COMPUTE': {'RSI': 'NEUTRAL', 'STOCH.K': 'NEUTRAL', 'CCI': 'NEUTRAL', 'ADX': 'NEUTRAL', 'AO': 'NEUTRAL', 'Mom': 'BUY', 'MACD': 'SELL', 'Stoch.RSI': 'NEUTRAL', 'W%R': 'NEUTRAL', 'BBP': 'BUY', 'UO': 'NEUTRAL'}} * moving_averages (``dict``) – Technical analysis (based on moving averages). .. code-block:: python3 # Example {'RECOMMENDATION': 'BUY', 'BUY': 9, 'SELL': 5, 'NEUTRAL': 1, 'COMPUTE': {'EMA10': 'SELL', 'SMA10': 'SELL', 'EMA20': 'SELL', 'SMA20': 'SELL', 'EMA30': 'BUY', 'SMA30': 'BUY', 'EMA50': 'BUY', 'SMA50': 'BUY', 'EMA100': 'BUY', 'SMA100': 'BUY', 'EMA200': 'BUY', 'SMA200': 'BUY', 'Ichimoku': 'NEUTRAL', 'VWMA': 'SELL', 'HullMA': 'BUY'}} * indicators (``dict``) – Technical indicators. .. code-block:: python3 # Example {'Recommend.Other': 0, 'Recommend.All': 0.26666667, 'Recommend.MA': 0.53333333, 'RSI': 60.28037412, 'RSI[1]': 58.58364778, 'Stoch.K': 73.80404453, 'Stoch.D': 79.64297643, 'Stoch.K[1]': 78.88160227, 'Stoch.D[1]': 85.97647064, 'CCI20': 46.58442886, 'CCI20[1]': 34.57058796, 'ADX': 35.78754863, 'ADX+DI': 23.16948389, 'ADX-DI': 13.82449817, 'ADX+DI[1]': 24.15991909, 'ADX-DI[1]': 13.87125505, 'AO': 6675.72158824, 'AO[1]': 7283.92420588, 'Mom': 1532.6, 'Mom[1]': 108.29, 'MACD.macd': 2444.73734978, 'MACD.signal': 2606.00138275, 'Rec.Stoch.RSI': 0, 'Stoch.RSI.K': 18.53740187, 'Rec.WR': 0, 'W.R': -26.05634845, 'Rec.BBPower': 0, 'BBPower': 295.52055898, 'Rec.UO': 0, 'UO': 55.68311917, 'close': 45326.97, 'EMA5': 45600.06414333, 'SMA5': 45995.592, 'EMA10': 45223.22433151, 'SMA10': 45952.635, 'EMA20': 43451.52018338, 'SMA20': 43609.214, 'EMA30': 41908.5944052, 'SMA30': 40880.391, 'EMA50': 40352.10222373, 'SMA50': 37819.3566, 'EMA100': 40356.09177879, 'SMA100': 38009.7808, 'EMA200': 39466.50411569, 'SMA200': 45551.36135, 'Rec.Ichimoku': 0, 'Ichimoku.BLine': 40772.57, 'Rec.VWMA': 1, 'VWMA': 43471.81729377, 'Rec.HullMA9': -1, 'HullMA9': 45470.37107407, 'Pivot.M.Classic.S3': 11389.27666667, 'Pivot.M.Classic.S2': 24559.27666667, 'Pivot.M.Classic.S1': 33010.55333333, 'Pivot.M.Classic.Middle': 37729.27666667, 'Pivot.M.Classic.R1': 46180.55333333, 'Pivot.M.Classic.R2': 50899.27666667, 'Pivot.M.Classic.R3': 64069.27666667, 'Pivot.M.Fibonacci.S3': 24559.27666667, 'Pivot.M.Fibonacci.S2': 29590.21666667, 'Pivot.M.Fibonacci.S1': 32698.33666667, 'Pivot.M.Fibonacci.Middle': 37729.27666667, 'Pivot.M.Fibonacci.R1': 42760.21666667, 'Pivot.M.Fibonacci.R2': 45868.33666667, 'Pivot.M.Fibonacci.R3': 50899.27666667, 'Pivot.M.Camarilla.S3': 37840.08, 'Pivot.M.Camarilla.S2': 39047.33, 'Pivot.M.Camarilla.S1': 40254.58, 'Pivot.M.Camarilla.Middle': 37729.27666667, 'Pivot.M.Camarilla.R1': 42669.08, 'Pivot.M.Camarilla.R2': 43876.33, 'Pivot.M.Camarilla.R3': 45083.58, 'Pivot.M.Woodie.S3': 21706.84, 'Pivot.M.Woodie.S2': 25492.42, 'Pivot.M.Woodie.S1': 34876.84, 'Pivot.M.Woodie.Middle': 38662.42, 'Pivot.M.Woodie.R1': 48046.84, 'Pivot.M.Woodie.R2': 51832.42, 'Pivot.M.Woodie.R3': 61216.84, 'Pivot.M.Demark.S1': 35369.915, 'Pivot.M.Demark.Middle': 38908.9575, 'Pivot.M.Demark.R1': 48539.915, 'open': 44695.95, 'P.SAR': 48068.64, 'BB.lower': 37961.23510877, 'BB.upper': 49257.19289123, 'AO[2]': 7524.31223529, 'volume': 32744.424503, 'change': 1.44612354, 'low': 44203.28, 'high': 45560} .. tip:: Useful indicators: * Opening price: ``analysis.indicators["open"]`` * Closing price: ``analysis.indicators["close"]`` * Momentum: ``analysis.indicators["Mom"]`` * RSI: ``analysis.indicators["RSI"]`` * MACD: ``analysis.indicators["MACD.macd"]`` Retrieving multiple analysis ---------------------------- .. code-block:: python3 from tradingview_ta import * analysis = get_multiple_analysis(screener="america", interval=Interval.INTERVAL_1_HOUR, symbols=["nasdaq:tsla", "nyse:docn", "nasdaq:aapl"]) .. note:: You can't mix different screener and interval. Parameters: * symbols (``list``) – List of exchange and ticker symbol separated by a colon. Example: ["NASDAQ:TSLA", "NYSE:DOCN"] or ["BINANCE:BTCUSDT", "BITSTAMP:ETHUSD"]. * screener (``str``) – Screener (e.g., ``"america"``, ``"indonesia"``, ``"forex"``, ``"crypto"``). * timeout (``float``, optional) – How long to wait (in seconds) for the server to return a response. * additional_indicators (``list``, optional) – List of additional indicators to retrieve. Example: ``["RSI", "Mom"]``. * interval (``str``) – Time frame .. note:: Please see the Interval class for available intervals. .. code-block:: python3 class Interval: INTERVAL_1_MINUTE = "1m" INTERVAL_5_MINUTES = "5m" INTERVAL_15_MINUTES = "15m" INTERVAL_30_MINUTES = "30m" INTERVAL_1_HOUR = "1h" INTERVAL_2_HOURS = "2h" INTERVAL_4_HOURS = "4h" INTERVAL_1_DAY = "1d" INTERVAL_1_WEEK = "1W" INTERVAL_1_MONTH = "1M" .. note:: ``get_multiple_analysis()`` returns a dictionary with a format of {"EXCHANGE:SYMBOL": Analysis}. .. code-block:: python3 # Example {'NYSE:DOCN': , 'NASDAQ:TSLA': , 'NASDAQ:AAPL': } Please use UPPERCASE letters when accessing the dictionary. If there is no analysis for a certain symbol, ``Analysis`` will be replaced with a ``None``. For example, ``BINANCE:DEXEUSDT`` does not have an analysis, but ``BINANCE:BTCUSDT`` has: .. code-block:: python3 # Example {'BINANCE:DEXEUSDT': None, 'BINANCE:BTCUSDT': } Symbol search ------------- .. versionadded:: 3.3.0 Search for symbols using the TradingView symbol search API. Returns a list of symbols, exchanges, types, descriptions, and logo URLs matching the search query. .. code-block:: python3 from tradingview_ta import TradingView print(TradingView.search("tesla", "america")) # Output: [{'symbol': 'TSLA', 'exchange': 'NASDAQ', 'type': 'stock', 'description': 'Tesla, Inc.', 'logo': 'https://s3-symbol-logo.tradingview.com/tesla.svg'}, ...] .. note:: While symbols listed on https://tvdb.brianthe.dev are guaranteed to work with the "get analysis()" function, symbols returned by this function may not. Parameters: * text (``str``) – Query string. * type (``str``, optional) – Type of asset (stock, crypto, futures, index). Defaults to None (all). Proxy ----- Simply add the ``proxies`` parameter if you wish to utilize a proxy. Works with both ``TA_Handler()`` and ``get_multiple_analysis()``. It's worth noting that a bad proxy could result in TradingView rejecting your request. .. code-block:: python3 from tradingview_ta import TA_Handler, Interval, Exchange tesla = TA_Handler( symbol="TSLA", screener="america", exchange="NASDAQ", interval=Interval.INTERVAL_1_DAY, proxies={'http': 'http://0.0.0.0:8080', 'https': 'https://0.0.0.0:443'} ) print(tesla.get_analysis().summary) # Example output: {"RECOMMENDATION": "BUY", "BUY": 8, "NEUTRAL": 6, "SELL": 3} ================================================ FILE: requirements.txt ================================================ requests colorama ================================================ FILE: setup.cfg ================================================ [metadata] license_file = LICENSE ================================================ FILE: setup.py ================================================ import setuptools with open("README.md", "r") as fh: long_description = fh.read() setuptools.setup( name='tradingview_ta', version='3.3.0', description="Unofficial TradingView technical analysis API wrapper.", long_description=long_description, long_description_content_type="text/markdown", url='https://github.com/brian-the-dev/python-tradingview-ta', author='Brian', author_email='brian@brianthe.dev', packages=['tradingview_ta'], classifiers=[ "Programming Language :: Python :: 3", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", ], install_requires=[ 'requests', ], python_requires='>=3.6', project_urls={ 'Demo': 'https://tradingview.brianthe.dev', 'Documentation': 'https://python-tradingview-ta.readthedocs.io', 'Source': 'https://github.com/brian-the-dev/python-tradingview-ta', }, ) ================================================ FILE: test.py ================================================ from colorama import Fore, Style from tradingview_ta import TA_Handler, Interval, get_multiple_analysis import tradingview_ta, requests, argparse arg_parser = argparse.ArgumentParser() arg_parser.add_argument("--proxy", help="Use HTTP proxy") arg_parser.add_argument("--secureproxy", help="Use HTTPS proxy") args = arg_parser.parse_args() proxies = {} if args.proxy: proxies["http"] = args.proxy if args.secureproxy: proxies["https"] = args.secureproxy print("------------------------------------------------") print("Testing {}Tradingview-TA{} v{}{}".format(Fore.CYAN, Fore.MAGENTA, tradingview_ta.__version__, Style.RESET_ALL)) print("This test is {}semi-automatic{}. Please compare with tradingview's data manually.".format(Fore.LIGHTRED_EX, Style.RESET_ALL)) print("------------------------------------------------") COUNT = 7 success = 0 print("{}#0{} {}Testing invalid symbol{}".format(Fore.BLUE, Style.RESET_ALL, Fore.LIGHTBLUE_EX, Style.RESET_ALL)) handler = TA_Handler( symbol="ThisSymbolIsInvalid", interval="1m", screener="america", exchange="NASDAQ", proxies = proxies ) try: analysis = handler.get_analysis() if analysis: print("{}#0{} Invalid symbol test {}failed{}. No exception occured.".format(Fore.BLUE, Style.RESET_ALL, Fore.RED, Style.RESET_ALL)) except Exception as e: if str(e) == "Exchange or symbol not found.": print("{}#0{} Invalid symbol test {}success{}.".format(Fore.BLUE, Style.RESET_ALL, Fore.GREEN, Style.RESET_ALL)) success += 1 else: print("{}#0{} Invalid symbol test {}failed{}. An exception occured, but the symbol is valid.".format(Fore.BLUE, Style.RESET_ALL, Fore.RED, Style.RESET_ALL)) print("{}#1{} {}Testing invalid exchange{}".format(Fore.BLUE, Style.RESET_ALL, Fore.LIGHTBLUE_EX, Style.RESET_ALL)) handler = TA_Handler( symbol="TSLA", interval="1m", screener="america", exchange="binance", proxies = proxies ) try: analysis = handler.get_analysis() if analysis: print("{}#1{} Invalid exchange test {}failed{}. No exception occured.".format(Fore.BLUE, Style.RESET_ALL, Fore.RED, Style.RESET_ALL)) except Exception as e: if str(e) == "Exchange or symbol not found.": print("{}#1{} Invalid exchange test {}success{}.".format(Fore.BLUE, Style.RESET_ALL, Fore.GREEN, Style.RESET_ALL)) success += 1 else: print("{}#1{} Invalid exchange test {}failed{}. An exception occured, but symbol is valid.".format(Fore.BLUE, Style.RESET_ALL, Fore.RED, Style.RESET_ALL)) print("{}#2{} {}Testing timeout{}".format(Fore.BLUE, Style.RESET_ALL, Fore.LIGHTBLUE_EX, Style.RESET_ALL)) handler = TA_Handler( symbol="AAPL", interval=Interval.INTERVAL_1_DAY, screener="america", exchange="NASDAQ", timeout=0.0001, proxies = proxies ) try: analysis = handler.get_analysis() if analysis: print("{}#2{} Timeout test {}failed{}.".format(Fore.BLUE, Style.RESET_ALL, Fore.RED, Style.RESET_ALL)) except Exception as e: if type(e) == requests.exceptions.ConnectTimeout: print("{}#2{} Timeout test {}success{}.".format(Fore.BLUE, Style.RESET_ALL, Fore.GREEN, Style.RESET_ALL)) success += 1 print("{}#3{} {}Testing invalid interval{}".format(Fore.BLUE, Style.RESET_ALL, Fore.LIGHTBLUE_EX, Style.RESET_ALL)) handler = TA_Handler( symbol="TSLA", interval="1 minute", screener="america", exchange="NASDAQ", proxies = proxies ) try: analysis = handler.get_analysis() if analysis and input('{}#3{} Did you see a "defaulting to 1 day" {}warning{}? (Y/N) '.format(Fore.BLUE, Style.RESET_ALL, Fore.YELLOW, Style.RESET_ALL)).lower() == "y": print("{}#3{} Invalid interval test {}success{}.".format(Fore.BLUE, Style.RESET_ALL, Fore.GREEN, Style.RESET_ALL)) success += 1 else: print("{}#3{} Invalid interval test {}failed{}".format(Fore.BLUE, Style.RESET_ALL, Fore.RED, Style.RESET_ALL)) except Exception as e: print("{}#3{} Invalid interval test {}failed{}. An exception occured: {}".format(Fore.BLUE, Style.RESET_ALL, Fore.RED, Style.RESET_ALL, e)) print("{}#4{} {}Testing stock (NASDAQ:AAPL){}".format(Fore.BLUE, Style.RESET_ALL, Fore.LIGHTBLUE_EX, Style.RESET_ALL)) handler = TA_Handler( symbol="AAPL", interval=Interval.INTERVAL_1_DAY, screener="america", exchange="NASDAQ", proxies = proxies ) try: analysis = handler.get_analysis() print("{}#4{} Please compare with {}https://www.tradingview.com/symbols/NASDAQ-AAPL/technicals/{}.".format(Fore.BLUE, Style.RESET_ALL, Fore.LIGHTMAGENTA_EX, Style.RESET_ALL)) print("{}#4{} (Summary) Rec: {}, Sell: {}, Neutral: {}, Buy: {}".format(Fore.BLUE, Style.RESET_ALL, analysis.summary["RECOMMENDATION"], analysis.summary["SELL"], analysis.summary["NEUTRAL"], analysis.summary["BUY"])) if input("{}#4{} Are the results the same? (Y/N) ".format(Fore.BLUE, Style.RESET_ALL)).lower() == "y": print("{}#4{} Stock test {}success{}.".format(Fore.BLUE, Style.RESET_ALL, Fore.GREEN, Style.RESET_ALL)) success += 1 else: print("{}#4{} Stock test {}failed{}".format(Fore.BLUE, Style.RESET_ALL, Fore.RED, Style.RESET_ALL)) except Exception as e: print("{}#4{} Stock test {}failed{}. An exception occured: {}".format(Fore.BLUE, Style.RESET_ALL, Fore.RED, Style.RESET_ALL, e)) print("{}#5{} {}Testing multiple analysis (NASDAQ:TSLA and NYSE:DOCN){}".format(Fore.BLUE, Style.RESET_ALL, Fore.LIGHTBLUE_EX, Style.RESET_ALL)) try: analysis = get_multiple_analysis(screener="america", interval=Interval.INTERVAL_1_HOUR, symbols=["nasdaq:tsla", "nyse:docn"]) for key, value in analysis.items(): print("{}#5{} Please compare with {}https://www.tradingview.com/symbols/{}/technicals/{}. (Switch to 1 hour tab)".format(Fore.BLUE, Style.RESET_ALL, Fore.LIGHTMAGENTA_EX, key, Style.RESET_ALL)) print("{}#5{} (Summary) Rec: {}, Sell: {}, Neutral: {}, Buy: {}".format(Fore.BLUE, Style.RESET_ALL, value.summary["RECOMMENDATION"], value.summary["SELL"], value.summary["NEUTRAL"], value.summary["BUY"])) if input("{}#5{} Are the results the same? (Y/N) ".format(Fore.BLUE, Style.RESET_ALL)).lower() == "y": print("{}#5{} Multiple analysis test {}success{}.".format(Fore.BLUE, Style.RESET_ALL, Fore.GREEN, Style.RESET_ALL)) success += 1 else: print("{}#5{} Multiple analysis test {}failed{}".format(Fore.BLUE, Style.RESET_ALL, Fore.RED, Style.RESET_ALL)) except Exception as e: print("{}#5{} Multiple analysis test {}failed{}. An exception occured: {}".format(Fore.BLUE, Style.RESET_ALL, Fore.RED, Style.RESET_ALL, e)) print("{}#6{} {}Testing get indicators (BINANCE:BTCUSDT){}".format(Fore.BLUE, Style.RESET_ALL, Fore.LIGHTBLUE_EX, Style.RESET_ALL)) handler = TA_Handler( symbol="BTCUSDT", interval=Interval.INTERVAL_1_DAY, screener="crypto", exchange="binance", proxies = proxies ) try: print("{}#6{} Please compare with {}https://www.tradingview.com/symbols/BINANCE:BTCUSDT/technicals/{}. (Check for indicators)".format(Fore.BLUE, Style.RESET_ALL, Fore.LIGHTMAGENTA_EX, Style.RESET_ALL)) print("{}#6{} {}".format(Fore.BLUE, Style.RESET_ALL, handler.get_indicators())) if input("{}#6{} Are the results the same? (Y/N) ".format(Fore.BLUE, Style.RESET_ALL)).lower() == "y": print("{}#6{} Get indicators test {}success{}.".format(Fore.BLUE, Style.RESET_ALL, Fore.GREEN, Style.RESET_ALL)) success += 1 else: print("{}#6{} Get indicators test {}failed{}".format(Fore.BLUE, Style.RESET_ALL, Fore.RED, Style.RESET_ALL)) except Exception as e: print("{}#6{} Get indicators test {}failed{}. An exception occured: {}".format(Fore.BLUE, Style.RESET_ALL, Fore.RED, Style.RESET_ALL, e)) print("------------------------------------------------") print("Test finished. Result: {}{}/{}{}.".format(Fore.LIGHTWHITE_EX, success, COUNT, Style.RESET_ALL)) ================================================ FILE: tradingview_ta/__init__.py ================================================ from .main import TA_Handler, TradingView, Analysis, Interval, Exchange, get_multiple_analysis, __version__ from .technicals import Recommendation, Compute ================================================ FILE: tradingview_ta/main.py ================================================ # Tradingview Technical Analysis (tradingview-ta) # Author: deathlyface (https://github.com/deathlyface) # License: MIT import requests import json import datetime import warnings from .technicals import Compute __version__ = "3.3.0" class Analysis(object): exchange = "" symbol = "" screener = "" time = "" interval = "" summary = {} oscillators = {} moving_averages = {} indicators = {} class Interval: INTERVAL_1_MINUTE = "1m" INTERVAL_5_MINUTES = "5m" INTERVAL_15_MINUTES = "15m" INTERVAL_30_MINUTES = "30m" INTERVAL_1_HOUR = "1h" INTERVAL_2_HOURS = "2h" INTERVAL_4_HOURS = "4h" INTERVAL_1_DAY = "1d" INTERVAL_1_WEEK = "1W" INTERVAL_1_MONTH = "1M" class Exchange: FOREX = "FX_IDC" CFD = "TVC" class TradingView: # Note: Please DO NOT modify the order or DELETE existing indicators, it will break the technical analysis. You may APPEND custom indicator to the END of the list. indicators = ["Recommend.Other", "Recommend.All", "Recommend.MA", "RSI", "RSI[1]", "Stoch.K", "Stoch.D", "Stoch.K[1]", "Stoch.D[1]", "CCI20", "CCI20[1]", "ADX", "ADX+DI", "ADX-DI", "ADX+DI[1]", "ADX-DI[1]", "AO", "AO[1]", "Mom", "Mom[1]", "MACD.macd", "MACD.signal", "Rec.Stoch.RSI", "Stoch.RSI.K", "Rec.WR", "W.R", "Rec.BBPower", "BBPower", "Rec.UO", "UO", "close", "EMA5", "SMA5", "EMA10", "SMA10", "EMA20", "SMA20", "EMA30", "SMA30", "EMA50", "SMA50", "EMA100", "SMA100", "EMA200", "SMA200", "Rec.Ichimoku", "Ichimoku.BLine", "Rec.VWMA", "VWMA", "Rec.HullMA9", "HullMA9", "Pivot.M.Classic.S3", "Pivot.M.Classic.S2", "Pivot.M.Classic.S1", "Pivot.M.Classic.Middle", "Pivot.M.Classic.R1", "Pivot.M.Classic.R2", "Pivot.M.Classic.R3", "Pivot.M.Fibonacci.S3", "Pivot.M.Fibonacci.S2", "Pivot.M.Fibonacci.S1", "Pivot.M.Fibonacci.Middle", "Pivot.M.Fibonacci.R1", "Pivot.M.Fibonacci.R2", "Pivot.M.Fibonacci.R3", "Pivot.M.Camarilla.S3", "Pivot.M.Camarilla.S2", "Pivot.M.Camarilla.S1", "Pivot.M.Camarilla.Middle", "Pivot.M.Camarilla.R1", "Pivot.M.Camarilla.R2", "Pivot.M.Camarilla.R3", "Pivot.M.Woodie.S3", "Pivot.M.Woodie.S2", "Pivot.M.Woodie.S1", "Pivot.M.Woodie.Middle", "Pivot.M.Woodie.R1", "Pivot.M.Woodie.R2", "Pivot.M.Woodie.R3", "Pivot.M.Demark.S1", "Pivot.M.Demark.Middle", "Pivot.M.Demark.R1", "open", "P.SAR", "BB.lower", "BB.upper", "AO[2]", "volume", "change", "low", "high"] scan_url = "https://scanner.tradingview.com/" def data(symbols, interval, indicators): """Format TradingView's Scanner Post Data Args: symbols (list): List of EXCHANGE:SYMBOL (ex: ["NASDAQ:AAPL"] or ["BINANCE:BTCUSDT"]) interval (string): Time Interval (ex: 1m, 5m, 15m, 1h, 4h, 1d, 1W, 1M) Returns: string: JSON object as a string. """ if interval == "1m": # 1 Minute data_interval = "|1" elif interval == "5m": # 5 Minutes data_interval = "|5" elif interval == "15m": # 15 Minutes data_interval = "|15" elif interval == "30m": # 30 Minutes data_interval = "|30" elif interval == "1h": # 1 Hour data_interval = "|60" elif interval == "2h": # 2 Hours data_interval = "|120" elif interval == "4h": # 4 Hour data_interval = "|240" elif interval == "1W": # 1 Week data_interval = "|1W" elif interval == "1M": # 1 Month data_interval = "|1M" else: if interval != '1d': warnings.warn( "Interval is empty or not valid, defaulting to 1 day.") # Default, 1 Day data_interval = "" data_json = {"symbols": {"tickers": [symbol.upper() for symbol in symbols], "query": { "types": []}}, "columns": [x + data_interval for x in indicators]} return data_json def search(text, type=None): """Search for assets on TradingView. Returns the symbol, exchange, type, and description of the asset. Args: text (str, required): Query string type (str, optional): Type of asset (stock, crypto, futures, index). Defaults to None. """ req = requests.post( "https://symbol-search.tradingview.com/symbol_search", params={"text": text, "type": type}) symbols = json.loads(req.text) res = [] for symbol in symbols: if "logoid" in symbol: logo = f"https://s3-symbol-logo.tradingview.com/{symbol['logoid']}.svg" elif "base-currency-logoid" in symbol: logo = f"https://s3-symbol-logo.tradingview.com/{symbol['base-currency-logoid']}.svg" elif "country" in symbol: logo = f"https://s3-symbol-logo.tradingview.com/country/{symbol['country']}.svg" else: logo = None res.append({"symbol": symbol["symbol"], "exchange": symbol["exchange"], "type": symbol["type"], "description": symbol["description"], "logo": logo}) return res def calculate(indicators, indicators_key, screener, symbol, exchange, interval): oscillators_counter, ma_counter = {"BUY": 0, "SELL": 0, "NEUTRAL": 0}, { "BUY": 0, "SELL": 0, "NEUTRAL": 0} computed_oscillators, computed_ma = {}, {} indicators = list(indicators.values()) # RECOMMENDATIONS if None not in indicators[0:2]: recommend_oscillators = Compute.Recommend(indicators[0]) recommend_summary = Compute.Recommend(indicators[1]) recommend_moving_averages = Compute.Recommend(indicators[2]) else: return None # OSCILLATORS # RSI (14) if None not in indicators[3:5]: computed_oscillators["RSI"] = Compute.RSI(indicators[3], indicators[4]) oscillators_counter[computed_oscillators["RSI"]] += 1 # Stoch %K if None not in indicators[5:9]: computed_oscillators["STOCH.K"] = Compute.Stoch( indicators[5], indicators[6], indicators[7], indicators[8]) oscillators_counter[computed_oscillators["STOCH.K"]] += 1 # CCI (20) if None not in indicators[9:11]: computed_oscillators["CCI"] = Compute.CCI20( indicators[9], indicators[10]) oscillators_counter[computed_oscillators["CCI"]] += 1 # ADX (14) if None not in indicators[11:16]: computed_oscillators["ADX"] = Compute.ADX( indicators[11], indicators[12], indicators[13], indicators[14], indicators[15]) oscillators_counter[computed_oscillators["ADX"]] += 1 # AO if None not in indicators[16:18] and indicators[86] != None: computed_oscillators["AO"] = Compute.AO( indicators[16], indicators[17], indicators[86]) oscillators_counter[computed_oscillators["AO"]] += 1 # Mom (10) if None not in indicators[18:20]: computed_oscillators["Mom"] = Compute.Mom( indicators[18], indicators[19]) oscillators_counter[computed_oscillators["Mom"]] += 1 # MACD if None not in indicators[20:22]: computed_oscillators["MACD"] = Compute.MACD( indicators[20], indicators[21]) oscillators_counter[computed_oscillators["MACD"]] += 1 # Stoch RSI if indicators[22] != None: computed_oscillators["Stoch.RSI"] = Compute.Simple(indicators[22]) oscillators_counter[computed_oscillators["Stoch.RSI"]] += 1 # W%R if indicators[24] != None: computed_oscillators["W%R"] = Compute.Simple(indicators[24]) oscillators_counter[computed_oscillators["W%R"]] += 1 # BBP if indicators[26] != None: computed_oscillators["BBP"] = Compute.Simple(indicators[26]) oscillators_counter[computed_oscillators["BBP"]] += 1 # UO if indicators[28] != None: computed_oscillators["UO"] = Compute.Simple(indicators[28]) oscillators_counter[computed_oscillators["UO"]] += 1 # MOVING AVERAGES ma_list = ["EMA10", "SMA10", "EMA20", "SMA20", "EMA30", "SMA30", "EMA50", "SMA50", "EMA100", "SMA100", "EMA200", "SMA200"] close = indicators[30] ma_list_counter = 0 for index in range(33, 45): if indicators[index] != None: computed_ma[ma_list[ma_list_counter]] = Compute.MA( indicators[index], close) ma_counter[computed_ma[ma_list[ma_list_counter]]] += 1 ma_list_counter += 1 # MOVING AVERAGES, pt 2 # ICHIMOKU if indicators[45] != None: computed_ma["Ichimoku"] = Compute.Simple(indicators[45]) ma_counter[computed_ma["Ichimoku"]] += 1 # VWMA if indicators[47] != None: computed_ma["VWMA"] = Compute.Simple(indicators[47]) ma_counter[computed_ma["VWMA"]] += 1 # HullMA (9) if indicators[49] != None: computed_ma["HullMA"] = Compute.Simple(indicators[49]) ma_counter[computed_ma["HullMA"]] += 1 analysis = Analysis() analysis.screener = screener analysis.exchange = exchange analysis.symbol = symbol analysis.interval = interval analysis.time = datetime.datetime.now() for x in range(len(indicators)): analysis.indicators[indicators_key[x]] = indicators[x] analysis.indicators = analysis.indicators.copy() analysis.oscillators = {"RECOMMENDATION": recommend_oscillators, "BUY": oscillators_counter["BUY"], "SELL": oscillators_counter["SELL"], "NEUTRAL": oscillators_counter["NEUTRAL"], "COMPUTE": computed_oscillators} analysis.moving_averages = {"RECOMMENDATION": recommend_moving_averages, "BUY": ma_counter["BUY"], "SELL": ma_counter["SELL"], "NEUTRAL": ma_counter["NEUTRAL"], "COMPUTE": computed_ma} analysis.summary = {"RECOMMENDATION": recommend_summary, "BUY": oscillators_counter["BUY"] + ma_counter["BUY"], "SELL": oscillators_counter["SELL"] + ma_counter["SELL"], "NEUTRAL": oscillators_counter["NEUTRAL"] + ma_counter["NEUTRAL"]} return analysis class TA_Handler(object): screener = "" exchange = "" symbol = "" interval = "" timeout = None indicators = TradingView.indicators.copy() def __init__(self, screener="", exchange="", symbol="", interval="", timeout=None, proxies=None): """Create an instance of TA_Handler class Args: screener (str, required): Screener (see documentation and tradingview's site). exchange (str, required): Exchange (see documentation and tradingview's site). symbol (str, required): Abbreviation of a stock or currency (see documentation and tradingview's site). interval (str, optional): See the interval class and the documentation. Defaults to 1 day. timeout (float, optional): Timeout for requests (in seconds). Defaults to None. proxies (dict, optional): Proxies to be used for requests. Defaults to None (disabled). """ self.screener = screener self.exchange = exchange self.symbol = symbol self.interval = interval self.timeout = timeout self.proxies = proxies # Set functions def set_screener_as_stock(self, country): """Set the screener as a country (for stocks). Args: country (string): Stock's country (ex: If NFLX or AAPL, then "america" is the screener) """ self.screener = country def set_screener_as_crypto(self): """Set the screener as crypto (for cryptocurrencies). """ self.screener = "crypto" def set_screener_as_cfd(self): """Set the screener as cfd (contract for differences). """ self.screener = "cfd" def set_screener_as_forex(self): """Set the screener as forex. """ self.screener = "forex" def set_exchange_as_crypto_or_stock(self, exchange): """Set the exchange Args: exchange (string): Stock/Crypto's exchange (NASDAQ, NYSE, BINANCE, BITTREX, etc). """ self.exchange = exchange def set_exchange_as_forex(self): """Set the exchange as FX_IDC for forex. """ self.exchange = "FX_IDC" def set_exchange_as_cfd(self): """Set the exchange as TVC for cfd. """ self.exchange = "TVC" def set_interval_as(self, intvl): """Set the interval. Refer to: https://python-tradingview-ta.readthedocs.io/en/latest/usage.html#setting-the-interval Args: intvl (string): interval. You can use values from the Interval class. """ self.interval = intvl def set_symbol_as(self, symbol): """Set the symbol. Refer to: https://python-tradingview-ta.readthedocs.io/en/latest/usage.html#setting-the-symbol Args: symbol (string): abbreviation of a stock or currency (ex: NFLX, AAPL, BTCUSD). """ self.symbol = symbol def get_indicators(self, indicators=[]): """Just the indicators, please. See valid indicators on https://pastebin.com/1DjWv2Hd. Args: indicators (list, optional): List of string of indicators (ex: ["RSI7", "open"]). Defaults to self.indicators. Returns: dict: A dictionary with a format of {"indicator": value}. """ if len(indicators) == 0: indicators = self.indicators if self.screener == "" or type(self.screener) != str: raise Exception("Screener is empty or not valid.") elif self.exchange == "" or type(self.exchange) != str: raise Exception("Exchange is empty or not valid.") elif self.symbol == "" or type(self.symbol) != str: raise Exception("Symbol is empty or not valid.") exchange_symbol = f"{self.exchange}:{self.symbol}" data = TradingView.data([exchange_symbol], self.interval, indicators) scan_url = f"{TradingView.scan_url}{self.screener.lower()}/scan" headers = {"User-Agent": "tradingview_ta/{}".format(__version__)} response = requests.post( scan_url, json=data, headers=headers, timeout=self.timeout, proxies=self.proxies) # Return False if can't get data if response.status_code != 200: raise Exception("Can't access TradingView's API. HTTP status code: {}. Check for invalid symbol, exchange, or indicators.".format( response.status_code)) result = json.loads(response.text)["data"] if result != []: indicators_val = {} for x in range(len(indicators)): indicators_val[indicators[x]] = result[0]["d"][x] return indicators_val else: raise Exception("Exchange or symbol not found.") # Add custom indicators def add_indicators(self, indicators): """Add custom indicators. See valid indicators on https://pastebin.com/1DjWv2Hd. Args: indicators (list): List of strings of indicators. (ex: ["RSI7", "VWMA"]) """ self.indicators += indicators # Get analysis def get_analysis(self): """Get analysis from TradingView and compute it. Returns: Analysis: Contains information about the analysis. """ return calculate(indicators=self.get_indicators(), indicators_key=self.indicators, screener=self.screener, symbol=self.symbol, exchange=self.exchange, interval=self.interval) def get_multiple_analysis(screener, interval, symbols, additional_indicators=[], timeout=None, proxies=None): """Retrieve multiple technical analysis at once. Note: You can't mix different screener and interval Args: screener (str, required): Screener (see documentation and tradingview's site). interval (str, optional): See the interval class and the documentation. Defaults to 1 day. symbols (list, required): List of exchange and ticker symbol separated by a colon. Example: ["NASDAQ:TSLA", "NYSE:DOCN"] or ["BINANCE:BTCUSDT", "BITSTAMP:ETHUSD"]. additional_indicators (list, optional): List of additional indicators to be requested from TradingView, see valid indicators on https://pastebin.com/1DjWv2Hd. timeout (float, optional): Timeout for requests (in seconds). Defaults to None. proxies (dict, optional): Proxies to be used for requests. Defaults to None (disabled). Returns: dict: dictionary with a format of {"EXCHANGE:SYMBOL": Analysis}. """ if screener == "" or type(screener) != str: raise Exception("Screener is empty or not valid.") if len(symbols) == 0 or type(symbols) != list: raise Exception("Symbols is empty or not valid.") for symbol in symbols: if len(symbol.split(":")) != 2 or "" in symbol.split(":"): raise Exception( "One or more symbol is invalid. Symbol should be a list of exchange and ticker symbol separated by a colon. Example: [\"NASDAQ:TSLA\", \"NYSE:DOCN\"] or [\"BINANCE:BTCUSDT\", \"BITSTAMP:ETHUSD\"].") indicators_key = TradingView.indicators.copy() if additional_indicators: indicators_key += additional_indicators data = TradingView.data(symbols, interval, indicators_key) scan_url = f"{TradingView.scan_url}{screener.lower()}/scan" headers = {"User-Agent": "tradingview_ta/{}".format(__version__)} response = requests.post( scan_url, json=data, headers=headers, timeout=timeout, proxies=proxies) result = json.loads(response.text)["data"] final = {} for analysis in result: # Convert list to dict indicators = {} for x in range(len(analysis["d"])): indicators[indicators_key[x]] = analysis["d"][x] final[analysis["s"]] = calculate(indicators=indicators, indicators_key=indicators_key, screener=screener, symbol=analysis["s"].split( ":")[1], exchange=analysis["s"].split(":")[0], interval=interval) for symbol in symbols: # Add None if there is no analysis for symbol if symbol.upper() not in final: final[symbol.upper()] = None return final ================================================ FILE: tradingview_ta/technicals.py ================================================ # Tradingview Technical Analysis (tradingview-ta) # Author: deathlyface (https://github.com/deathlyface) # Rewritten from https://www.tradingview.com/static/bundles/technicals.f2e6e6a51aebb6cd46f8.js # License: MIT class Recommendation: buy = "BUY" strong_buy = "STRONG_BUY" sell = "SELL" strong_sell = "STRONG_SELL" neutral = "NEUTRAL" error = "ERROR" class Compute: def MA(ma, close): """Compute Moving Average Args: ma (float): MA value close (float): Close value Returns: string: "BUY", "SELL", or "NEUTRAL" """ if (ma < close): return Recommendation.buy elif (ma > close): return Recommendation.sell else: return Recommendation.neutral def RSI(rsi, rsi1): """Compute Relative Strength Index Args: rsi (float): RSI value rsi1 (float): RSI[1] value Returns: string: "BUY", "SELL", or "NEUTRAL" """ if (rsi < 30 and rsi1 < rsi): return Recommendation.buy elif (rsi > 70 and rsi1 > rsi): return Recommendation.sell else: return Recommendation.neutral def Stoch(k, d, k1, d1): """Compute Stochastic Args: k (float): Stoch.K value d (float): Stoch.D value k1 (float): Stoch.K[1] value d1 (float): Stoch.D[1] value Returns: string: "BUY", "SELL", or "NEUTRAL" """ if (k < 20 and d < 20 and k > d and k1 < d1): return Recommendation.buy elif (k > 80 and d > 80 and k < d and k1 > d1): return Recommendation.sell else: return Recommendation.neutral def CCI20(cci20, cci201): """Compute Commodity Channel Index 20 Args: cci20 (float): CCI20 value cci201 ([type]): CCI20[1] value Returns: string: "BUY", "SELL", or "NEUTRAL" """ if (cci20 < -100 and cci20 > cci201): return Recommendation.buy elif (cci20 > 100 and cci20 < cci201): return Recommendation.sell else: return Recommendation.neutral def ADX(adx, adxpdi, adxndi, adxpdi1, adxndi1): """Compute Average Directional Index Args: adx (float): ADX value adxpdi (float): ADX+DI value adxndi (float): ADX-DI value adxpdi1 (float): ADX+DI[1] value adxndi1 (float): ADX-DI[1] value Returns: string: "BUY", "SELL", or "NEUTRAL" """ if (adx > 20 and adxpdi1 < adxndi1 and adxpdi > adxndi): return Recommendation.buy elif (adx > 20 and adxpdi1 > adxndi1 and adxpdi < adxndi): return Recommendation.sell else: return Recommendation.neutral def AO(ao, ao1, ao2): """Compute Awesome Oscillator Args: ao (float): AO value ao1 (float): AO[1] value ao2 (float): AO[2] value Returns: string: "BUY", "SELL", or "NEUTRAL" """ if (ao > 0 and ao1 < 0) or (ao > 0 and ao1 > 0 and ao > ao1 and ao2 > ao1): return Recommendation.buy elif (ao < 0 and ao1 > 0) or (ao < 0 and ao1 < 0 and ao < ao1 and ao2 < ao1): return Recommendation.sell else: return Recommendation.neutral def Mom(mom, mom1): """Compute Momentum Args: mom (float): Mom value mom1 (float): Mom[1] value Returns: string: "BUY", "SELL", or "NEUTRAL" """ if (mom < mom1): return Recommendation.sell elif (mom > mom1): return Recommendation.buy else: return Recommendation.neutral def MACD(macd, signal): """Compute Moving Average Convergence/Divergence Args: macd (float): MACD.macd value signal (float): MACD.signal value Returns: string: "BUY", "SELL", or "NEUTRAL" """ if (macd > signal): return Recommendation.buy elif (macd < signal): return Recommendation.sell else: return Recommendation.neutral def BBBuy(close, bblower): """Compute Bull Bear Buy Args: close (float): close value bblower (float): BB.lower value Returns: string: "BUY", "SELL", or "NEUTRAL" """ if (close < bblower): return Recommendation.buy else: return Recommendation.neutral def BBSell(close, bbupper): """Compute Bull Bear Sell Args: close (float): close value bbupper (float): BB.upper value Returns: string: "BUY", "SELL", or "NEUTRAL" """ if (close > bbupper): return Recommendation.sell else: return Recommendation.neutral def PSAR(psar, open): """Compute Parabolic Stop-And-Reverse Args: psar (float): P.SAR value open (float): open value Returns: string: "BUY", "SELL", or "NEUTRAL" """ if (psar < open): return Recommendation.buy elif (psar > open): return Recommendation.sell else: return Recommendation.neutral def Recommend(value): """Compute Recommend Args: value (float): recommend value Returns: string: "STRONG_BUY", "BUY", "NEUTRAL", "SELL", "STRONG_SELL", or "ERROR" """ if value >= -1 and value < -.5: return Recommendation.strong_sell elif value >= -.5 and value < -.1: return Recommendation.sell elif value >= -.1 and value <= .1: return Recommendation.neutral elif value > .1 and value <= .5 : return Recommendation.buy elif value > .5 and value <= 1: return Recommendation.strong_buy else: return Recommendation.error def Simple(value): """Compute Simple Args: value (float): Rec.X value Returns: string: "BUY", "SELL", or "NEUTRAL" """ if (value == -1): return Recommendation.sell elif (value == 1): return Recommendation.buy else: return Recommendation.neutral