Remove pandas_ta.tar.gz from the repository
@@ -1,2 +0,0 @@
|
||||
The filename, directory name, or volume label syntax is incorrect.
|
||||
Error occurred while processing: https://files.pythonhosted.org/packages/95/6d/60b88a0334a8c6a5be114ed2c46c8f3e164127d0eccd9ff99b50773f2b20/pandas_ta-0.4.71b0.tar.gz.
|
||||
@@ -49,6 +49,9 @@ BenchmarkDotNet.Artifacts/
|
||||
|
||||
# Temporary files and agent workspace
|
||||
temp/
|
||||
temp_pandas_ta/
|
||||
temp_decompile/
|
||||
Invoke-WebRequest/
|
||||
.temp/
|
||||
*.tmp
|
||||
*.temp
|
||||
@@ -78,4 +81,15 @@ plans/
|
||||
|
||||
# SonarLint IDE plugin
|
||||
.sonarlint/
|
||||
.obsidian/
|
||||
.obsidian/
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
**/.DS_Store
|
||||
|
||||
# Python cache
|
||||
__pycache__/
|
||||
.pytest_cache/
|
||||
|
||||
# PowerShell accidents
|
||||
$null
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- development
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- development
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
if: github.actor != 'dependabot[bot]' && github.ref != 'refs/heads/master'
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
# If failure occurs on one OS, it is still relevant to see which others may work
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ["3.12"]
|
||||
os: [ubuntu-latest]
|
||||
|
||||
steps:
|
||||
- name: Github Actor Info
|
||||
run: |
|
||||
echo "Workflow triggered by github actor ${{ github.actor }}"
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Activate Cache for pip
|
||||
uses: actions/cache@v3
|
||||
id: cache-python-env
|
||||
with:
|
||||
path: ${{ env.pythonLocation }}
|
||||
key: "v3-${{ env.pythonLocation }}-${{ hashFiles('setup.py') }}"
|
||||
|
||||
- name: Update pip and friends
|
||||
run: |
|
||||
python -m pip install --upgrade pip setuptools wheel
|
||||
if: steps.cache-python-env.outputs.cache-hit != 'true'
|
||||
|
||||
- name: Install TA-lib
|
||||
# Inspiration for this step is taken from here: https://github.com/mrjbq7/ta-lib/blob/master/.github/workflows/tests.yml
|
||||
shell: bash
|
||||
run: |
|
||||
wget https://raw.githubusercontent.com/mrjbq7/ta-lib/master/tools/build_talib_from_source.bash
|
||||
chmod +x build_talib_from_source.bash
|
||||
./build_talib_from_source.bash $DEPS_PATH
|
||||
python -m pip install TA-lib
|
||||
env:
|
||||
DEPS_PATH: ${{ github.workspace }}/dependencies
|
||||
TA_INCLUDE_PATH: ${{ github.workspace }}/dependencies/include
|
||||
TA_LIBRARY_PATH: ${{ github.workspace }}/dependencies/lib
|
||||
|
||||
- name: Install pandas-ta
|
||||
run: |
|
||||
python -m pip install ".[test]"
|
||||
|
||||
- name: Run tests
|
||||
shell: bash
|
||||
run: |
|
||||
make tests
|
||||
@@ -1,147 +0,0 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
|
||||
.DS_Store
|
||||
|
||||
# Distribution / packaging
|
||||
.pypirc
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
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/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
# celery beat schedule file
|
||||
celerybeat-schedule
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# pycharm
|
||||
.idea/*
|
||||
|
||||
# pytest
|
||||
.pytest_cache/
|
||||
|
||||
# pytest debug logs generated via --debug
|
||||
pytestdebug.log
|
||||
|
||||
# dotenv
|
||||
.env
|
||||
|
||||
# virtualenv
|
||||
.venv
|
||||
venv/
|
||||
ENV/
|
||||
env/**
|
||||
.env*/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
|
||||
# vscode settings
|
||||
.vscode/**
|
||||
|
||||
# zed settings
|
||||
.zed
|
||||
.zed/**
|
||||
|
||||
# misc
|
||||
dev.sh
|
||||
Dockerfile
|
||||
flake.nix
|
||||
flake.lock
|
||||
Makefile
|
||||
scripts/
|
||||
setup.py*
|
||||
ta-lib/
|
||||
venv.sh
|
||||
website.tar.gz
|
||||
|
||||
# Data & NB Exclusions
|
||||
csv/
|
||||
# data/
|
||||
jnb/
|
||||
notes/
|
||||
|
||||
# mkdocs documentation
|
||||
all_tests.sh
|
||||
mkdocs.yml
|
||||
docs/
|
||||
site/
|
||||
examples/
|
||||
|
||||
*.bak
|
||||
@@ -1,73 +0,0 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, 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.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers 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, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
|
||||
## Guidelines
|
||||
|
||||
Not everyone is familiar with open-source communities or intuitively understands what is acceptable behavior. To assist, the following guidelines and examples provide a quick overview to help you avoid common pitfalls:
|
||||
|
||||
1. Do **not** feel entitled to free software, support, or advice, especially if you are **not** a contributor, member, or business customer. Do **not** expect others to give you status reports as if they work for you or owe you something, even if you've made a donation. Please refrain from using GitHub Issues or other development tools for general discussions, technical support, or personal opinions.
|
||||
|
||||
2. Slow down and **read** the documentation and use the troubleshooting checklists provided to identify the root cause of a problem **before** submitting _invalid_ bug reports, inciting public disputes, or insulting community members in public spaces. Such actions are disruptive and prevent maintainers and contributors from working on features and improvements that benefit users.
|
||||
|
||||
3. Ignorant, reckless, or harsh communication is unacceptable, whether public or private.
|
||||
|
||||
Many issues that new users become upset about in old issue comments have been resolved. If not, rest assured that we are working diligently to improve the software.
|
||||
|
||||
## Enforcement
|
||||
|
||||
We will enforce our community standards as necessary appropriate to the circumstances to protect everyone's well-being if there are instances of abusive, harassing, or otherwise unacceptable behavior.
|
||||
|
||||
Initial warnings may be issued in the form of a snarky comment, especially if you seem to be exhibiting behaviour from Guideline #3 above. For serious cases, we will refer you to this Code of Conduct to prevent any misunderstandings. We also reserve the right to remove rants, personal attacks, spam, and unsolicited advertising from our community forums.
|
||||
|
||||
In addition, we may use technical measures to temporarily or permanently restrict your access to our infrastructure.
|
||||
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2019+ Kevin Johnson
|
||||
|
||||
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.
|
||||
@@ -1,52 +0,0 @@
|
||||
Metadata-Version: 2.4
|
||||
Name: pandas-ta
|
||||
Version: 0.4.71b0
|
||||
Summary: A Comprehensive Python 3 Technical Analysis Library with Pandas Dataframe Extension for Quantitative Researchers, Traders, and Investors.
|
||||
Project-URL: Homepage, https://www.pandas-ta.dev
|
||||
Project-URL: Documentation, https://www.pandas-ta.dev/api
|
||||
Project-URL: Repository, https://github.com/twopirllc/pandas-ta
|
||||
Author-email: Pandas TA Support <support@pandas-ta.dev>
|
||||
License-File: LICENSE
|
||||
Keywords: ai,dataframe extension,finance,indicators,library,machine learning,pandas,ta,technical analysis,trading
|
||||
Classifier: Development Status :: 4 - Beta
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Intended Audience :: Financial and Insurance Industry
|
||||
Classifier: Intended Audience :: Science/Research
|
||||
Classifier: Natural Language :: English
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python :: 3.12
|
||||
Classifier: Topic :: Office/Business :: Financial
|
||||
Classifier: Topic :: Office/Business :: Financial :: Investment
|
||||
Classifier: Topic :: Scientific/Engineering
|
||||
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
||||
Requires-Python: >=3.12
|
||||
Requires-Dist: numba==0.61.2
|
||||
Requires-Dist: numpy>=2.2.6
|
||||
Requires-Dist: pandas>=2.3.2
|
||||
Requires-Dist: tqdm>=4.67.1
|
||||
Description-Content-Type: text/markdown
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.pandas-ta.dev"><img src="https://www.pandas-ta.dev/assets/images/pta-logo.webp" alt="Pandas TA"></a>
|
||||
</p>
|
||||
|
||||
# Pandas TA
|
||||
A popular and comprehensive Technical Analysis Library in Python 3 that leverages [_numba_](http://numba.pydata.org/) and [_numpy_](https://numpy.org/) for accuracy and performance, and [_pandas_](https://pandas.pydata.org/) for simplicity and bulk processing. The library contains more than 150 indicators and utilities as well as 60 Candlestick Patterns when [TA Lib](https://ta-lib.org) is installed.
|
||||
|
||||
<br>
|
||||
|
||||

|
||||

|
||||
|
||||
<br>
|
||||
|
||||
## Details
|
||||
|
||||
* [Getting Started](https://www.pandas-ta.dev/getting-started/installation/)
|
||||
* [Documentation](https://www.pandas-ta.dev/api/)
|
||||
* [Support](https://www.pandas-ta.dev/support/)
|
||||
* [License](https://www.pandas-ta.dev/legal/license/)
|
||||
|
||||
<br>
|
||||
|
||||
Copyright © 2025 - Pandas TA
|
||||
@@ -1,24 +0,0 @@
|
||||
<p align="center">
|
||||
<a href="https://www.pandas-ta.dev"><img src="https://www.pandas-ta.dev/assets/images/pta-logo.webp" alt="Pandas TA"></a>
|
||||
</p>
|
||||
|
||||
# Pandas TA
|
||||
A popular and comprehensive Technical Analysis Library in Python 3 that leverages [_numba_](http://numba.pydata.org/) and [_numpy_](https://numpy.org/) for accuracy and performance, and [_pandas_](https://pandas.pydata.org/) for simplicity and bulk processing. The library contains more than 150 indicators and utilities as well as 60 Candlestick Patterns when [TA Lib](https://ta-lib.org) is installed.
|
||||
|
||||
<br>
|
||||
|
||||

|
||||

|
||||
|
||||
<br>
|
||||
|
||||
## Details
|
||||
|
||||
* [Getting Started](https://www.pandas-ta.dev/getting-started/installation/)
|
||||
* [Documentation](https://www.pandas-ta.dev/api/)
|
||||
* [Support](https://www.pandas-ta.dev/support/)
|
||||
* [License](https://www.pandas-ta.dev/legal/license/)
|
||||
|
||||
<br>
|
||||
|
||||
Copyright © 2025 - Pandas TA
|
||||
@@ -1,31 +0,0 @@
|
||||
,date,high,low,close
|
||||
0,2020-6-19,11382,11150,11286
|
||||
1,2020-6-20,11351,11155,11325
|
||||
2,2020-6-21,11355,11225,11238
|
||||
3,2020-6-22,11675,11232,11593
|
||||
4,2020-6-23,11649,11488,11509
|
||||
5,2020-6-24,11553,11110,11233
|
||||
6,2020-6-25,11232,10842,11147
|
||||
7,2020-6-26,11185,10901,11045
|
||||
8,2020-6-27,11051,10791,10913
|
||||
9,2020-6-28,11163,10756,10970
|
||||
10,2020-6-29,11033,10814,10972
|
||||
11,2020-6-30,11004,10882,10903
|
||||
12,2020-7-1,11111,10887,11051
|
||||
13,2020-7-2,11077,10772,10888
|
||||
14,2020-7-3,10920,10821,10837
|
||||
15,2020-7-4,10960,10814,10884
|
||||
16,2020-7-5,10900,10700,10831
|
||||
17,2020-7-6,11102,10796,11065
|
||||
18,2020-7-7,11097,10952,10988
|
||||
19,2020-7-8,11208,10968,11138
|
||||
20,2020-7-9,11149,10906,10961
|
||||
21,2020-7-10,11062,10880,11043
|
||||
22,2020-7-11,11044,10910,10957
|
||||
23,2020-7-12,11061,10915,11036
|
||||
24,2020-7-13,11063,10908,11000
|
||||
25,2020-7-14,11040,10925,11010
|
||||
26,2020-7-15,11017,10955,10975
|
||||
27,2020-7-16,11003,10835,10934
|
||||
28,2020-7-17,10980,10875,10937
|
||||
29,2020-7-18,10990,10894,10905
|
||||
|
@@ -1,248 +0,0 @@
|
||||
Date,Open,High,Low,Close,VWAP,Volume
|
||||
2020-10-26,343.7,344.9,336.7,339.8,341.19,8695206
|
||||
2020-10-27,338.3,339.75,331.05,334.05,333.74,9910942
|
||||
2020-10-28,335.75,339.85,334.4,335.65,337.29,8984606
|
||||
2020-10-29,333.65,340.0,331.15,337.45,335.96,7239961
|
||||
2020-10-30,339.25,345.0,338.45,340.7,341.18,11496123
|
||||
2020-11-02,341.75,341.75,333.7,334.8,336.22,4831133
|
||||
2020-11-03,335.5,339.45,332.65,335.65,336.36,4757798
|
||||
2020-11-04,338.0,351.55,337.5,342.95,345.59,15381900
|
||||
2020-11-05,347.95,349.0,344.05,345.4,346.41,5602436
|
||||
2020-11-06,346.15,349.0,343.4,345.75,344.92,5457793
|
||||
2020-11-09,350.0,352.8,347.0,351.95,350.46,7107285
|
||||
2020-11-10,350.75,350.75,341.15,342.3,343.63,9049620
|
||||
2020-11-11,344.5,347.75,341.5,346.75,344.53,7637879
|
||||
2020-11-12,348.0,350.7,344.3,345.55,346.81,5114424
|
||||
2020-11-13,344.5,346.25,342.7,344.15,344.04,4727888
|
||||
2020-11-14,347.15,347.55,343.1,345.45,345.82,749242
|
||||
2020-11-17,347.0,350.5,343.7,348.7,347.99,6653834
|
||||
2020-11-18,349.75,352.35,341.8,345.3,345.38,7407808
|
||||
2020-11-19,347.7,349.5,341.6,342.6,345.72,11056851
|
||||
2020-11-20,343.8,348.5,342.05,346.3,345.96,6181393
|
||||
2020-11-23,348.0,357.4,346.0,355.85,352.34,10333347
|
||||
2020-11-24,359.0,361.4,355.0,355.5,357.97,10092441
|
||||
2020-11-25,357.9,358.8,349.55,350.0,352.95,6812338
|
||||
2020-11-26,351.0,356.4,347.2,354.85,352.19,7366370
|
||||
2020-11-27,354.85,357.5,347.85,350.5,351.8,12402084
|
||||
2020-12-01,352.7,353.9,346.25,352.85,350.99,10693567
|
||||
2020-12-02,354.45,360.3,354.2,358.9,357.61,9434077
|
||||
2020-12-03,364.0,364.0,358.0,360.3,360.33,10697045
|
||||
2020-12-04,361.1,362.4,359.0,360.8,360.69,7427393
|
||||
2020-12-07,362.0,362.75,357.5,358.45,359.01,8392383
|
||||
2020-12-08,360.3,365.0,358.4,363.7,361.67,11813301
|
||||
2020-12-09,367.75,367.75,357.5,359.5,362.22,18137688
|
||||
2020-12-10,356.2,358.0,352.75,355.9,355.84,6897397
|
||||
2020-12-11,357.4,360.0,352.65,353.5,355.85,5863616
|
||||
2020-12-14,353.5,354.55,347.1,349.35,349.28,11501839
|
||||
2020-12-15,349.3,353.9,347.5,352.7,351.95,7231781
|
||||
2020-12-16,353.9,358.95,353.2,358.4,356.44,6666272
|
||||
2020-12-17,358.4,359.25,355.5,356.9,357.27,4165371
|
||||
2020-12-18,358.95,365.8,357.5,363.55,362.94,17398081
|
||||
2020-12-21,362.5,367.45,348.35,353.95,360.92,9665063
|
||||
2020-12-22,354.0,365.7,349.45,364.2,357.14,8186039
|
||||
2020-12-23,374.0,387.6,371.7,385.55,379.89,44874433
|
||||
2020-12-24,386.45,386.7,378.65,382.2,382.71,12240172
|
||||
2020-12-28,383.45,386.4,382.0,382.9,384.06,4725879
|
||||
2020-12-29,384.0,390.5,383.1,385.0,387.04,11459126
|
||||
2020-12-30,385.0,386.6,382.8,384.4,384.43,7188435
|
||||
2020-12-31,381.2,387.6,381.2,386.25,385.2,6394605
|
||||
2021-01-01,385.05,390.75,385.05,388.1,388.0,5042336
|
||||
2021-01-04,390.0,397.95,387.8,396.4,393.91,9755721
|
||||
2021-01-05,394.1,409.8,393.5,406.3,403.28,25156747
|
||||
2021-01-06,405.0,417.4,403.3,406.4,410.04,22486300
|
||||
2021-01-07,412.25,413.0,403.85,406.75,406.88,12344755
|
||||
2021-01-08,407.5,432.65,407.25,430.2,423.56,40993230
|
||||
2021-01-11,436.0,451.0,435.0,446.8,444.84,47334018
|
||||
2021-01-12,447.95,460.75,442.4,457.7,451.3,22134465
|
||||
2021-01-13,461.0,467.45,452.8,459.0,460.7,29190193
|
||||
2021-01-14,452.0,466.0,430.0,454.35,450.54,71551807
|
||||
2021-01-15,454.75,459.4,436.6,438.55,447.14,25307779
|
||||
2021-01-18,441.0,445.0,429.1,431.55,438.58,21510587
|
||||
2021-01-19,433.0,439.55,427.7,430.25,432.24,15677790
|
||||
2021-01-20,434.0,447.85,433.0,444.95,443.71,24419679
|
||||
2021-01-21,451.6,453.45,442.3,445.8,448.46,15911377
|
||||
2021-01-22,447.45,452.0,440.45,444.75,445.22,11398812
|
||||
2021-01-25,445.15,451.0,435.15,437.25,441.91,7380169
|
||||
2021-01-27,438.0,454.75,437.25,446.45,449.19,29590210
|
||||
2021-01-28,443.25,448.6,427.3,431.9,434.54,14812435
|
||||
2021-01-29,437.4,437.7,415.55,417.9,425.79,15632421
|
||||
2021-02-01,416.1,423.8,408.2,421.5,415.3,15081852
|
||||
2021-02-02,428.0,435.55,423.65,428.35,427.93,13310498
|
||||
2021-02-03,430.2,439.95,430.2,433.5,436.37,9897666
|
||||
2021-02-04,433.5,436.9,428.25,429.9,430.85,7193299
|
||||
2021-02-05,432.0,433.4,420.55,425.55,424.89,8679026
|
||||
2021-02-08,430.35,437.7,426.3,435.3,431.95,12516340
|
||||
2021-02-09,440.25,451.75,435.2,439.35,445.17,29474830
|
||||
2021-02-10,442.0,444.15,435.0,439.0,438.83,10607735
|
||||
2021-02-11,439.0,440.5,433.4,437.0,436.02,9237026
|
||||
2021-02-12,440.0,449.2,439.6,442.0,444.59,19280834
|
||||
2021-02-15,444.6,444.9,436.8,439.7,440.59,7844877
|
||||
2021-02-16,446.0,447.8,433.8,437.55,440.41,12453798
|
||||
2021-02-17,435.9,439.0,428.5,430.2,432.63,7390192
|
||||
2021-02-18,430.3,436.65,429.35,432.95,432.81,8385736
|
||||
2021-02-19,433.15,435.75,426.1,429.95,431.28,8478666
|
||||
2021-02-22,430.7,432.85,416.0,418.7,422.91,10666087
|
||||
2021-02-23,419.7,426.0,414.3,415.5,419.17,8992353
|
||||
2021-02-24,417.7,425.8,414.75,423.1,419.2,5060297
|
||||
2021-02-25,423.1,429.0,420.45,421.3,424.69,9110392
|
||||
2021-02-26,417.95,419.85,408.0,410.3,413.09,11731941
|
||||
2021-03-01,411.0,418.7,409.2,414.4,414.87,6421696
|
||||
2021-03-02,419.7,433.1,418.25,430.4,426.86,14875234
|
||||
2021-03-03,433.0,436.65,428.25,435.5,433.26,8782452
|
||||
2021-03-04,428.9,444.3,427.5,438.8,439.03,12963797
|
||||
2021-03-05,440.0,440.0,417.0,420.85,426.19,43931172
|
||||
2021-03-08,425.1,425.15,415.55,416.9,418.53,12354838
|
||||
2021-03-09,419.8,422.8,410.05,419.2,416.27,11905629
|
||||
2021-03-10,426.1,430.7,423.0,426.7,427.09,17291368
|
||||
2021-03-12,431.5,432.8,422.1,425.2,427.39,8960126
|
||||
2021-03-15,424.8,428.6,417.8,426.35,424.52,7517124
|
||||
2021-03-16,427.25,434.95,425.65,429.3,430.57,10673647
|
||||
2021-03-17,429.0,435.5,417.7,419.65,427.84,12134812
|
||||
2021-03-18,423.25,424.15,404.3,410.15,414.52,10082931
|
||||
2021-03-19,408.95,413.65,399.45,410.5,408.79,16875402
|
||||
2021-03-22,411.05,416.25,410.2,414.45,413.97,6622984
|
||||
2021-03-23,417.7,423.4,412.7,415.5,416.98,11575194
|
||||
2021-03-24,411.35,415.45,409.2,411.0,411.84,5140347
|
||||
2021-03-25,410.7,411.7,397.75,399.65,402.63,12737129
|
||||
2021-03-26,404.8,407.7,400.65,403.9,403.72,9033369
|
||||
2021-03-30,405.0,420.45,405.0,418.1,413.6,13171390
|
||||
2021-03-31,419.8,419.8,413.35,414.15,415.37,7445134
|
||||
2021-04-01,418.85,422.85,414.35,416.4,417.72,7596943
|
||||
2021-04-05,416.45,427.9,416.2,425.45,423.14,21216395
|
||||
2021-04-06,427.95,428.9,422.35,427.15,425.99,8320520
|
||||
2021-04-07,425.0,439.0,423.4,438.0,431.67,13867650
|
||||
2021-04-08,441.95,445.95,440.0,442.1,442.94,12916614
|
||||
2021-04-09,442.9,451.35,440.0,450.1,446.5,11699385
|
||||
2021-04-12,450.0,450.1,429.4,432.6,435.75,15086267
|
||||
2021-04-13,432.0,437.55,412.6,418.95,420.89,20420320
|
||||
2021-04-15,418.9,434.45,415.0,430.7,428.6,26758891
|
||||
2021-04-16,441.7,473.65,436.0,469.2,464.06,109361636
|
||||
2021-04-19,463.0,477.95,461.1,472.75,470.56,43809855
|
||||
2021-04-20,476.0,477.55,467.8,470.1,471.11,17730691
|
||||
2021-04-22,471.6,494.5,471.6,486.65,486.53,42620929
|
||||
2021-04-23,483.55,487.35,474.35,475.7,481.46,13596003
|
||||
2021-04-26,479.4,483.85,477.0,480.3,479.77,9314644
|
||||
2021-04-27,481.4,487.0,481.0,485.05,484.07,7209467
|
||||
2021-04-28,485.85,493.2,481.25,489.3,487.55,9615534
|
||||
2021-04-29,492.7,492.8,485.7,489.85,489.45,7641133
|
||||
2021-04-30,491.5,511.8,489.3,492.75,501.42,29115571
|
||||
2021-05-03,487.95,496.0,483.25,487.35,488.82,8599731
|
||||
2021-05-04,487.3,488.3,477.8,481.95,482.16,8102429
|
||||
2021-05-05,484.8,496.0,483.3,490.6,490.81,11856591
|
||||
2021-05-06,493.7,514.8,487.25,512.3,506.32,24413544
|
||||
2021-05-07,514.0,516.55,507.5,515.25,512.83,14666581
|
||||
2021-05-10,517.6,528.5,513.25,525.95,521.17,12544472
|
||||
2021-05-11,517.95,523.3,514.05,518.4,517.71,7649499
|
||||
2021-05-12,519.95,522.55,504.85,507.6,512.01,7871107
|
||||
2021-05-14,507.5,508.4,492.75,498.45,497.83,6799879
|
||||
2021-05-17,498.45,503.7,495.0,499.8,500.11,5752650
|
||||
2021-05-18,502.0,514.8,500.9,508.05,509.98,9380746
|
||||
2021-05-19,508.3,517.8,505.15,511.65,512.88,7490396
|
||||
2021-05-20,516.0,517.0,503.6,508.25,510.08,6292304
|
||||
2021-05-21,510.0,515.9,509.15,512.7,512.84,5197503
|
||||
2021-05-24,511.9,518.5,509.65,514.9,515.62,7436812
|
||||
2021-05-25,517.4,524.85,515.7,517.55,520.01,7954564
|
||||
2021-05-26,514.9,530.45,514.75,527.25,525.5,8823190
|
||||
2021-05-27,527.25,545.0,525.05,540.9,539.19,29411126
|
||||
2021-05-28,539.0,540.3,532.65,538.7,536.6,5878626
|
||||
2021-05-31,538.7,540.55,531.05,539.05,537.4,5386205
|
||||
2021-06-01,541.9,547.0,539.65,542.8,543.11,5965044
|
||||
2021-06-02,541.95,545.0,533.0,543.0,539.1,4713568
|
||||
2021-06-03,545.7,549.9,538.3,539.05,541.49,5637991
|
||||
2021-06-04,543.5,545.5,540.45,541.2,542.62,4771716
|
||||
2021-06-07,544.7,551.2,542.7,548.25,548.14,4348433
|
||||
2021-06-08,550.0,555.5,549.15,550.6,552.19,5429734
|
||||
2021-06-09,553.0,553.25,542.2,544.2,547.74,6206899
|
||||
2021-06-10,545.55,555.5,545.55,554.25,552.94,5720744
|
||||
2021-06-11,555.0,558.95,551.5,554.3,555.3,5612359
|
||||
2021-06-14,553.9,562.8,553.0,561.6,559.27,5952159
|
||||
2021-06-15,561.5,564.0,557.0,557.9,560.54,3837245
|
||||
2021-06-16,559.9,562.55,553.5,555.25,557.94,5497269
|
||||
2021-06-17,552.5,561.5,549.55,558.7,555.66,4399348
|
||||
2021-06-18,560.0,561.95,546.05,549.8,551.95,10007116
|
||||
2021-06-21,544.75,544.75,535.2,542.15,540.03,5390821
|
||||
2021-06-22,545.25,559.95,542.3,556.55,553.47,5752921
|
||||
2021-06-23,560.0,560.85,538.4,540.15,545.31,11242702
|
||||
2021-06-24,541.9,550.55,539.2,549.05,546.31,8668680
|
||||
2021-06-25,549.85,551.0,540.5,547.5,546.25,5039822
|
||||
2021-06-28,549.75,550.8,544.25,547.4,547.78,3259830
|
||||
2021-06-29,547.8,553.75,541.0,542.6,546.44,7927880
|
||||
2021-06-30,544.85,548.0,542.0,545.65,545.7,4293322
|
||||
2021-07-01,545.0,545.9,538.0,539.35,540.69,4329374
|
||||
2021-07-02,540.1,542.3,533.6,538.6,537.3,4157307
|
||||
2021-07-05,542.9,542.9,535.55,536.35,537.49,3439169
|
||||
2021-07-06,536.55,538.3,531.85,532.6,533.81,4193441
|
||||
2021-07-07,534.05,536.4,525.1,532.15,531.49,5377687
|
||||
2021-07-08,533.9,536.95,528.0,531.0,532.33,4565510
|
||||
2021-07-09,527.4,530.95,523.25,525.8,526.28,5724608
|
||||
2021-07-12,530.75,532.15,523.2,525.85,528.04,3865556
|
||||
2021-07-13,528.0,529.5,522.6,524.85,525.64,4172358
|
||||
2021-07-14,526.25,563.3,525.6,561.7,551.0,29348083
|
||||
2021-07-15,561.0,579.65,559.0,575.9,572.71,31066201
|
||||
2021-07-16,580.0,589.25,568.3,577.75,577.56,36907827
|
||||
2021-07-19,572.55,584.0,570.0,573.8,577.28,10857851
|
||||
2021-07-20,575.7,578.15,561.55,568.1,567.43,10523527
|
||||
2021-07-22,577.1,585.0,571.0,584.2,579.61,12043385
|
||||
2021-07-23,586.5,601.8,583.7,599.15,594.86,14057455
|
||||
2021-07-26,600.1,600.5,588.25,590.45,594.0,6099903
|
||||
2021-07-27,588.9,594.65,584.15,591.45,588.79,3983137
|
||||
2021-07-28,590.95,593.35,583.0,591.95,587.86,4573930
|
||||
2021-07-29,593.6,598.0,587.9,590.45,593.23,5834470
|
||||
2021-07-30,588.85,593.0,585.0,587.15,589.07,3178206
|
||||
2021-08-02,588.2,595.4,582.25,592.25,588.64,4623898
|
||||
2021-08-03,604.0,604.0,594.15,599.4,597.75,5165607
|
||||
2021-08-04,603.5,604.0,594.3,596.8,597.91,4509356
|
||||
2021-08-05,597.5,614.5,597.5,600.9,606.72,11294364
|
||||
2021-08-06,603.75,606.4,596.3,598.0,601.42,5270200
|
||||
2021-08-09,600.0,606.0,595.5,596.8,599.75,4646751
|
||||
2021-08-10,598.4,608.95,593.1,603.85,603.0,7027782
|
||||
2021-08-11,601.9,606.5,598.45,601.25,601.72,4282513
|
||||
2021-08-12,602.0,608.9,600.65,605.85,605.08,3952508
|
||||
2021-08-13,606.0,620.45,606.0,615.5,614.1,8364684
|
||||
2021-08-16,616.1,620.9,610.5,614.05,615.39,3572426
|
||||
2021-08-17,613.75,637.05,611.2,634.9,626.66,11822772
|
||||
2021-08-18,635.75,639.2,624.6,629.4,631.97,6923577
|
||||
2021-08-20,622.5,631.95,618.0,620.05,623.36,6170693
|
||||
2021-08-23,626.0,636.95,623.5,628.85,630.46,7036375
|
||||
2021-08-24,636.0,636.0,624.1,633.55,630.64,4483718
|
||||
2021-08-25,635.0,642.8,629.55,631.65,636.31,6407718
|
||||
2021-08-26,632.2,638.5,626.0,628.95,631.86,4208351
|
||||
2021-08-27,629.5,636.0,625.3,634.95,632.11,4371554
|
||||
2021-08-30,635.95,639.5,630.55,632.45,633.87,4371855
|
||||
2021-08-31,634.6,642.55,628.9,640.95,637.51,7795908
|
||||
2021-09-01,643.8,647.35,635.25,642.05,641.38,4725222
|
||||
2021-09-02,645.0,657.0,640.75,651.45,648.56,4538778
|
||||
2021-09-03,653.0,656.7,649.5,655.1,653.68,3774970
|
||||
2021-09-06,656.65,688.7,656.65,686.45,675.53,12338416
|
||||
2021-09-07,690.0,690.0,672.75,674.25,679.16,6406109
|
||||
2021-09-08,675.4,675.4,660.0,662.2,664.96,6716231
|
||||
2021-09-09,660.9,664.55,654.0,662.35,660.1,5805730
|
||||
2021-09-13,662.35,671.85,657.85,670.75,667.33,5588789
|
||||
2021-09-14,671.0,675.7,670.0,673.45,673.41,3661338
|
||||
2021-09-15,674.0,680.55,670.0,674.05,675.03,4145416
|
||||
2021-09-16,679.75,680.75,665.0,667.85,670.77,4657846
|
||||
2021-09-17,671.4,674.4,662.75,665.25,668.16,5407781
|
||||
2021-09-20,657.75,670.5,653.4,662.5,664.4,4546430
|
||||
2021-09-21,660.5,669.0,657.1,667.6,663.15,3683551
|
||||
2021-09-22,669.0,674.5,663.0,668.15,668.59,4791652
|
||||
2021-09-23,672.9,677.0,671.4,674.3,674.63,3231293
|
||||
2021-09-24,680.5,699.15,675.0,676.5,687.0,12126588
|
||||
2021-09-27,678.05,678.35,651.0,653.9,658.22,8399082
|
||||
2021-09-28,653.9,653.9,635.25,639.6,642.5,8112462
|
||||
2021-09-29,629.95,646.5,627.35,640.75,636.66,8839566
|
||||
2021-09-30,638.75,646.75,632.55,634.1,638.65,6013959
|
||||
2021-10-01,634.8,639.75,630.2,636.25,635.17,4208854
|
||||
2021-10-04,639.9,643.6,635.95,641.05,638.84,5247122
|
||||
2021-10-05,636.45,649.5,634.05,646.85,641.56,5456074
|
||||
2021-10-06,650.4,650.45,634.4,635.75,640.73,4836599
|
||||
2021-10-07,639.0,648.55,636.9,642.95,643.86,3724343
|
||||
2021-10-08,646.15,667.55,645.0,661.15,659.07,11045983
|
||||
2021-10-11,648.95,666.3,635.0,652.8,651.74,10211466
|
||||
2021-10-12,652.0,662.4,642.55,659.1,653.44,9340216
|
||||
2021-10-13,665.0,674.7,656.0,672.6,664.89,9462941
|
||||
2021-10-14,697.0,739.85,695.0,708.25,717.07,59188803
|
||||
2021-10-18,719.0,720.8,702.4,709.75,711.39,10599446
|
||||
2021-10-19,717.1,729.95,708.0,711.55,721.38,10932574
|
||||
2021-10-20,713.6,722.75,695.75,701.95,705.96,8054391
|
||||
2021-10-21,708.95,709.0,681.7,696.3,694.67,7958456
|
||||
2021-10-22,701.75,705.5,678.25,682.4,689.25,5379151
|
||||
|
@@ -1,101 +0,0 @@
|
||||
,date,open,high,low,close,volume
|
||||
0,2018-07-05,272.17,273.18,270.96,273.11,56925919.0
|
||||
1,2018-07-06,273.14,275.84,272.715,275.42,66493696.0
|
||||
2,2018-07-09,276.55,277.96,276.5,277.9,50550399.0
|
||||
3,2018-07-10,278.41,279.01,278.08,278.9,51966829.0
|
||||
4,2018-07-11,277.15,278.04,276.52,276.86,77054739.0
|
||||
5,2018-07-12,278.28,279.43,277.6,279.37,60124687.0
|
||||
6,2018-07-13,279.17,279.93,278.66,279.59,48234964.0
|
||||
7,2018-07-16,279.64,279.803,278.84,279.34,48201038.0
|
||||
8,2018-07-17,278.47,280.91,278.41,280.47,52315500.0
|
||||
9,2018-07-18,280.56,281.18,280.06,281.06,44593465.0
|
||||
10,2018-07-19,280.31,280.74,279.46,280.0,61412117.0
|
||||
11,2018-07-20,279.77,280.48,279.5,279.68,82372729.0
|
||||
12,2018-07-23,279.45,280.43,279.06,280.2,47047565.0
|
||||
13,2018-07-24,281.79,282.56,280.63,281.61,68026935.0
|
||||
14,2018-07-25,281.33,284.37,281.28,284.01,78882927.0
|
||||
15,2018-07-26,283.2,284.11,283.09,283.34,57919495.0
|
||||
16,2018-07-27,283.71,283.82,280.38,281.42,76783177.0
|
||||
17,2018-07-30,281.51,281.69,279.36,279.95,63742508.0
|
||||
18,2018-07-31,280.81,282.02,280.38,281.33,68570493.0
|
||||
19,2018-08-01,281.56,282.13,280.1315,280.86,53853326.0
|
||||
20,2018-08-02,279.39,282.58,279.16,282.39,63426363.0
|
||||
21,2018-08-03,282.53,283.6577,282.33,283.6,53935386.0
|
||||
22,2018-08-06,283.64,284.99,283.2015,284.64,39400887.0
|
||||
23,2018-08-07,285.39,286.01,285.24,285.58,43196646.0
|
||||
24,2018-08-08,285.39,285.91,284.94,285.46,42114551.0
|
||||
25,2018-08-09,285.53,285.97,284.915,285.07,35716976.0
|
||||
26,2018-08-10,283.45,284.055,282.36,283.16,77076044.0
|
||||
27,2018-08-13,283.47,284.16,281.77,282.1,65732909.0
|
||||
28,2018-08-14,282.92,284.17,282.4833,283.9,43842031.0
|
||||
29,2018-08-15,282.38,282.54,280.16,281.78,102925355.0
|
||||
30,2018-08-16,283.4,285.04,283.36,284.06,69967919.0
|
||||
31,2018-08-17,283.83,285.5601,283.37,285.06,65618481.0
|
||||
32,2018-08-20,285.57,285.97,285.06,285.67,39807490.0
|
||||
33,2018-08-21,286.25,287.31,285.7135,286.34,67271983.0
|
||||
34,2018-08-22,285.88,286.76,285.575,286.17,44993333.0
|
||||
35,2018-08-23,285.97,286.94,285.43,285.79,49204851.0
|
||||
36,2018-08-24,286.44,287.67,286.38,287.51,57487399.0
|
||||
37,2018-08-27,288.86,289.9,288.68,289.78,57072377.0
|
||||
38,2018-08-28,290.3,290.4175,289.4,289.92,46943472.0
|
||||
39,2018-08-29,290.16,291.74,289.8854,291.48,61485514.0
|
||||
40,2018-08-30,290.94,291.36,289.63,290.3,61229501.0
|
||||
41,2018-08-31,289.84,290.81,289.29,290.31,66140838.0
|
||||
42,2018-09-04,289.84,290.21,288.68,289.81,57594367.0
|
||||
43,2018-09-05,289.41,289.64,287.89,289.03,72452437.0
|
||||
44,2018-09-06,289.15,289.49,287.0,288.16,65909863.0
|
||||
45,2018-09-07,286.98,288.7,286.71,287.6,73524824.0
|
||||
46,2018-09-10,288.74,289.04,287.88,288.1,50191113.0
|
||||
47,2018-09-11,287.37,289.55,286.975,289.05,50530492.0
|
||||
48,2018-09-12,289.06,289.8,288.23,289.12,59810758.0
|
||||
49,2018-09-13,290.32,291.0384,289.995,290.83,51034222.0
|
||||
50,2018-09-14,291.06,291.27,290.0,290.88,55079875.0
|
||||
51,2018-09-17,290.82,290.86,289.03,289.34,68244043.0
|
||||
52,2018-09-18,289.58,291.58,289.55,290.91,61930407.0
|
||||
53,2018-09-19,290.97,291.69,290.825,291.22,49080562.0
|
||||
54,2018-09-20,292.64,293.94,291.2363,293.58,100360646.0
|
||||
55,2018-09-21,293.09,293.22,291.81,291.99,105479656.0
|
||||
56,2018-09-24,291.34,291.5,290.37,291.02,53409645.0
|
||||
57,2018-09-25,291.53,291.65,290.4833,290.75,44370037.0
|
||||
58,2018-09-26,290.91,292.24,289.41,289.88,79739674.0
|
||||
59,2018-09-27,290.41,291.91,290.1,290.69,59249455.0
|
||||
60,2018-09-28,289.99,291.28,289.95,290.72,70091385.0
|
||||
61,2018-10-01,292.11,292.93,290.98,291.73,62078937.0
|
||||
62,2018-10-02,291.56,292.355,291.14,291.56,47258227.0
|
||||
63,2018-10-03,292.74,293.21,291.32,291.72,64694594.0
|
||||
64,2018-10-04,291.18,291.24,287.66,289.44,111545910.0
|
||||
65,2018-10-05,289.69,290.27,286.22,287.82,105951698.0
|
||||
66,2018-10-08,287.05,288.22,285.5,287.82,87742172.0
|
||||
67,2018-10-09,287.39,288.86,286.77,287.4,74338982.0
|
||||
68,2018-10-10,286.83,286.91,277.88,278.3,214731000.0
|
||||
69,2018-10-11,277.08,278.9,270.36,272.17,274840491.0
|
||||
70,2018-10-12,276.77,277.09,272.37,275.95,183186492.0
|
||||
71,2018-10-15,275.55,277.04,274.3,274.4,102263717.0
|
||||
72,2018-10-16,276.6,280.82,276.07,280.4,118255834.0
|
||||
73,2018-10-17,280.44,281.15,277.56,280.45,110625987.0
|
||||
74,2018-10-18,279.4,280.07,274.97,276.4,134557525.0
|
||||
75,2018-10-19,277.13,279.3,275.47,276.25,139901634.0
|
||||
76,2018-10-22,277.0,277.36,274.41,275.01,82415812.0
|
||||
77,2018-10-23,270.95,274.87,268.61,273.61,146352719.0
|
||||
78,2018-10-24,273.33,273.76,264.7,265.32,177806697.0
|
||||
79,2018-10-25,267.38,271.81,266.23,270.08,138061545.0
|
||||
80,2018-10-26,265.92,271.0,262.29,265.33,201574596.0
|
||||
81,2018-10-29,268.8,270.25,259.85,263.86,160749101.0
|
||||
82,2018-10-30,263.67,268.12,263.12,267.77,157115995.0
|
||||
83,2018-10-31,270.65,273.23,270.12,270.63,128296325.0
|
||||
84,2018-11-01,271.6,273.73,270.38,273.51,99495037.0
|
||||
85,2018-11-02,274.75,275.23,269.59,271.89,122634107.0
|
||||
86,2018-11-05,272.44,274.01,271.35,273.39,65622482.0
|
||||
87,2018-11-06,273.32,275.3,273.25,275.12,60085894.0
|
||||
88,2018-11-07,277.56,281.1,277.08,281.01,102752099.0
|
||||
89,2018-11-08,280.11,281.22,279.22,280.5,65584886.0
|
||||
90,2018-11-09,279.03,279.24,276.18,277.76,98812561.0
|
||||
91,2018-11-12,277.19,277.46,271.99,272.57,99673574.0
|
||||
92,2018-11-13,273.09,275.325,271.25,272.06,98176610.0
|
||||
93,2018-11-14,274.16,274.61,268.45,270.2,125335931.0
|
||||
94,2018-11-15,268.78,273.54,267.0102,273.02,135101437.0
|
||||
95,2018-11-16,271.79,274.75,271.21,273.73,126668040.0
|
||||
96,2018-11-19,273.05,273.38,268.07,269.1,103061706.0
|
||||
97,2018-11-20,265.36,267.0,263.15,264.12,136021311.0
|
||||
98,2018-11-21,265.86,267.15,265.01,265.02,75563743.0
|
||||
99,2018-11-23,263.18,264.8234,263.07,263.25,42807878.0
|
||||
|
|
Before Width: | Height: | Size: 73 KiB |
|
Before Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 262 KiB |
|
Before Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 55 KiB |
@@ -1 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 96 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-miterlimit:1;"><g id="pandas-ta"><g transform="matrix(0.732166,0,0,1,-4.21259,-3.55271e-15)"><g transform="matrix(21.0163,0,0,21.0163,134.752,20.2035)"></g><text x="37.089px" y="20.204px" style="font-family:'Lato-Bold', 'Lato', sans-serif;font-weight:700;font-size:21.016px;fill:#fff;stroke:#000;stroke-width:0.54px;">P<tspan x="49.699px " y="20.204px ">a</tspan>ndas T<tspan x="119.83px " y="20.204px ">A</tspan></text></g></g><g id="logo"><rect id="bg" x="0.96" y="1.92" width="20.16" height="20.16" style="fill:#fff;"/><path d="M21.12,1.92l0,20.16l-20.16,0l-0,-20.16l20.16,0Zm-0.504,0.504l-19.152,-0l-0,19.152l19.152,0l0,-19.152Z"/><g id="bars"><rect id="_1" serif:id="1" x="2.88" y="12.48" width="3.436" height="2.88" style="fill:#ef5552;"/><rect id="_2" serif:id="2" x="7.175" y="15.36" width="3.436" height="4.8" style="fill:#ef5552;"/><rect id="_3" serif:id="3" x="11.469" y="11.52" width="3.436" height="2.88" style="fill:#4cae4f;"/><rect id="_4" serif:id="4" x="15.764" y="3.84" width="3.436" height="6.72" style="fill:#4cae4f;"/></g><path d="M2.88,14.016c0,-0 3.474,6.213 8.589,3.744c6.51,-3.142 7.731,-9.12 7.731,-9.12" style="fill:none;stroke:#0d28f2;stroke-width:0.45px;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:1.5;"/></g></svg>
|
||||
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 10 KiB |
@@ -1,72 +0,0 @@
|
||||
[project]
|
||||
name = "pandas-ta"
|
||||
version = "0.4.71b"
|
||||
description = "A Comprehensive Python 3 Technical Analysis Library with Pandas Dataframe Extension for Quantitative Researchers, Traders, and Investors."
|
||||
authors = [{ name = "Pandas TA Support", email = "support@pandas-ta.dev" }]
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"numba==0.61.2",
|
||||
"numpy>=2.2.6",
|
||||
"pandas>=2.3.2",
|
||||
"tqdm>=4.67.1",
|
||||
]
|
||||
readme = { file = "README.md", content-type = "text/markdown" }
|
||||
license-files = ["LICENSE"]
|
||||
keywords = [
|
||||
"library",
|
||||
"technical analysis",
|
||||
"ta",
|
||||
"indicators",
|
||||
"pandas",
|
||||
"dataframe extension",
|
||||
"finance",
|
||||
"trading",
|
||||
"machine learning",
|
||||
"ai",
|
||||
]
|
||||
classifiers = [
|
||||
"Development Status :: 4 - Beta",
|
||||
"Programming Language :: Python :: 3.12",
|
||||
"Operating System :: OS Independent",
|
||||
"Natural Language :: English",
|
||||
"Intended Audience :: Developers",
|
||||
"Intended Audience :: Financial and Insurance Industry",
|
||||
"Intended Audience :: Science/Research",
|
||||
"Topic :: Office/Business :: Financial",
|
||||
"Topic :: Office/Business :: Financial :: Investment",
|
||||
"Topic :: Scientific/Engineering",
|
||||
"Topic :: Scientific/Engineering :: Information Analysis",
|
||||
]
|
||||
|
||||
[project.urls]
|
||||
Homepage = "https://www.pandas-ta.dev"
|
||||
Documentation = "https://www.pandas-ta.dev/api"
|
||||
Repository = "https://github.com/twopirllc/pandas-ta"
|
||||
|
||||
[build-system]
|
||||
requires = ["hatchling"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"bokeh>=3.7.3",
|
||||
"cryptography>=45.0.6",
|
||||
"ipython>=9.4.0",
|
||||
"jupyterlab>=4.4.6",
|
||||
"matplotlib>=3.10.5",
|
||||
"pytest>=8.4.1",
|
||||
"requests>=2.32.5",
|
||||
"ta-lib==0.6.4",
|
||||
"yfinance>=0.2.65",
|
||||
]
|
||||
docs = [
|
||||
"mkdocs>=1.6.1",
|
||||
"mkdocs-include-markdown-plugin>=7.1.6",
|
||||
"mkdocs-macros-plugin>=1.3.9",
|
||||
"mkdocs-material>=9.6.18",
|
||||
"mkdocs-minify-plugin>=0.8.0",
|
||||
"mkdocs-plotly-plugin>=0.1.3",
|
||||
"mkdocs-redirects>=1.2.2",
|
||||
"mkdocstrings-python>=1.17.0",
|
||||
"ruff>=0.12.10",
|
||||
]
|
||||
@@ -1,383 +0,0 @@
|
||||
# This file was autogenerated by uv via the following command:
|
||||
# uv export --dev --no-hashes -vn -o requirements.dev.txt
|
||||
-e .
|
||||
anyio==4.10.0
|
||||
# via
|
||||
# httpx
|
||||
# jupyter-server
|
||||
appnope==0.1.4 ; sys_platform == 'darwin'
|
||||
# via ipykernel
|
||||
argon2-cffi==25.1.0
|
||||
# via jupyter-server
|
||||
argon2-cffi-bindings==21.2.0 ; python_full_version >= '3.14'
|
||||
# via argon2-cffi
|
||||
argon2-cffi-bindings==25.1.0 ; python_full_version < '3.14'
|
||||
# via argon2-cffi
|
||||
arrow==1.3.0
|
||||
# via isoduration
|
||||
asttokens==3.0.0
|
||||
# via stack-data
|
||||
async-lru==2.0.5
|
||||
# via jupyterlab
|
||||
attrs==25.3.0
|
||||
# via
|
||||
# jsonschema
|
||||
# referencing
|
||||
babel==2.17.0
|
||||
# via jupyterlab-server
|
||||
beautifulsoup4==4.13.5
|
||||
# via
|
||||
# nbconvert
|
||||
# yfinance
|
||||
bleach==6.2.0
|
||||
# via nbconvert
|
||||
bokeh==3.7.3
|
||||
certifi==2025.8.3
|
||||
# via
|
||||
# curl-cffi
|
||||
# httpcore
|
||||
# httpx
|
||||
# requests
|
||||
cffi==1.17.1
|
||||
# via
|
||||
# argon2-cffi-bindings
|
||||
# cryptography
|
||||
# curl-cffi
|
||||
# pyzmq
|
||||
charset-normalizer==3.4.3
|
||||
# via requests
|
||||
colorama==0.4.6 ; sys_platform == 'win32'
|
||||
# via
|
||||
# ipython
|
||||
# pytest
|
||||
# tqdm
|
||||
comm==0.2.3
|
||||
# via ipykernel
|
||||
contourpy==1.3.3
|
||||
# via
|
||||
# bokeh
|
||||
# matplotlib
|
||||
cryptography==45.0.6
|
||||
curl-cffi==0.13.0
|
||||
# via yfinance
|
||||
cycler==0.12.1
|
||||
# via matplotlib
|
||||
debugpy==1.8.16
|
||||
# via ipykernel
|
||||
decorator==5.2.1
|
||||
# via ipython
|
||||
defusedxml==0.7.1
|
||||
# via nbconvert
|
||||
executing==2.2.0
|
||||
# via stack-data
|
||||
fastjsonschema==2.21.2
|
||||
# via nbformat
|
||||
fonttools==4.59.1
|
||||
# via matplotlib
|
||||
fqdn==1.5.1
|
||||
# via jsonschema
|
||||
frozendict==2.4.6
|
||||
# via yfinance
|
||||
h11==0.16.0
|
||||
# via httpcore
|
||||
httpcore==1.0.9
|
||||
# via httpx
|
||||
httpx==0.28.1
|
||||
# via jupyterlab
|
||||
idna==3.10
|
||||
# via
|
||||
# anyio
|
||||
# httpx
|
||||
# jsonschema
|
||||
# requests
|
||||
iniconfig==2.1.0
|
||||
# via pytest
|
||||
ipykernel==6.30.1
|
||||
# via jupyterlab
|
||||
ipython==9.4.0
|
||||
# via ipykernel
|
||||
ipython-pygments-lexers==1.1.1
|
||||
# via ipython
|
||||
isoduration==20.11.0
|
||||
# via jsonschema
|
||||
jedi==0.19.2
|
||||
# via ipython
|
||||
jinja2==3.1.6
|
||||
# via
|
||||
# bokeh
|
||||
# jupyter-server
|
||||
# jupyterlab
|
||||
# jupyterlab-server
|
||||
# nbconvert
|
||||
json5==0.12.1
|
||||
# via jupyterlab-server
|
||||
jsonpointer==3.0.0
|
||||
# via jsonschema
|
||||
jsonschema==4.25.1
|
||||
# via
|
||||
# jupyter-events
|
||||
# jupyterlab-server
|
||||
# nbformat
|
||||
jsonschema-specifications==2025.4.1
|
||||
# via jsonschema
|
||||
jupyter-client==8.6.3
|
||||
# via
|
||||
# ipykernel
|
||||
# jupyter-server
|
||||
# nbclient
|
||||
jupyter-core==5.8.1
|
||||
# via
|
||||
# ipykernel
|
||||
# jupyter-client
|
||||
# jupyter-server
|
||||
# jupyterlab
|
||||
# nbclient
|
||||
# nbconvert
|
||||
# nbformat
|
||||
jupyter-events==0.12.0
|
||||
# via jupyter-server
|
||||
jupyter-lsp==2.2.6
|
||||
# via jupyterlab
|
||||
jupyter-server==2.17.0
|
||||
# via
|
||||
# jupyter-lsp
|
||||
# jupyterlab
|
||||
# jupyterlab-server
|
||||
# notebook-shim
|
||||
jupyter-server-terminals==0.5.3
|
||||
# via jupyter-server
|
||||
jupyterlab==4.4.6
|
||||
jupyterlab-pygments==0.3.0
|
||||
# via nbconvert
|
||||
jupyterlab-server==2.27.3
|
||||
# via jupyterlab
|
||||
kiwisolver==1.4.9
|
||||
# via matplotlib
|
||||
lark==1.2.2
|
||||
# via rfc3987-syntax
|
||||
llvmlite==0.44.0
|
||||
# via numba
|
||||
markupsafe==3.0.2
|
||||
# via
|
||||
# jinja2
|
||||
# nbconvert
|
||||
matplotlib==3.10.5
|
||||
matplotlib-inline==0.1.7
|
||||
# via
|
||||
# ipykernel
|
||||
# ipython
|
||||
mistune==3.1.3
|
||||
# via nbconvert
|
||||
multitasking==0.0.12
|
||||
# via yfinance
|
||||
narwhals==2.2.0
|
||||
# via bokeh
|
||||
nbclient==0.10.2
|
||||
# via nbconvert
|
||||
nbconvert==7.16.6
|
||||
# via jupyter-server
|
||||
nbformat==5.10.4
|
||||
# via
|
||||
# jupyter-server
|
||||
# nbclient
|
||||
# nbconvert
|
||||
nest-asyncio==1.6.0
|
||||
# via ipykernel
|
||||
notebook-shim==0.2.4
|
||||
# via jupyterlab
|
||||
numba==0.61.2
|
||||
# via pandas-ta
|
||||
numpy==2.2.6
|
||||
# via
|
||||
# bokeh
|
||||
# contourpy
|
||||
# matplotlib
|
||||
# numba
|
||||
# pandas
|
||||
# pandas-ta
|
||||
# ta-lib
|
||||
# yfinance
|
||||
packaging==25.0
|
||||
# via
|
||||
# bokeh
|
||||
# ipykernel
|
||||
# jupyter-events
|
||||
# jupyter-server
|
||||
# jupyterlab
|
||||
# jupyterlab-server
|
||||
# matplotlib
|
||||
# nbconvert
|
||||
# pytest
|
||||
pandas==2.3.2
|
||||
# via
|
||||
# bokeh
|
||||
# pandas-ta
|
||||
# yfinance
|
||||
pandocfilters==1.5.1
|
||||
# via nbconvert
|
||||
parso==0.8.5
|
||||
# via jedi
|
||||
peewee==3.18.2
|
||||
# via yfinance
|
||||
pexpect==4.9.0 ; sys_platform != 'emscripten' and sys_platform != 'win32'
|
||||
# via ipython
|
||||
pillow==11.3.0
|
||||
# via
|
||||
# bokeh
|
||||
# matplotlib
|
||||
platformdirs==4.3.8
|
||||
# via
|
||||
# jupyter-core
|
||||
# yfinance
|
||||
pluggy==1.6.0
|
||||
# via pytest
|
||||
prometheus-client==0.22.1
|
||||
# via jupyter-server
|
||||
prompt-toolkit==3.0.51
|
||||
# via ipython
|
||||
protobuf==6.32.0
|
||||
# via yfinance
|
||||
psutil==7.0.0
|
||||
# via ipykernel
|
||||
ptyprocess==0.7.0 ; os_name != 'nt' or (sys_platform != 'emscripten' and sys_platform != 'win32')
|
||||
# via
|
||||
# pexpect
|
||||
# terminado
|
||||
pure-eval==0.2.3
|
||||
# via stack-data
|
||||
pycparser==2.22
|
||||
# via cffi
|
||||
pygments==2.19.2
|
||||
# via
|
||||
# ipython
|
||||
# ipython-pygments-lexers
|
||||
# nbconvert
|
||||
# pytest
|
||||
pyparsing==3.2.3
|
||||
# via matplotlib
|
||||
pytest==8.4.1
|
||||
python-dateutil==2.9.0.post0
|
||||
# via
|
||||
# arrow
|
||||
# jupyter-client
|
||||
# matplotlib
|
||||
# pandas
|
||||
python-json-logger==3.3.0
|
||||
# via jupyter-events
|
||||
pytz==2025.2
|
||||
# via
|
||||
# pandas
|
||||
# yfinance
|
||||
pywin32==311 ; platform_python_implementation != 'PyPy' and sys_platform == 'win32'
|
||||
# via jupyter-core
|
||||
pywinpty==3.0.0 ; os_name == 'nt'
|
||||
# via
|
||||
# jupyter-server
|
||||
# jupyter-server-terminals
|
||||
# terminado
|
||||
pyyaml==6.0.2
|
||||
# via
|
||||
# bokeh
|
||||
# jupyter-events
|
||||
pyzmq==27.0.2
|
||||
# via
|
||||
# ipykernel
|
||||
# jupyter-client
|
||||
# jupyter-server
|
||||
referencing==0.36.2
|
||||
# via
|
||||
# jsonschema
|
||||
# jsonschema-specifications
|
||||
# jupyter-events
|
||||
requests==2.32.5
|
||||
# via
|
||||
# jupyterlab-server
|
||||
# yfinance
|
||||
rfc3339-validator==0.1.4
|
||||
# via
|
||||
# jsonschema
|
||||
# jupyter-events
|
||||
rfc3986-validator==0.1.1
|
||||
# via
|
||||
# jsonschema
|
||||
# jupyter-events
|
||||
rfc3987-syntax==1.1.0
|
||||
# via jsonschema
|
||||
rpds-py==0.27.0
|
||||
# via
|
||||
# jsonschema
|
||||
# referencing
|
||||
send2trash==1.8.3
|
||||
# via jupyter-server
|
||||
setuptools==80.9.0
|
||||
# via
|
||||
# jupyterlab
|
||||
# ta-lib
|
||||
six==1.17.0
|
||||
# via
|
||||
# python-dateutil
|
||||
# rfc3339-validator
|
||||
sniffio==1.3.1
|
||||
# via anyio
|
||||
soupsieve==2.7
|
||||
# via beautifulsoup4
|
||||
stack-data==0.6.3
|
||||
# via ipython
|
||||
ta-lib==0.6.4
|
||||
terminado==0.18.1
|
||||
# via
|
||||
# jupyter-server
|
||||
# jupyter-server-terminals
|
||||
tinycss2==1.4.0
|
||||
# via bleach
|
||||
tornado==6.5.2
|
||||
# via
|
||||
# bokeh
|
||||
# ipykernel
|
||||
# jupyter-client
|
||||
# jupyter-server
|
||||
# jupyterlab
|
||||
# terminado
|
||||
tqdm==4.67.1
|
||||
# via pandas-ta
|
||||
traitlets==5.14.3
|
||||
# via
|
||||
# ipykernel
|
||||
# ipython
|
||||
# jupyter-client
|
||||
# jupyter-core
|
||||
# jupyter-events
|
||||
# jupyter-server
|
||||
# jupyterlab
|
||||
# matplotlib-inline
|
||||
# nbclient
|
||||
# nbconvert
|
||||
# nbformat
|
||||
types-python-dateutil==2.9.0.20250822
|
||||
# via arrow
|
||||
typing-extensions==4.15.0
|
||||
# via
|
||||
# anyio
|
||||
# beautifulsoup4
|
||||
# referencing
|
||||
tzdata==2025.2
|
||||
# via pandas
|
||||
uri-template==1.3.0
|
||||
# via jsonschema
|
||||
urllib3==2.5.0
|
||||
# via requests
|
||||
wcwidth==0.2.13
|
||||
# via prompt-toolkit
|
||||
webcolors==24.11.1
|
||||
# via jsonschema
|
||||
webencodings==0.5.1
|
||||
# via
|
||||
# bleach
|
||||
# tinycss2
|
||||
websocket-client==1.8.0
|
||||
# via jupyter-server
|
||||
websockets==15.0.1
|
||||
# via yfinance
|
||||
xyzservices==2025.4.0
|
||||
# via bokeh
|
||||
yfinance==0.2.65
|
||||
@@ -1,383 +0,0 @@
|
||||
# This file was autogenerated by uv via the following command:
|
||||
# uv export --no-hashes -vn -o requirements.txt
|
||||
-e .
|
||||
anyio==4.10.0
|
||||
# via
|
||||
# httpx
|
||||
# jupyter-server
|
||||
appnope==0.1.4 ; sys_platform == 'darwin'
|
||||
# via ipykernel
|
||||
argon2-cffi==25.1.0
|
||||
# via jupyter-server
|
||||
argon2-cffi-bindings==21.2.0 ; python_full_version >= '3.14'
|
||||
# via argon2-cffi
|
||||
argon2-cffi-bindings==25.1.0 ; python_full_version < '3.14'
|
||||
# via argon2-cffi
|
||||
arrow==1.3.0
|
||||
# via isoduration
|
||||
asttokens==3.0.0
|
||||
# via stack-data
|
||||
async-lru==2.0.5
|
||||
# via jupyterlab
|
||||
attrs==25.3.0
|
||||
# via
|
||||
# jsonschema
|
||||
# referencing
|
||||
babel==2.17.0
|
||||
# via jupyterlab-server
|
||||
beautifulsoup4==4.13.5
|
||||
# via
|
||||
# nbconvert
|
||||
# yfinance
|
||||
bleach==6.2.0
|
||||
# via nbconvert
|
||||
bokeh==3.7.3
|
||||
certifi==2025.8.3
|
||||
# via
|
||||
# curl-cffi
|
||||
# httpcore
|
||||
# httpx
|
||||
# requests
|
||||
cffi==1.17.1
|
||||
# via
|
||||
# argon2-cffi-bindings
|
||||
# cryptography
|
||||
# curl-cffi
|
||||
# pyzmq
|
||||
charset-normalizer==3.4.3
|
||||
# via requests
|
||||
colorama==0.4.6 ; sys_platform == 'win32'
|
||||
# via
|
||||
# ipython
|
||||
# pytest
|
||||
# tqdm
|
||||
comm==0.2.3
|
||||
# via ipykernel
|
||||
contourpy==1.3.3
|
||||
# via
|
||||
# bokeh
|
||||
# matplotlib
|
||||
cryptography==45.0.6
|
||||
curl-cffi==0.13.0
|
||||
# via yfinance
|
||||
cycler==0.12.1
|
||||
# via matplotlib
|
||||
debugpy==1.8.16
|
||||
# via ipykernel
|
||||
decorator==5.2.1
|
||||
# via ipython
|
||||
defusedxml==0.7.1
|
||||
# via nbconvert
|
||||
executing==2.2.0
|
||||
# via stack-data
|
||||
fastjsonschema==2.21.2
|
||||
# via nbformat
|
||||
fonttools==4.59.1
|
||||
# via matplotlib
|
||||
fqdn==1.5.1
|
||||
# via jsonschema
|
||||
frozendict==2.4.6
|
||||
# via yfinance
|
||||
h11==0.16.0
|
||||
# via httpcore
|
||||
httpcore==1.0.9
|
||||
# via httpx
|
||||
httpx==0.28.1
|
||||
# via jupyterlab
|
||||
idna==3.10
|
||||
# via
|
||||
# anyio
|
||||
# httpx
|
||||
# jsonschema
|
||||
# requests
|
||||
iniconfig==2.1.0
|
||||
# via pytest
|
||||
ipykernel==6.30.1
|
||||
# via jupyterlab
|
||||
ipython==9.4.0
|
||||
# via ipykernel
|
||||
ipython-pygments-lexers==1.1.1
|
||||
# via ipython
|
||||
isoduration==20.11.0
|
||||
# via jsonschema
|
||||
jedi==0.19.2
|
||||
# via ipython
|
||||
jinja2==3.1.6
|
||||
# via
|
||||
# bokeh
|
||||
# jupyter-server
|
||||
# jupyterlab
|
||||
# jupyterlab-server
|
||||
# nbconvert
|
||||
json5==0.12.1
|
||||
# via jupyterlab-server
|
||||
jsonpointer==3.0.0
|
||||
# via jsonschema
|
||||
jsonschema==4.25.1
|
||||
# via
|
||||
# jupyter-events
|
||||
# jupyterlab-server
|
||||
# nbformat
|
||||
jsonschema-specifications==2025.4.1
|
||||
# via jsonschema
|
||||
jupyter-client==8.6.3
|
||||
# via
|
||||
# ipykernel
|
||||
# jupyter-server
|
||||
# nbclient
|
||||
jupyter-core==5.8.1
|
||||
# via
|
||||
# ipykernel
|
||||
# jupyter-client
|
||||
# jupyter-server
|
||||
# jupyterlab
|
||||
# nbclient
|
||||
# nbconvert
|
||||
# nbformat
|
||||
jupyter-events==0.12.0
|
||||
# via jupyter-server
|
||||
jupyter-lsp==2.2.6
|
||||
# via jupyterlab
|
||||
jupyter-server==2.17.0
|
||||
# via
|
||||
# jupyter-lsp
|
||||
# jupyterlab
|
||||
# jupyterlab-server
|
||||
# notebook-shim
|
||||
jupyter-server-terminals==0.5.3
|
||||
# via jupyter-server
|
||||
jupyterlab==4.4.6
|
||||
jupyterlab-pygments==0.3.0
|
||||
# via nbconvert
|
||||
jupyterlab-server==2.27.3
|
||||
# via jupyterlab
|
||||
kiwisolver==1.4.9
|
||||
# via matplotlib
|
||||
lark==1.2.2
|
||||
# via rfc3987-syntax
|
||||
llvmlite==0.44.0
|
||||
# via numba
|
||||
markupsafe==3.0.2
|
||||
# via
|
||||
# jinja2
|
||||
# nbconvert
|
||||
matplotlib==3.10.5
|
||||
matplotlib-inline==0.1.7
|
||||
# via
|
||||
# ipykernel
|
||||
# ipython
|
||||
mistune==3.1.3
|
||||
# via nbconvert
|
||||
multitasking==0.0.12
|
||||
# via yfinance
|
||||
narwhals==2.2.0
|
||||
# via bokeh
|
||||
nbclient==0.10.2
|
||||
# via nbconvert
|
||||
nbconvert==7.16.6
|
||||
# via jupyter-server
|
||||
nbformat==5.10.4
|
||||
# via
|
||||
# jupyter-server
|
||||
# nbclient
|
||||
# nbconvert
|
||||
nest-asyncio==1.6.0
|
||||
# via ipykernel
|
||||
notebook-shim==0.2.4
|
||||
# via jupyterlab
|
||||
numba==0.61.2
|
||||
# via pandas-ta
|
||||
numpy==2.2.6
|
||||
# via
|
||||
# bokeh
|
||||
# contourpy
|
||||
# matplotlib
|
||||
# numba
|
||||
# pandas
|
||||
# pandas-ta
|
||||
# ta-lib
|
||||
# yfinance
|
||||
packaging==25.0
|
||||
# via
|
||||
# bokeh
|
||||
# ipykernel
|
||||
# jupyter-events
|
||||
# jupyter-server
|
||||
# jupyterlab
|
||||
# jupyterlab-server
|
||||
# matplotlib
|
||||
# nbconvert
|
||||
# pytest
|
||||
pandas==2.3.2
|
||||
# via
|
||||
# bokeh
|
||||
# pandas-ta
|
||||
# yfinance
|
||||
pandocfilters==1.5.1
|
||||
# via nbconvert
|
||||
parso==0.8.5
|
||||
# via jedi
|
||||
peewee==3.18.2
|
||||
# via yfinance
|
||||
pexpect==4.9.0 ; sys_platform != 'emscripten' and sys_platform != 'win32'
|
||||
# via ipython
|
||||
pillow==11.3.0
|
||||
# via
|
||||
# bokeh
|
||||
# matplotlib
|
||||
platformdirs==4.3.8
|
||||
# via
|
||||
# jupyter-core
|
||||
# yfinance
|
||||
pluggy==1.6.0
|
||||
# via pytest
|
||||
prometheus-client==0.22.1
|
||||
# via jupyter-server
|
||||
prompt-toolkit==3.0.51
|
||||
# via ipython
|
||||
protobuf==6.32.0
|
||||
# via yfinance
|
||||
psutil==7.0.0
|
||||
# via ipykernel
|
||||
ptyprocess==0.7.0 ; os_name != 'nt' or (sys_platform != 'emscripten' and sys_platform != 'win32')
|
||||
# via
|
||||
# pexpect
|
||||
# terminado
|
||||
pure-eval==0.2.3
|
||||
# via stack-data
|
||||
pycparser==2.22
|
||||
# via cffi
|
||||
pygments==2.19.2
|
||||
# via
|
||||
# ipython
|
||||
# ipython-pygments-lexers
|
||||
# nbconvert
|
||||
# pytest
|
||||
pyparsing==3.2.3
|
||||
# via matplotlib
|
||||
pytest==8.4.1
|
||||
python-dateutil==2.9.0.post0
|
||||
# via
|
||||
# arrow
|
||||
# jupyter-client
|
||||
# matplotlib
|
||||
# pandas
|
||||
python-json-logger==3.3.0
|
||||
# via jupyter-events
|
||||
pytz==2025.2
|
||||
# via
|
||||
# pandas
|
||||
# yfinance
|
||||
pywin32==311 ; platform_python_implementation != 'PyPy' and sys_platform == 'win32'
|
||||
# via jupyter-core
|
||||
pywinpty==3.0.0 ; os_name == 'nt'
|
||||
# via
|
||||
# jupyter-server
|
||||
# jupyter-server-terminals
|
||||
# terminado
|
||||
pyyaml==6.0.2
|
||||
# via
|
||||
# bokeh
|
||||
# jupyter-events
|
||||
pyzmq==27.0.2
|
||||
# via
|
||||
# ipykernel
|
||||
# jupyter-client
|
||||
# jupyter-server
|
||||
referencing==0.36.2
|
||||
# via
|
||||
# jsonschema
|
||||
# jsonschema-specifications
|
||||
# jupyter-events
|
||||
requests==2.32.5
|
||||
# via
|
||||
# jupyterlab-server
|
||||
# yfinance
|
||||
rfc3339-validator==0.1.4
|
||||
# via
|
||||
# jsonschema
|
||||
# jupyter-events
|
||||
rfc3986-validator==0.1.1
|
||||
# via
|
||||
# jsonschema
|
||||
# jupyter-events
|
||||
rfc3987-syntax==1.1.0
|
||||
# via jsonschema
|
||||
rpds-py==0.27.0
|
||||
# via
|
||||
# jsonschema
|
||||
# referencing
|
||||
send2trash==1.8.3
|
||||
# via jupyter-server
|
||||
setuptools==80.9.0
|
||||
# via
|
||||
# jupyterlab
|
||||
# ta-lib
|
||||
six==1.17.0
|
||||
# via
|
||||
# python-dateutil
|
||||
# rfc3339-validator
|
||||
sniffio==1.3.1
|
||||
# via anyio
|
||||
soupsieve==2.7
|
||||
# via beautifulsoup4
|
||||
stack-data==0.6.3
|
||||
# via ipython
|
||||
ta-lib==0.6.4
|
||||
terminado==0.18.1
|
||||
# via
|
||||
# jupyter-server
|
||||
# jupyter-server-terminals
|
||||
tinycss2==1.4.0
|
||||
# via bleach
|
||||
tornado==6.5.2
|
||||
# via
|
||||
# bokeh
|
||||
# ipykernel
|
||||
# jupyter-client
|
||||
# jupyter-server
|
||||
# jupyterlab
|
||||
# terminado
|
||||
tqdm==4.67.1
|
||||
# via pandas-ta
|
||||
traitlets==5.14.3
|
||||
# via
|
||||
# ipykernel
|
||||
# ipython
|
||||
# jupyter-client
|
||||
# jupyter-core
|
||||
# jupyter-events
|
||||
# jupyter-server
|
||||
# jupyterlab
|
||||
# matplotlib-inline
|
||||
# nbclient
|
||||
# nbconvert
|
||||
# nbformat
|
||||
types-python-dateutil==2.9.0.20250822
|
||||
# via arrow
|
||||
typing-extensions==4.15.0
|
||||
# via
|
||||
# anyio
|
||||
# beautifulsoup4
|
||||
# referencing
|
||||
tzdata==2025.2
|
||||
# via pandas
|
||||
uri-template==1.3.0
|
||||
# via jsonschema
|
||||
urllib3==2.5.0
|
||||
# via requests
|
||||
wcwidth==0.2.13
|
||||
# via prompt-toolkit
|
||||
webcolors==24.11.1
|
||||
# via jsonschema
|
||||
webencodings==0.5.1
|
||||
# via
|
||||
# bleach
|
||||
# tinycss2
|
||||
websocket-client==1.8.0
|
||||
# via jupyter-server
|
||||
websockets==15.0.1
|
||||
# via yfinance
|
||||
xyzservices==2025.4.0
|
||||
# via bokeh
|
||||
yfinance==0.2.65
|
||||
@@ -1,65 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from importlib.metadata import version
|
||||
version = version("pandas-ta")
|
||||
|
||||
from pandas_ta.maps import EXCHANGE_TZ, RATE, Category, Imports
|
||||
from pandas_ta.utils import *
|
||||
from pandas_ta.utils import __all__ as utils_all
|
||||
|
||||
# Flat Structure. Supports ta.ema() or ta.overlap.ema()
|
||||
from pandas_ta.candle import *
|
||||
from pandas_ta.cycle import *
|
||||
from pandas_ta.momentum import *
|
||||
from pandas_ta.overlap import *
|
||||
from pandas_ta.performance import *
|
||||
from pandas_ta.statistics import *
|
||||
from pandas_ta.trend import *
|
||||
from pandas_ta.volatility import *
|
||||
from pandas_ta.volume import *
|
||||
from pandas_ta.candle import __all__ as candle_all
|
||||
from pandas_ta.cycle import __all__ as cycle_all
|
||||
from pandas_ta.momentum import __all__ as momentum_all
|
||||
from pandas_ta.overlap import __all__ as overlap_all
|
||||
from pandas_ta.performance import __all__ as performance_all
|
||||
from pandas_ta.statistics import __all__ as statistics_all
|
||||
from pandas_ta.trend import __all__ as trend_all
|
||||
from pandas_ta.volatility import __all__ as volatility_all
|
||||
from pandas_ta.volume import __all__ as volume_all
|
||||
|
||||
# Common Averages useful for Indicators
|
||||
# with a mamode argument, like ta.adx()
|
||||
from pandas_ta.ma import ma
|
||||
|
||||
# Custom External Directory Commands. See help(import_dir)
|
||||
from pandas_ta.custom import create_dir, import_dir
|
||||
|
||||
# Enable "ta" DataFrame Extension
|
||||
from pandas_ta.core import AnalysisIndicators
|
||||
|
||||
__all__ = [
|
||||
# "name",
|
||||
"EXCHANGE_TZ",
|
||||
"RATE",
|
||||
"Category",
|
||||
"Imports",
|
||||
"version",
|
||||
"ma",
|
||||
"create_dir",
|
||||
"import_dir",
|
||||
"AnalysisIndicators",
|
||||
"AllStudy",
|
||||
"CommonStudy",
|
||||
]
|
||||
|
||||
__all__ += [
|
||||
utils_all
|
||||
+ candle_all
|
||||
+ cycle_all
|
||||
+ momentum_all
|
||||
+ overlap_all
|
||||
+ performance_all
|
||||
+ statistics_all
|
||||
+ trend_all
|
||||
+ volatility_all
|
||||
+ volume_all
|
||||
]
|
||||
@@ -1,7 +0,0 @@
|
||||
#-*- coding: utf-8 -*-
|
||||
from pandas_ta import version
|
||||
|
||||
SUPPORT="http://www.pandas-ta.dev/support"
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(f"Pandas TA: {version}\nSupport: {SUPPORT}")
|
||||
@@ -1,71 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pathlib import Path
|
||||
from typing import (
|
||||
Any,
|
||||
Dict,
|
||||
Iterable,
|
||||
List,
|
||||
Optional,
|
||||
Sequence,
|
||||
TextIO,
|
||||
Tuple,
|
||||
TypeVar,
|
||||
Union
|
||||
)
|
||||
|
||||
from numpy import ndarray, recarray, void
|
||||
from numpy import bool_ as np_bool_
|
||||
from numpy import floating as np_floating
|
||||
from numpy import generic as np_generic
|
||||
from numpy import integer as np_integer
|
||||
from numpy import number as np_number
|
||||
from pandas import DataFrame, Series
|
||||
|
||||
|
||||
|
||||
# Generic types
|
||||
T = TypeVar("T")
|
||||
|
||||
# Scalars
|
||||
Scalar = Union[str, float, int, complex, bool, object, np_generic]
|
||||
Number = Union[int, float, complex, np_number, np_bool_]
|
||||
Int = Union[int, np_integer]
|
||||
Float = Union[float, np_floating]
|
||||
IntFloat = Union[Int, Float]
|
||||
|
||||
# Basic sequences
|
||||
MaybeTuple = Union[T, Tuple[T, ...]]
|
||||
MaybeList = Union[T | List[T]]
|
||||
TupleList = Union[List[T], Tuple[T, ...]]
|
||||
MaybeTupleList = Union[T, List[T], Tuple[T, ...]]
|
||||
MaybeIterable = Union[T, Iterable[T]]
|
||||
MaybeSequence = Union[T, Sequence[T]]
|
||||
ListStr = List[str]
|
||||
|
||||
DictLike = Union[None, dict]
|
||||
DictLikeSequence = MaybeSequence[DictLike]
|
||||
Args = Tuple[Any, ...]
|
||||
ArgsLike = Union[None, Args]
|
||||
Kwargs = Dict[str, Any]
|
||||
KwargsLike = Union[None, Kwargs]
|
||||
KwargsLikeSequence = MaybeSequence[KwargsLike]
|
||||
FileName = Union[str, Path]
|
||||
|
||||
DTypeLike = Any
|
||||
PandasDTypeLike = Any
|
||||
Shape = Tuple[int, ...]
|
||||
RelaxedShape = Union[int, Shape]
|
||||
Array = ndarray
|
||||
Array1d = ndarray
|
||||
Array2d = ndarray
|
||||
Array3d = ndarray
|
||||
Record = void
|
||||
RecordArray = ndarray
|
||||
RecArray = recarray
|
||||
MaybeArray = Union[T, Array]
|
||||
SeriesFrame = Union[Series, DataFrame]
|
||||
MaybeSeries = Union[T, Series]
|
||||
MaybeSeriesFrame = Union[T, Series, DataFrame]
|
||||
AnyArray = Union[Array, Series, DataFrame]
|
||||
AnyArray1d = Union[Array1d, Series]
|
||||
AnyArray2d = Union[Array2d, DataFrame]
|
||||
@@ -1,16 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from .cdl_doji import cdl_doji
|
||||
from .cdl_inside import cdl_inside
|
||||
from .cdl_pattern import cdl_pattern, cdl, ALL_PATTERNS as CDL_PATTERN_NAMES
|
||||
from .cdl_z import cdl_z
|
||||
from .ha import ha
|
||||
|
||||
__all__ = [
|
||||
"cdl_doji",
|
||||
"cdl_inside",
|
||||
"cdl_pattern",
|
||||
"cdl",
|
||||
"CDL_PATTERN_NAMES",
|
||||
"cdl_z",
|
||||
"ha",
|
||||
]
|
||||
@@ -1,90 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import Series
|
||||
from pandas_ta.overlap import sma
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.utils import high_low_range, v_percent
|
||||
from pandas_ta.utils import real_body, v_offset, v_pos_default
|
||||
from pandas_ta.utils import v_bool, v_scalar, v_series
|
||||
|
||||
|
||||
|
||||
def cdl_doji(
|
||||
open_: Series, high: Series, low: Series, close: Series,
|
||||
length: Int = None, factor: IntFloat = None,
|
||||
scalar: IntFloat = None, asint: bool = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Doji
|
||||
|
||||
Attempts to identify a "Doji" candle which is shorter than 10% of
|
||||
the average of the 10 previous bars High-Low range.
|
||||
|
||||
Sources:
|
||||
* [TA Lib](https://github.com/TA-Lib/ta-lib/blob/main/src/ta_func/ta_CDLDOJI.c)
|
||||
|
||||
Parameters:
|
||||
open_ (Series): ```open``` Series
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```10```
|
||||
factor (float): Doji value. Default: ```100```
|
||||
scalar (float): Scalar. Default: ```100```
|
||||
asint (bool): Returns as ```Int```. Default: ```True```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
naive (bool): Prefills potential Doji; bodies that are less
|
||||
than a percentage, ```factor```, of it's High-Low range.
|
||||
Default: ```False```
|
||||
fillna (value): Replaces ```na```'s with ```value```.
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
|
||||
Warning:
|
||||
TA-Lib Correlation: ```np.float64(0.9434563530497265)```
|
||||
|
||||
Tip:
|
||||
Corrective contributions welcome!
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 10)
|
||||
open_ = v_series(open_, length)
|
||||
high = v_series(high, length)
|
||||
low = v_series(low, length)
|
||||
close = v_series(close, length)
|
||||
|
||||
if open_ is None or high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
factor = v_scalar(factor, 10) if v_percent(factor) else 10
|
||||
scalar = v_scalar(scalar, 100)
|
||||
asint = v_bool(asint, True)
|
||||
offset = v_offset(offset)
|
||||
naive = kwargs.pop("naive", False)
|
||||
|
||||
# Calculate
|
||||
body = real_body(open_, close).abs()
|
||||
hl_range = high_low_range(high, low).abs()
|
||||
hl_range_avg = sma(hl_range, length)
|
||||
doji = body < 0.01 * factor * hl_range_avg
|
||||
|
||||
if naive:
|
||||
doji.iat[:length] = body < 0.01 * factor * hl_range
|
||||
if asint:
|
||||
doji = scalar * doji.astype(int)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
doji = doji.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
doji.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
doji.name = f"CDL_DOJI_{length}_{0.01 * factor}"
|
||||
doji.category = "candle"
|
||||
|
||||
return doji
|
||||
@@ -1,84 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numba import njit
|
||||
from numpy import roll, where
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.utils import (
|
||||
v_bool,
|
||||
v_offset,
|
||||
v_offset,
|
||||
v_scalar,
|
||||
v_series
|
||||
)
|
||||
|
||||
|
||||
|
||||
@njit(cache=True)
|
||||
def np_cdl_inside(high, low):
|
||||
hdiff = where(high - roll(high, 1) < 0, 1, 0)
|
||||
ldiff = where(low - roll(low, 1) > 0, 1, 0)
|
||||
return hdiff & ldiff
|
||||
|
||||
|
||||
def cdl_inside(
|
||||
open_: Series, high: Series, low: Series, close: Series,
|
||||
asbool: bool = None, scalar: IntFloat = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Inside Bar
|
||||
|
||||
Attempts to identify an "Inside" candle which is smaller than it's
|
||||
previous candle.
|
||||
|
||||
Sources:
|
||||
* [TA Lib](https://github.com/TA-Lib/ta-lib/blob/main/src/ta_func/ta_CDL3INSIDE.c)
|
||||
* [tradingview](https://www.tradingview.com/script/IyIGN1WO-Inside-Bar/)
|
||||
|
||||
Parameters:
|
||||
open_ (Series): ```open``` Series
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
close (Series): ```close``` Series
|
||||
asbool (bool): Return booleans. Default: ```False```
|
||||
scalar (float): Scalar. Default: ```100```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): Replaces ```na```'s with ```value```.
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
open_ = v_series(open_)
|
||||
high = v_series(high)
|
||||
low = v_series(low)
|
||||
close = v_series(close)
|
||||
|
||||
if open_ is None or high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
asbool = v_bool(asbool, False)
|
||||
scalar = v_scalar(scalar, 100)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
np_high, np_low = high.to_numpy(), low.to_numpy()
|
||||
np_inside = np_cdl_inside(np_high, np_low)
|
||||
inside = Series(np_inside, index=close.index, dtype=bool)
|
||||
|
||||
if not asbool:
|
||||
inside = scalar * inside.astype(int)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
inside = inside.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
inside.fillna(kwargs["fillna"], inplace=True)
|
||||
# Name and Category
|
||||
inside.name = f"CDL_INSIDE"
|
||||
inside.category = "candle"
|
||||
|
||||
return inside
|
||||
@@ -1,126 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import Series, DataFrame
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat, List
|
||||
from pandas_ta.maps import Imports
|
||||
from pandas_ta.utils import v_offset, v_scalar, v_series
|
||||
from pandas_ta.candle import cdl_doji, cdl_inside
|
||||
|
||||
|
||||
|
||||
ALL_PATTERNS = [
|
||||
"2crows", "3blackcrows", "3inside", "3linestrike", "3outside",
|
||||
"3starsinsouth", "3whitesoldiers", "abandonedbaby", "advanceblock",
|
||||
"belthold", "breakaway", "closingmarubozu", "concealbabyswall",
|
||||
"counterattack", "darkcloudcover", "doji", "dojistar", "dragonflydoji",
|
||||
"engulfing", "eveningdojistar", "eveningstar", "gapsidesidewhite",
|
||||
"gravestonedoji", "hammer", "hangingman", "harami", "haramicross",
|
||||
"highwave", "hikkake", "hikkakemod", "homingpigeon", "identical3crows",
|
||||
"inneck", "inside", "invertedhammer", "kicking", "kickingbylength",
|
||||
"ladderbottom", "longleggeddoji", "longline", "marubozu", "matchinglow",
|
||||
"mathold", "morningdojistar", "morningstar", "onneck", "piercing",
|
||||
"rickshawman", "risefall3methods", "separatinglines", "shootingstar",
|
||||
"shortline", "spinningtop", "stalledpattern", "sticksandwich", "takuri",
|
||||
"tasukigap", "thrusting", "tristar", "unique3river", "upsidegap2crows",
|
||||
"xsidegap3methods"
|
||||
]
|
||||
|
||||
|
||||
def cdl_pattern(
|
||||
open_: Series, high: Series, low: Series, close: Series,
|
||||
name: str | List[str] = "all",
|
||||
scalar: IntFloat = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> DataFrame:
|
||||
"""Candle Pattern
|
||||
|
||||
This function wraps TA Lib candle patterns.
|
||||
|
||||
Sources:
|
||||
* [TA Lib](https://ta-lib.org)
|
||||
|
||||
Parameters:
|
||||
open_ (Series): ```open``` Series
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
close (Series): ```close``` Series
|
||||
name (str | List[str]): Pattern name or a list of pattern names.
|
||||
Default: ```"all"```
|
||||
scalar (float): Scalar. Default: ```100```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): Replaces ```na```'s with ```value```.
|
||||
|
||||
Returns:
|
||||
(DataFrame): Pattern Column(s)
|
||||
|
||||
Warning: TA Lib
|
||||
TA Lib must be installed
|
||||
"""
|
||||
# Validate Arguments
|
||||
open_ = v_series(open_, 1)
|
||||
high = v_series(high, 1)
|
||||
low = v_series(low, 1)
|
||||
close = v_series(close, 1)
|
||||
|
||||
if open_ is None or high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
offset = v_offset(offset)
|
||||
scalar = v_scalar(scalar, 100)
|
||||
|
||||
pta_patterns = {"doji": cdl_doji, "inside": cdl_inside}
|
||||
|
||||
if name == "all":
|
||||
name = ALL_PATTERNS
|
||||
|
||||
if isinstance(name, str):
|
||||
name = [name]
|
||||
|
||||
if Imports["talib"]:
|
||||
import talib.abstract as tala
|
||||
|
||||
result = {}
|
||||
for n in name:
|
||||
if n not in ALL_PATTERNS:
|
||||
print(f"[X] There is no candle pattern named {n} available!")
|
||||
continue
|
||||
|
||||
if n in pta_patterns:
|
||||
pattern_result = pta_patterns[n](
|
||||
open_, high, low, close, offset=offset, scalar=scalar, **kwargs
|
||||
)
|
||||
if not isinstance(pattern_result, Series):
|
||||
continue
|
||||
result[pattern_result.name] = pattern_result
|
||||
|
||||
else:
|
||||
if not Imports["talib"]:
|
||||
print(f"[i] Requires TA-Lib to use {n}. (pip install TA-Lib)")
|
||||
continue
|
||||
|
||||
pf = tala.Function(f"CDL{n.upper()}")
|
||||
pattern_result = Series(
|
||||
0.01 * scalar * pf(open_, high, low, close, **kwargs)
|
||||
)
|
||||
pattern_result.index = close.index
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
pattern_result = pattern_result.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
pattern_result.fillna(kwargs["fillna"], inplace=True)
|
||||
result[f"CDL_{n.upper()}"] = pattern_result
|
||||
|
||||
if len(result) == 0:
|
||||
return
|
||||
|
||||
# Name and Category
|
||||
df = DataFrame(result)
|
||||
df.name = "CDL_PATTERN"
|
||||
df.category = "candle"
|
||||
return df
|
||||
|
||||
cdl = cdl_pattern # Alias
|
||||
@@ -1,93 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.statistics import zscore
|
||||
from pandas_ta.utils import v_bool, v_offset, v_pos_default, v_series
|
||||
|
||||
|
||||
|
||||
def cdl_z(
|
||||
open_: Series, high: Series, low: Series, close: Series,
|
||||
length: Int = None, full: bool = None, ddof: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> DataFrame:
|
||||
"""Z Candles
|
||||
|
||||
Creates candlesticks using a rolling Z Score.
|
||||
|
||||
Sources:
|
||||
* Kevin Johnson
|
||||
|
||||
Parameters:
|
||||
open_ (Series): ```open``` Series
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```10```
|
||||
full (bool): Apply ```length``` to whole DataFrame.
|
||||
Default: ```False```
|
||||
ddof (int): By default, uses Pandas ```ddof=1```.
|
||||
For Numpy calculation, use ```0```. Default: ```1```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
naive (bool): If ```True```, prefills potential Doji less
|
||||
than the length if it less than a percentage of it's
|
||||
High-Low range. Default: ```False```
|
||||
fillna (value): Replaces ```na```'s with ```value```.
|
||||
|
||||
Returns:
|
||||
(DataFrame): 4 columns
|
||||
|
||||
Note:
|
||||
* Numpy ```std()``` [ddof](https://numpy.org/doc/stable/reference/generated/numpy.std.html) explanation.
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 30)
|
||||
open_ = v_series(open_, length)
|
||||
high = v_series(high, length)
|
||||
low = v_series(low, length)
|
||||
close = v_series(close, length)
|
||||
|
||||
if open_ is None or high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
full = v_bool(full, False)
|
||||
ddof = int(ddof) if isinstance(ddof, int) and 0 <= ddof < length else 1
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
if full:
|
||||
length = close.size
|
||||
|
||||
z_open = zscore(open_, length=length, ddof=ddof)
|
||||
z_high = zscore(high, length=length, ddof=ddof)
|
||||
z_low = zscore(low, length=length, ddof=ddof)
|
||||
z_close = zscore(close, length=length, ddof=ddof)
|
||||
|
||||
_full = "a" if full else ""
|
||||
_props = _full if full else f"_{length}_{ddof}"
|
||||
data = {
|
||||
f"open_Z{_props}": z_open,
|
||||
f"high_Z{_props}": z_high,
|
||||
f"low_Z{_props}": z_low,
|
||||
f"close_Z{_props}": z_close,
|
||||
}
|
||||
df = DataFrame(data, index=close.index)
|
||||
|
||||
if full:
|
||||
df.fillna(method="backfill", axis=0, inplace=True)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
df = df.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
df.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
df.name = f"CDL_Z{_props}"
|
||||
df.category = "candle"
|
||||
|
||||
return df
|
||||
@@ -1,86 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numba import njit
|
||||
from numpy import empty_like, maximum, minimum
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.utils import v_offset, v_series
|
||||
|
||||
|
||||
|
||||
@njit(cache=True)
|
||||
def np_ha(np_open, np_high, np_low, np_close):
|
||||
ha_close = 0.25 * (np_open + np_high + np_low + np_close)
|
||||
ha_open = empty_like(ha_close)
|
||||
ha_open[0] = 0.5 * (np_open[0] + np_close[0])
|
||||
|
||||
m = np_close.size
|
||||
for i in range(1, m):
|
||||
ha_open[i] = 0.5 * (ha_open[i - 1] + ha_close[i - 1])
|
||||
|
||||
ha_high = maximum(maximum(ha_open, ha_close), np_high)
|
||||
ha_low = minimum(minimum(ha_open, ha_close), np_low)
|
||||
|
||||
return ha_open, ha_high, ha_low, ha_close
|
||||
|
||||
|
||||
def ha(
|
||||
open_: Series, high: Series, low: Series, close: Series,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> DataFrame:
|
||||
"""Heikin Ashi Candles
|
||||
|
||||
Creates Japanese _ohlc_ candlesticks that attempts to filter out market
|
||||
noise. Developed by Munehisa Homma in the 1700s, Heikin Ashi Candles share
|
||||
some characteristics with standard candlestick charts but creates a
|
||||
smoother candlestick appearance.
|
||||
|
||||
Sources:
|
||||
* [Investopedia](https://www.investopedia.com/terms/h/heikinashi.asp)
|
||||
|
||||
Parameters:
|
||||
open_ (Series): ```open``` Series
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
close (Series): ```close``` Series
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): Replaces ```na```'s with ```value```.
|
||||
|
||||
Returns:
|
||||
(DataFrame): 4 columns
|
||||
"""
|
||||
# Validate
|
||||
open_ = v_series(open_, 1)
|
||||
high = v_series(high, 1)
|
||||
low = v_series(low, 1)
|
||||
close = v_series(close, 1)
|
||||
offset = v_offset(offset)
|
||||
|
||||
if open_ is None or high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
# Calculate
|
||||
np_open, np_high = open_.to_numpy(), high.to_numpy()
|
||||
np_low, np_close = low.to_numpy(), close.to_numpy()
|
||||
ha_open, ha_high, ha_low, ha_close = np_ha(np_open, np_high, np_low, np_close)
|
||||
df = DataFrame({
|
||||
"HA_open": ha_open,
|
||||
"HA_high": ha_high,
|
||||
"HA_low": ha_low,
|
||||
"HA_close": ha_close,
|
||||
}, index=close.index)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
df = df.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
df.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
df.name = "Heikin-Ashi"
|
||||
df.category = "candle"
|
||||
|
||||
return df
|
||||
@@ -1,177 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import importlib
|
||||
import os
|
||||
import sys
|
||||
import types
|
||||
from glob import glob
|
||||
from os.path import abspath, basename, exists, join, splitext
|
||||
|
||||
import pandas_ta
|
||||
from pandas_ta._typing import DictLike
|
||||
|
||||
|
||||
|
||||
def bind(name: str, fn: types.FunctionType, method: types.MethodType = None):
|
||||
"""Bind
|
||||
|
||||
Helper function to bind the function and class method defined in a custom
|
||||
indicator module to the active pandas_ta instance.
|
||||
|
||||
Parameters:
|
||||
name (str): The name of the indicator within pandas_ta
|
||||
fn (types.FunctionType): The indicator function
|
||||
method (types.MethodType): The class method corresponding to the passed function
|
||||
"""
|
||||
setattr(pandas_ta, name, fn)
|
||||
setattr(pandas_ta.AnalysisIndicators, name, method)
|
||||
|
||||
|
||||
def create_dir(path: str, categories: bool = True, verbose: bool = True):
|
||||
"""Create Dir
|
||||
|
||||
Sets up a suitable folder structure for working with custom indicators.
|
||||
Use it **once** to setup and initialize the custom folder.
|
||||
|
||||
Parameters:
|
||||
path (str): Indicator directory full path
|
||||
categories (bool): Create category sub-folders
|
||||
verbose (bool): Verbose output
|
||||
"""
|
||||
|
||||
# ensure that the passed directory exists / is readable
|
||||
if not exists(path):
|
||||
os.makedirs(path)
|
||||
if verbose:
|
||||
print(f"[i] Created main directory '{path}'.")
|
||||
|
||||
# list the contents of the directory
|
||||
# dirs = glob(abspath(join(path, '*')))
|
||||
|
||||
# optionally add any missing category subdirectories
|
||||
if categories:
|
||||
for _ in [*pandas_ta.Category]:
|
||||
d = abspath(join(path, _))
|
||||
if not exists(d):
|
||||
os.makedirs(d)
|
||||
if verbose:
|
||||
dirname = basename(d)
|
||||
print(f"[i] Created an empty sub-directory '{dirname}'.")
|
||||
|
||||
|
||||
def get_module_functions(module: types.ModuleType) -> DictLike:
|
||||
"""Get Module Functions
|
||||
|
||||
Returns a dictionary with the mapping: "name" to a _function_.
|
||||
|
||||
Parameters:
|
||||
module (types.ModuleType): python module
|
||||
|
||||
Returns:
|
||||
(DictLike): Returns a dictionary with the mapping: "name" to a _function_
|
||||
|
||||
Example:
|
||||
Example return
|
||||
```py
|
||||
{
|
||||
"func1_name": func1,
|
||||
"func2_name": func2, # ...
|
||||
}
|
||||
```
|
||||
"""
|
||||
module_functions = {}
|
||||
|
||||
for name, item in vars(module).items():
|
||||
if isinstance(item, types.FunctionType):
|
||||
module_functions[name] = item
|
||||
|
||||
return module_functions
|
||||
|
||||
|
||||
def import_dir(path: str, verbose: bool = True):
|
||||
"""Import Dir
|
||||
|
||||
Import a directory of custom (proprietary) indicators into Pandas TA.
|
||||
|
||||
Parameters:
|
||||
path (str): Full path to indicator directory.
|
||||
verbose (bool): Output process to STDOUT.
|
||||
"""
|
||||
# ensure that the passed directory exists / is readable
|
||||
if not exists(path):
|
||||
print(f"[X] Unable to read the directory '{path}'.")
|
||||
return
|
||||
|
||||
# list the contents of the directory
|
||||
dirs = glob(abspath(join(path, "*")))
|
||||
|
||||
# traverse full directory, importing all modules found there
|
||||
for d in dirs:
|
||||
dirname = basename(d)
|
||||
|
||||
# only look in directories which are valid pandas_ta categories
|
||||
if dirname not in [*pandas_ta.Category]:
|
||||
if verbose and dirname not in ["__pycache__", "__init__.py"]:
|
||||
print(
|
||||
f"[i] Skipping the sub-directory '{dirname}' since it's not a valid pandas_ta category."
|
||||
)
|
||||
continue
|
||||
|
||||
# for each module found in that category (directory)...
|
||||
for module in glob(abspath(join(path, dirname, "*.py"))):
|
||||
module_name = splitext(basename(module))[0]
|
||||
if module_name not in ["__init__"]:
|
||||
# ensure that the supplied path is included in our python path
|
||||
if d not in sys.path:
|
||||
sys.path.append(d)
|
||||
|
||||
# (re)load the indicator module
|
||||
module_functions = load_indicator_module(module_name)
|
||||
|
||||
# figure out which of the modules functions to bind to pandas_ta
|
||||
_callable = module_functions.get(module_name, None)
|
||||
_method_callable = module_functions.get(f"{module_name}_method", None)
|
||||
|
||||
if _callable == None:
|
||||
print(
|
||||
f"[X] Unable to find a function named '{module_name}' in the module '{module_name}.py'."
|
||||
)
|
||||
continue
|
||||
if _method_callable == None:
|
||||
missing_method = f"{module_name}_method"
|
||||
print(
|
||||
f"[X] Unable to find a method function named '{missing_method}' in the module '{module_name}.py'."
|
||||
)
|
||||
continue
|
||||
|
||||
# add it to the correct category if it's not there yet
|
||||
if module_name not in pandas_ta.Category[dirname]:
|
||||
pandas_ta.Category[dirname].append(module_name)
|
||||
|
||||
bind(module_name, _callable, _method_callable)
|
||||
if verbose:
|
||||
print(
|
||||
f"[i] Successfully imported the custom indicator '{module}' into category '{dirname}'."
|
||||
)
|
||||
|
||||
|
||||
def load_indicator_module(name: str) -> dict:
|
||||
"""
|
||||
Helper function to (re)load an indicator module.
|
||||
|
||||
Returns:
|
||||
dict: module functions mapping
|
||||
```{
|
||||
"func1_name": func1,
|
||||
"func2_name": func2, # ...
|
||||
}```
|
||||
|
||||
"""
|
||||
try:
|
||||
module = importlib.import_module(name)
|
||||
except Exception as ex:
|
||||
print(f"[X] An error occurred when attempting to load module {name}: {ex}")
|
||||
sys.exit(1)
|
||||
|
||||
# reload to refresh previously loaded module
|
||||
module = importlib.reload(module)
|
||||
return get_module_functions(module)
|
||||
@@ -1,8 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from .ebsw import ebsw
|
||||
from .reflex import reflex
|
||||
|
||||
__all__ = [
|
||||
"ebsw",
|
||||
"reflex",
|
||||
]
|
||||
@@ -1,142 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import cos, exp, mean, nan, pi, roll, sin, sqrt, zeros
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.utils import v_bool, v_offset, v_pos_default, v_series
|
||||
|
||||
|
||||
|
||||
def ebsw(
|
||||
close: Series, length: Int = None, bars: Int = None,
|
||||
initial_version: bool = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Even Better SineWave
|
||||
|
||||
This indicator attempts to quantify market cycles using a low pass filter.
|
||||
|
||||
Sources:
|
||||
* [rengel8](https://github.com/rengel8)
|
||||
* J.F.Ehlers 'Cycle Analytics for Traders', 2014
|
||||
* [Pandas TA Issue #350](https://github.com/twopirllc/pandas-ta/issues/350)
|
||||
* [Proreal Code](https://www.prorealcode.com/prorealtime-indicators/even-better-sinewave/)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
length (int): Max cycle/trend period. Values between ```40-48``` work
|
||||
as expected with minimum value: ```39```. Default: ```40```
|
||||
bars (int): Period of low pass filtering. Default: ```10```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): Replaces ```na```'s with ```value```.
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
|
||||
Note:
|
||||
The _default_ is more cycle oriented and seems to be less
|
||||
whipsaw-prune. The older version might offer earlier signals at medium
|
||||
and stronger reversals. Compared to TradingView, returns very close
|
||||
results but appears to be one bar earlier.
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 40)
|
||||
close = v_series(close, length)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
initial_version = v_bool(initial_version, False)
|
||||
bars = v_pos_default(bars, 10)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
# allow initial version to be used (more responsive/caution!)
|
||||
m = close.size
|
||||
if isinstance(initial_version, bool) and initial_version:
|
||||
# not the default version that is active
|
||||
alpha1 = hp = 0 # alpha and HighPass
|
||||
a1 = b1 = c1 = c2 = c3 = 0
|
||||
filter_ = power_ = wave = 0
|
||||
lastClose = lastHP = 0
|
||||
filtHist = [0, 0] # Filter history
|
||||
|
||||
result = [nan for _ in range(0, length - 1)] + [0]
|
||||
for i in range(length, m):
|
||||
# HighPass filter cyclic components whose periods are shorter than
|
||||
# Duration input
|
||||
alpha1 = (1 - sin(360 / length)) / cos(360 / length)
|
||||
hp = 0.5 * (1 + alpha1) * (close.iloc[i] - lastClose) + alpha1 * lastHP
|
||||
|
||||
# Smooth with a Super Smoother Filter from equation 3-3
|
||||
a1 = exp(-sqrt(2) * pi / bars)
|
||||
b1 = 2 * a1 * cos(sqrt(2) * 180 / bars)
|
||||
c2 = b1
|
||||
c3 = -1 * a1 * a1
|
||||
c1 = 1 - c2 - c3
|
||||
filter_ = 0.5 * c1 * (hp + lastHP) + c2 * \
|
||||
filtHist[1] + c3 * filtHist[0]
|
||||
# filter_ = float("{:.8f}".format(float(filter_))) # to fix for
|
||||
# small scientific notations, the big ones fail
|
||||
|
||||
# 3 Bar average of wave amplitude and power
|
||||
wave = (filter_ + filtHist[1] + filtHist[0]) / 3
|
||||
power_ = (filter_ * filter_ + filtHist[1] * filtHist[1] \
|
||||
+ filtHist[0] * filtHist[0]) / 3
|
||||
# Normalize the Average Wave to Square Root of the Average Power
|
||||
wave = wave / sqrt(power_)
|
||||
|
||||
# update storage, result
|
||||
filtHist.append(filter_) # append new filter_ value
|
||||
# remove first element of list (left) -> updating/trim
|
||||
filtHist.pop(0)
|
||||
lastHP = hp
|
||||
lastClose = close.iloc[i]
|
||||
result.append(wave)
|
||||
|
||||
else: # Default
|
||||
lastHP = lastClose = 0
|
||||
filtHist = zeros(3)
|
||||
result = [nan] * (length - 1) + [0]
|
||||
|
||||
angle = 2 * pi / length
|
||||
alpha1 = (1 - sin(angle)) / cos(angle)
|
||||
ang = 2 ** .5 * pi / bars
|
||||
a1 = exp(-ang)
|
||||
c2 = 2 * a1 * cos(ang)
|
||||
c3 = -a1 ** 2
|
||||
c1 = 1 - c2 - c3
|
||||
|
||||
for i in range(length, m):
|
||||
hp = 0.5 * (1 + alpha1) * (close.iloc[i] - lastClose) + alpha1 * lastHP
|
||||
|
||||
# Rotate filters to overwrite oldest value
|
||||
filtHist = roll(filtHist, -1)
|
||||
filtHist[-1] = 0.5 * c1 * \
|
||||
(hp + lastHP) + c2 * filtHist[1] + c3 * filtHist[0]
|
||||
|
||||
# Wave calculation
|
||||
wave = mean(filtHist)
|
||||
rms = sqrt(mean(filtHist ** 2))
|
||||
wave = wave / rms
|
||||
|
||||
# Update past values
|
||||
lastHP = hp
|
||||
lastClose = close.iloc[i]
|
||||
result.append(wave)
|
||||
|
||||
ebsw = Series(result, index=close.index)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
ebsw = ebsw.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
ebsw.fillna(kwargs["fillna"], inplace=True)
|
||||
# Name and Category
|
||||
ebsw.name = f"EBSW_{length}_{bars}"
|
||||
ebsw.category = "cycle"
|
||||
|
||||
return ebsw
|
||||
@@ -1,115 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numba import njit
|
||||
from numpy import cos, exp, nan, sqrt, zeros_like
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.utils import v_offset, v_pos_default, v_series
|
||||
|
||||
|
||||
|
||||
@njit(cache=True)
|
||||
def np_reflex(x, n, k, alpha, pi, sqrt2):
|
||||
m, ratio = x.size, 2 * sqrt2 / k
|
||||
a = exp(-pi * ratio)
|
||||
b = 2 * a * cos(180 * ratio)
|
||||
c = a * a - b + 1
|
||||
|
||||
_f = zeros_like(x)
|
||||
_ms = zeros_like(x)
|
||||
result = zeros_like(x)
|
||||
|
||||
for i in range(2, m):
|
||||
_f[i] = 0.5 * c * (x[i] + x[i - 1]) + b * _f[i - 1] - a * a * _f[i - 2]
|
||||
|
||||
for i in range(n, m):
|
||||
slope = (_f[i - n] - _f[i]) / n
|
||||
|
||||
_sum = 0
|
||||
for j in range(1, n):
|
||||
_sum += _f[i] - _f[i - j] + j * slope
|
||||
_sum /= n
|
||||
|
||||
_ms[i] = alpha * _sum * _sum + (1 - alpha) * _ms[i - 1]
|
||||
if _ms[i] != 0.0:
|
||||
result[i] = _sum / sqrt(_ms[i])
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def reflex(
|
||||
close: Series, length: Int = None,
|
||||
smooth: Int = None, alpha: IntFloat = None,
|
||||
pi: IntFloat = None, sqrt2: IntFloat = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Reflex
|
||||
|
||||
This cycle indicator, by John F. Ehlers, attempts to reduce lag.
|
||||
|
||||
Sources:
|
||||
* [rengel8](https://github.com/rengel8) (2021-08-11) based on the
|
||||
implementation from "ProRealCode"
|
||||
* [traders.com](http://traders.com/Documentation/FEEDbk_docs/2020/02/TradersTips.html)
|
||||
* [prorealcode](https://www.prorealcode.com/prorealtime-indicators/reflex-and-trendflex-indicators-john-f-ehlers/)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```20```
|
||||
smooth (int): SuperSmoother period. Default: ```20```
|
||||
alpha (float): Alpha weight of Difference Sums. Default: ```0.04```
|
||||
pi (float): Ehlers's truncated value: ```3.14159```.
|
||||
Default: ```3.14159```
|
||||
sqrt2 (float): Ehlers's truncated value: ```1.414```.
|
||||
Default: ```1.414```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): Replaces ```na```'s with ```value```.
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
|
||||
Tip:
|
||||
This implementation has a separate control parameter for the
|
||||
internal applied SuperSmoother.
|
||||
|
||||
Note:
|
||||
John F. Ehlers introduced two indicators within the article
|
||||
"Reflex: A New Zero-Lag Indicator” in February 2020, TASC magazine.
|
||||
One of which is Reflex, a lag reduced cycle indicator. Both indicators
|
||||
(Reflex/Trendflex) are oscillators that complement each other with the
|
||||
focus for cycle and trend.
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 20)
|
||||
smooth = v_pos_default(smooth, 20)
|
||||
_length = max(length, smooth) + 1
|
||||
close = v_series(close, _length)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
alpha = v_pos_default(alpha, 0.04)
|
||||
pi = v_pos_default(pi, 3.14159)
|
||||
sqrt2 = v_pos_default(sqrt2, 1.414)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
np_close = close.to_numpy()
|
||||
result = np_reflex(np_close, length, smooth, alpha, pi, sqrt2)
|
||||
result[:length] = nan
|
||||
result = Series(result, index=close.index)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
result = result.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
result.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
result.name = f"REFLEX_{length}_{smooth}_{alpha}"
|
||||
result.category = "cycle"
|
||||
|
||||
return result
|
||||
@@ -1,75 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike
|
||||
from pandas_ta.overlap.dema import dema
|
||||
from pandas_ta.overlap.ema import ema
|
||||
from pandas_ta.overlap.fwma import fwma
|
||||
from pandas_ta.overlap.hma import hma
|
||||
from pandas_ta.overlap.linreg import linreg
|
||||
from pandas_ta.overlap.midpoint import midpoint
|
||||
from pandas_ta.overlap.pwma import pwma
|
||||
from pandas_ta.overlap.rma import rma
|
||||
from pandas_ta.overlap.sinwma import sinwma
|
||||
from pandas_ta.overlap.sma import sma
|
||||
from pandas_ta.overlap.ssf import ssf
|
||||
from pandas_ta.overlap.swma import swma
|
||||
from pandas_ta.overlap.t3 import t3
|
||||
from pandas_ta.overlap.tema import tema
|
||||
from pandas_ta.overlap.trima import trima
|
||||
from pandas_ta.overlap.vidya import vidya
|
||||
from pandas_ta.overlap.wma import wma
|
||||
|
||||
|
||||
|
||||
|
||||
def ma(name: str = None, source: Series = None, **kwargs: DictLike) -> Series:
|
||||
"""MA Selection Utility
|
||||
|
||||
Available MAs: dema, ema, fwma, hma, linreg, midpoint, pwma, rma,
|
||||
sinwma, sma, ssf, swma, t3, tema, trima, vidya, wma.
|
||||
|
||||
Parameters:
|
||||
name (str): One of the Available MAs. Default: "ema"
|
||||
source (Series): Input Series ```source```.
|
||||
|
||||
Other Parameters:
|
||||
kwargs (**kwargs): Additional args for the MA.
|
||||
|
||||
Returns:
|
||||
(Series): Selected MA
|
||||
|
||||
Esourceample:
|
||||
```py linenums="0"
|
||||
ema8 = ta.ma("ema", df.close, length=8)
|
||||
sma50 = ta.ma("sma", df.close, length=50)
|
||||
pwma10 = ta.ma("pwma", df.close, length=10, asc=False)
|
||||
```
|
||||
"""
|
||||
_mas = [
|
||||
"dema", "ema", "fwma", "hma", "linreg", "midpoint", "pwma", "rma",
|
||||
"sinwma", "sma", "ssf", "swma", "t3", "tema", "trima", "vidya", "wma"
|
||||
]
|
||||
if name is None and source is None:
|
||||
return _mas
|
||||
elif isinstance(name, str) and name.lower() in _mas:
|
||||
name = name.lower()
|
||||
else: # "ema"
|
||||
name = _mas[1]
|
||||
|
||||
if name == "dema": return dema(source, **kwargs)
|
||||
elif name == "fwma": return fwma(source, **kwargs)
|
||||
elif name == "hma": return hma(source, **kwargs)
|
||||
elif name == "linreg": return linreg(source, **kwargs)
|
||||
elif name == "midpoint": return midpoint(source, **kwargs)
|
||||
elif name == "pwma": return pwma(source, **kwargs)
|
||||
elif name == "rma": return rma(source, **kwargs)
|
||||
elif name == "sinwma": return sinwma(source, **kwargs)
|
||||
elif name == "sma": return sma(source, **kwargs)
|
||||
elif name == "ssf": return ssf(source, **kwargs)
|
||||
elif name == "swma": return swma(source, **kwargs)
|
||||
elif name == "t3": return t3(source, **kwargs)
|
||||
elif name == "tema": return tema(source, **kwargs)
|
||||
elif name == "trima": return trima(source, **kwargs)
|
||||
elif name == "vidya": return vidya(source, **kwargs)
|
||||
elif name == "wma": return wma(source, **kwargs)
|
||||
else: return ema(source, **kwargs)
|
||||
@@ -1,90 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from importlib.util import find_spec
|
||||
from pandas_ta._typing import Dict, IntFloat, ListStr
|
||||
|
||||
|
||||
Imports: Dict[str, bool] = {
|
||||
"talib": find_spec("talib") is not None,
|
||||
"vectorbt": find_spec("vectorbt") is not None,
|
||||
"yfinance": find_spec("yfinance") is not None,
|
||||
}
|
||||
|
||||
|
||||
# Not ideal and not dynamic but it works.
|
||||
# TODO: find a dynamic solution later.
|
||||
Category: Dict[str, ListStr] = {
|
||||
"candle": [
|
||||
"cdl_pattern", "cdl_z", "ha"
|
||||
],
|
||||
"cycle": ["ebsw", "reflex"],
|
||||
"momentum": [
|
||||
"ao", "apo", "bias", "bop", "brar", "cci", "cfo", "cg", "cmo",
|
||||
"coppock", "crsi", "cti", "er", "eri", "exhc", "fisher",
|
||||
"inertia", "kdj", "kst", "macd", "mom", "pgo", "ppo", "psl", "qqe",
|
||||
"roc", "rsi", "rsx", "rvgi", "slope", "smc", "smi", "squeeze",
|
||||
"squeeze_pro", "stc", "stoch", "stochf", "stochrsi", "tmo", "trix",
|
||||
"tsi", "uo", "willr"
|
||||
],
|
||||
"overlap": [
|
||||
"alligator", "alma", "dema", "ema", "fwma", "hilo", "hl2", "hlc3",
|
||||
"hma", "hwma", "ichimoku", "jma", "kama", "linreg", "mama",
|
||||
"mcgd", "midpoint", "midprice", "ohlc4", "pivots", "pwma", "rma",
|
||||
"sinwma", "sma", "smma", "ssf", "ssf3", "supertrend", "swma", "t3",
|
||||
"tema", "trima", "vidya", "wcp", "wma", "zlma"
|
||||
],
|
||||
"performance": ["log_return", "percent_return"],
|
||||
"statistics": [
|
||||
"entropy", "kurtosis", "mad", "median", "quantile", "skew", "stdev",
|
||||
"tos_stdevall", "variance", "zscore"
|
||||
],
|
||||
"trend": [
|
||||
"adx", "alphatrend", "amat", "aroon", "chop", "cksp", "decay",
|
||||
"decreasing", "dpo", "ht_trendline", "increasing",
|
||||
"long_run", "psar", "qstick", "rwi", "short_run", "trendflex",
|
||||
"vhf", "vortex", "zigzag"
|
||||
],
|
||||
"volatility": [
|
||||
"aberration", "accbands", "atr", "atrts", "bbands", "chandelier_exit",
|
||||
"donchian", "hwc", "kc", "massi", "natr", "pdist", "rvi", "thermo",
|
||||
"true_range", "ui"
|
||||
],
|
||||
# Note: "vp" or "Volume Profile" is excluded since it does not
|
||||
# return a Time Series
|
||||
"volume": [
|
||||
"ad", "adosc", "aobv", "cmf", "efi", "eom", "kvo", "mfi", "nvi",
|
||||
"obv", "pvi", "pvo", "pvol", "pvr", "pvt", "tsv", "vhm", "vwap",
|
||||
"vwma"
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
CANDLE_AGG: Dict[str, str] = {
|
||||
"open": "first",
|
||||
"high": "max",
|
||||
"low": "min",
|
||||
"close": "last",
|
||||
"volume": "sum"
|
||||
}
|
||||
|
||||
|
||||
# https://www.worldtimezone.com/markets24.php
|
||||
EXCHANGE_TZ: Dict[str, IntFloat] = {
|
||||
"NZSX": 12, "ASX": 11,
|
||||
"TSE": 9, "HKE": 8, "SSE": 8, "SGX": 8,
|
||||
"NSE": 5.5, "DIFX": 4, "RTS": 3,
|
||||
"JSE": 2, "FWB": 1, "LSE": 1,
|
||||
"BMF": -2, "NYSE": -4, "TSX": -4,
|
||||
"GENR": 0 # Generated Data
|
||||
}
|
||||
|
||||
|
||||
RATE: Dict[str, IntFloat] = {
|
||||
"DAYS_PER_MONTH": 21,
|
||||
"MINUTES_PER_HOUR": 60,
|
||||
"MONTHS_PER_YEAR": 12,
|
||||
"QUARTERS_PER_YEAR": 4,
|
||||
"TRADING_DAYS_PER_YEAR": 252, # Keep even
|
||||
"TRADING_HOURS_PER_DAY": 6.5,
|
||||
"WEEKS_PER_YEAR": 52,
|
||||
"YEARLY": 1,
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from .ao import ao
|
||||
from .apo import apo
|
||||
from .bias import bias
|
||||
from .bop import bop
|
||||
from .brar import brar
|
||||
from .cci import cci
|
||||
from .cfo import cfo
|
||||
from .cg import cg
|
||||
from .cmo import cmo
|
||||
from .coppock import coppock
|
||||
from .crsi import crsi
|
||||
from .cti import cti
|
||||
from .dm import dm
|
||||
from .er import er
|
||||
from .eri import eri
|
||||
from .exhc import exhc
|
||||
from .fisher import fisher
|
||||
from .inertia import inertia
|
||||
from .kdj import kdj
|
||||
from .kst import kst
|
||||
from .macd import macd
|
||||
from .mom import mom
|
||||
from .pgo import pgo
|
||||
from .ppo import ppo
|
||||
from .psl import psl
|
||||
from .qqe import qqe
|
||||
from .roc import roc
|
||||
from .rsi import rsi
|
||||
from .rsx import rsx
|
||||
from .rvgi import rvgi
|
||||
from .slope import slope
|
||||
from .smc import smc
|
||||
from .smi import smi
|
||||
from .squeeze import squeeze
|
||||
from .squeeze_pro import squeeze_pro
|
||||
from .stc import stc
|
||||
from .stoch import stoch
|
||||
from .stochf import stochf
|
||||
from .stochrsi import stochrsi
|
||||
from .tmo import tmo
|
||||
from .trix import trix
|
||||
from .tsi import tsi
|
||||
from .uo import uo
|
||||
from .willr import willr
|
||||
|
||||
|
||||
__all__ = [
|
||||
"ao",
|
||||
"apo",
|
||||
"bias",
|
||||
"bop",
|
||||
"brar",
|
||||
"cci",
|
||||
"cfo",
|
||||
"cg",
|
||||
"cmo",
|
||||
"coppock",
|
||||
"crsi",
|
||||
"cti",
|
||||
"dm",
|
||||
"er",
|
||||
"eri",
|
||||
"exhc",
|
||||
"fisher",
|
||||
"inertia",
|
||||
"kdj",
|
||||
"kst",
|
||||
"macd",
|
||||
"mom",
|
||||
"pgo",
|
||||
"ppo",
|
||||
"psl",
|
||||
"qqe",
|
||||
"roc",
|
||||
"rsi",
|
||||
"rsx",
|
||||
"rvgi",
|
||||
"slope",
|
||||
"smc",
|
||||
"smi",
|
||||
"squeeze",
|
||||
"squeeze_pro",
|
||||
"stc",
|
||||
"stoch",
|
||||
"stochf",
|
||||
"stochrsi",
|
||||
"tmo",
|
||||
"trix",
|
||||
"tsi",
|
||||
"uo",
|
||||
"willr",
|
||||
]
|
||||
@@ -1,66 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.overlap import sma
|
||||
from pandas_ta.utils import v_offset, v_pos_default, v_series
|
||||
|
||||
|
||||
|
||||
def ao(
|
||||
high: Series, low: Series, fast: Int = None, slow: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Awesome Oscillator
|
||||
|
||||
This indicator attempts to identify momentum with the intention to
|
||||
affirm trends or anticipate possible reversals.
|
||||
|
||||
Sources:
|
||||
* [ifcm](https://www.ifcm.co.uk/ntx-indicators/awesome-oscillator)
|
||||
* [tradingview](https://www.tradingview.com/wiki/Awesome_Oscillator_(AO))
|
||||
|
||||
Parameters:
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
fast (int): Fast period. Default: ```5```
|
||||
slow (int): Slow period. Default: ```34```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
fast = v_pos_default(fast, 5)
|
||||
slow = v_pos_default(slow, 34)
|
||||
if slow < fast:
|
||||
fast, slow = slow, fast
|
||||
_length = max(fast, slow)
|
||||
high = v_series(high, _length)
|
||||
low = v_series(low, _length)
|
||||
|
||||
if high is None or low is None:
|
||||
return
|
||||
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
median_price = 0.5 * (high + low)
|
||||
fast_sma = sma(median_price, fast)
|
||||
slow_sma = sma(median_price, slow)
|
||||
ao = fast_sma - slow_sma
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
ao = ao.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
ao.fillna(kwargs["fillna"], inplace=True)
|
||||
# Name and Category
|
||||
ao.name = f"AO_{fast}_{slow}"
|
||||
ao.category = "momentum"
|
||||
|
||||
return ao
|
||||
@@ -1,75 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.ma import ma
|
||||
from pandas_ta.maps import Imports
|
||||
from pandas_ta.utils import tal_ma, v_mamode, v_offset
|
||||
from pandas_ta.utils import v_pos_default, v_series, v_talib
|
||||
|
||||
|
||||
|
||||
def apo(
|
||||
close: Series, fast: Int = None, slow: Int = None,
|
||||
mamode: str = None, talib: bool = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Absolute Price Oscillator
|
||||
|
||||
This indicator attempts to quantify momentum.
|
||||
|
||||
Sources:
|
||||
* [tradingtechnologies](https://www.tradingtechnologies.com/xtrader-help/x-study/technical-indicator-definitions/absolute-price-oscillator-apo/)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
fast (int): Fast period. Default: ```12```
|
||||
slow (int): Slow period. Default: ```26```
|
||||
mamode (str): See ```help(ta.ma)```. Default: ```"sma"```
|
||||
talib (bool): If installed, use TA Lib. Default: ```True```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
|
||||
Note:
|
||||
* Simply the difference of two different EMAs.
|
||||
* APO and MACD lines are equivalent.
|
||||
"""
|
||||
# Validate
|
||||
fast = v_pos_default(fast, 12)
|
||||
slow = v_pos_default(slow, 26)
|
||||
if slow < fast:
|
||||
fast, slow = slow, fast
|
||||
close = v_series(close, max(fast, slow))
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
mamode = v_mamode(mamode, "sma")
|
||||
mode_tal = v_talib(talib)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
if Imports["talib"] and mode_tal:
|
||||
from talib import APO
|
||||
apo = APO(close, fast, slow, tal_ma(mamode))
|
||||
else:
|
||||
fastma = ma(mamode, close, length=fast, talib=mode_tal)
|
||||
slowma = ma(mamode, close, length=slow, talib=mode_tal)
|
||||
apo = fastma - slowma
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
apo = apo.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
apo.fillna(kwargs["fillna"], inplace=True)
|
||||
# Name and Category
|
||||
apo.name = f"APO_{fast}_{slow}"
|
||||
apo.category = "momentum"
|
||||
|
||||
return apo
|
||||
@@ -1,59 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.ma import ma
|
||||
from pandas_ta.utils import v_mamode, v_offset, v_pos_default, v_series
|
||||
|
||||
|
||||
|
||||
def bias(
|
||||
close: Series, length: Int = None, mamode: str = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Bias
|
||||
|
||||
This indicator computes the Rate of Change between the source and a
|
||||
moving average.
|
||||
|
||||
Sources:
|
||||
* Few internet resources on definitive definition.
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```26```
|
||||
mamode (str): See ```help(ta.ma)```. Default: ```"sma"```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 26)
|
||||
close = v_series(close, length)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
mamode = v_mamode(mamode, "sma")
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
bma = ma(mamode, close, length=length, **kwargs)
|
||||
bias = (close / bma) - 1
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
bias = bias.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
bias.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
bias.name = f"BIAS_{bma.name}"
|
||||
bias.category = "momentum"
|
||||
|
||||
return bias
|
||||
@@ -1,73 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.maps import Imports
|
||||
from pandas_ta.utils import (
|
||||
non_zero_range,
|
||||
v_offset,
|
||||
v_scalar,
|
||||
v_series,
|
||||
v_talib
|
||||
)
|
||||
|
||||
|
||||
|
||||
def bop(
|
||||
open_: Series, high: Series, low: Series, close: Series,
|
||||
scalar: IntFloat = None, talib: bool = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Balance of Power
|
||||
|
||||
This indicator attempts to quantify the market strength of buyers
|
||||
versus sellers.
|
||||
|
||||
Sources:
|
||||
* [worden](http://www.worden.com/TeleChartHelp/Content/Indicators/Balance_of_Power.htm)
|
||||
|
||||
Parameters:
|
||||
open_ (Series): ```open``` Series
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
close (Series): ```close``` Series
|
||||
scalar (float): Scalar. Default: ```1```
|
||||
talib (bool): If installed, use TA Lib. Default: ```True```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
open_ = v_series(open_)
|
||||
high = v_series(high)
|
||||
low = v_series(low)
|
||||
close = v_series(close)
|
||||
scalar = v_scalar(scalar, 1)
|
||||
mode_tal = v_talib(talib)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
if Imports["talib"] and mode_tal and close.size:
|
||||
from talib import BOP
|
||||
bop = BOP(open_, high, low, close)
|
||||
else:
|
||||
high_low_range = non_zero_range(high, low)
|
||||
close_open_range = non_zero_range(close, open_)
|
||||
bop = scalar * close_open_range / high_low_range
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
bop = bop.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
bop.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
bop.name = f"BOP"
|
||||
bop.category = "momentum"
|
||||
|
||||
return bop
|
||||
@@ -1,93 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.utils import (
|
||||
non_zero_range,
|
||||
v_drift,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_scalar,
|
||||
v_series
|
||||
)
|
||||
|
||||
|
||||
|
||||
def brar(
|
||||
open_: Series, high: Series, low: Series, close: Series,
|
||||
length: Int = None, scalar: IntFloat = None, drift: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> DataFrame:
|
||||
"""BRAR
|
||||
|
||||
BR and AR
|
||||
|
||||
Sources:
|
||||
* No internet resources on definitive definition.
|
||||
|
||||
Parameters:
|
||||
open_ (Series): ```open``` Series
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```26```
|
||||
scalar (float): Scalar. Default: ```100```
|
||||
drift (int): Difference amount. Default: ```1```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(DataFrame): 2 columns
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 26)
|
||||
open_ = v_series(open_, length)
|
||||
high = v_series(high, length)
|
||||
low = v_series(low, length)
|
||||
close = v_series(close, length)
|
||||
|
||||
if open_ is None or high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
scalar = v_scalar(scalar, 100)
|
||||
drift = v_drift(drift)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
high_open_range = non_zero_range(high, open_)
|
||||
open_low_range = non_zero_range(open_, low)
|
||||
hcy = non_zero_range(high, close.shift(drift))
|
||||
cyl = non_zero_range(close.shift(drift), low)
|
||||
|
||||
hcy[hcy < 0] = 0 # Zero negative values
|
||||
cyl[cyl < 0] = 0 # ""
|
||||
|
||||
ar = scalar * high_open_range.rolling(length).sum() \
|
||||
/ open_low_range.rolling(length).sum()
|
||||
|
||||
br = scalar * hcy.rolling(length).sum() \
|
||||
/ cyl.rolling(length).sum()
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
ar = ar.shift(offset)
|
||||
br = ar.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
ar.fillna(kwargs["fillna"], inplace=True)
|
||||
br.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
_props = f"_{length}"
|
||||
ar.name = f"AR{_props}"
|
||||
br.name = f"BR{_props}"
|
||||
ar.category = br.category = "momentum"
|
||||
|
||||
data = {ar.name: ar, br.name: br}
|
||||
df = DataFrame(data, index=close.index)
|
||||
df.name = f"BRAR{_props}"
|
||||
df.category = "momentum"
|
||||
|
||||
return df
|
||||
@@ -1,75 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.maps import Imports
|
||||
from pandas_ta.overlap import hlc3, sma
|
||||
from pandas_ta.statistics import mad
|
||||
from pandas_ta.utils import v_offset, v_pos_default, v_series, v_talib
|
||||
|
||||
|
||||
|
||||
def cci(
|
||||
high: Series, low: Series, close: Series, length: Int = None,
|
||||
c: IntFloat = None, talib: bool = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Commodity Channel Index
|
||||
|
||||
This indicator attempts to identify "overbought" and "oversold" levels
|
||||
relative to a mean.
|
||||
|
||||
Sources:
|
||||
* [tradingview](https://www.tradingview.com/wiki/Commodity_Channel_Index_(CCI))
|
||||
|
||||
Parameters:
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```14```
|
||||
c (float): Scaling Constant. Default: ```0.015```
|
||||
talib (bool): If installed, use TA Lib. Default: ```True```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 14)
|
||||
high = v_series(high, length)
|
||||
low = v_series(low, length)
|
||||
close = v_series(close, length)
|
||||
|
||||
if high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
c = v_pos_default(c, 0.015)
|
||||
mode_tal = v_talib(talib)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
if Imports["talib"] and mode_tal:
|
||||
from talib import CCI
|
||||
cci = CCI(high, low, close, length)
|
||||
else:
|
||||
typical_price = hlc3(high=high, low=low, close=close, talib=mode_tal)
|
||||
mean_typical_price = sma(typical_price, length=length, talib=mode_tal)
|
||||
mad_typical_price = mad(typical_price, length=length)
|
||||
|
||||
cci = typical_price - mean_typical_price / (c * mad_typical_price)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
cci = cci.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
cci.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
cci.name = f"CCI_{length}_{c}"
|
||||
cci.category = "momentum"
|
||||
|
||||
return cci
|
||||
@@ -1,69 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.overlap import linreg
|
||||
from pandas_ta.utils import (
|
||||
v_drift,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_scalar,
|
||||
v_series
|
||||
)
|
||||
|
||||
|
||||
|
||||
def cfo(
|
||||
close: Series, length: Int = None,
|
||||
scalar: IntFloat = None, drift: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Chande Forcast Oscillator
|
||||
|
||||
This indicator attempts to calculate the percentage difference between
|
||||
the actual price and the Time Series Forecast (the endpoint of a
|
||||
linear regression line).
|
||||
|
||||
Sources:
|
||||
* [fmlabs](https://www.fmlabs.com/reference/default.htm?url=ForecastOscillator.htm)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```9```
|
||||
scalar (float): Scalar. Default: ```100```
|
||||
drift (int): Difference amount. Default: ```1```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 9)
|
||||
close = v_series(close, length)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
scalar = v_scalar(scalar, 100)
|
||||
drift = v_drift(drift)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
# Finding linear regression of Series
|
||||
cfo = scalar * (close - linreg(close, length=length, tsf=True)) / close
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
cfo = cfo.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
cfo.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
cfo.name = f"CFO_{length}"
|
||||
cfo.category = "momentum"
|
||||
|
||||
return cfo
|
||||
@@ -1,57 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.utils import v_offset, v_pos_default, v_series, weights
|
||||
|
||||
|
||||
|
||||
def cg(
|
||||
close: Series, length: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Center of Gravity
|
||||
|
||||
This indicator, by John Ehlers, attempts to identify turning points with
|
||||
minimal to zero lag and smoothing.
|
||||
|
||||
Sources:
|
||||
* [MESA Software](http://www.mesasoftware.com/papers/TheCGOscillator.pdf)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```10```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 10)
|
||||
close = v_series(close, length)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
coefficients = range(1, length + 1)
|
||||
numerator = close.rolling(length).apply(weights(coefficients), raw=True)
|
||||
cg = -numerator / close.rolling(length).sum()
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
cg = cg.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
cg.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
cg.name = f"CG_{length}"
|
||||
cg.category = "momentum"
|
||||
|
||||
return cg
|
||||
@@ -1,90 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.maps import Imports
|
||||
from pandas_ta.overlap import rma
|
||||
from pandas_ta.utils import (
|
||||
v_drift,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_scalar,
|
||||
v_series,
|
||||
v_talib
|
||||
)
|
||||
|
||||
|
||||
|
||||
def cmo(
|
||||
close: Series, length: Int = None, scalar: IntFloat = None,
|
||||
talib: bool = None, drift: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Chande Momentum Oscillator
|
||||
|
||||
This indicator attempts to capture momentum.
|
||||
|
||||
Sources:
|
||||
* [tradingtechnologies](https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/chande-momentum-oscillator-cmo/)
|
||||
* [tradingview](https://www.tradingview.com/script/hdrf0fXV-Variable-Index-Dynamic-Average-VIDYA/)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
scalar (float): Scalar. Default: ```100```
|
||||
talib (bool): If installed, use TA Lib. Uses EMA if ```False```.
|
||||
Default: ```True```
|
||||
drift (int): Difference amount. Default: ```1```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
|
||||
Note:
|
||||
* Overbought around 50
|
||||
* Oversold around -50.
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 14)
|
||||
close = v_series(close, length + 1)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
scalar = v_scalar(scalar, 100)
|
||||
mode_tal = v_talib(talib)
|
||||
drift = v_drift(drift)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
if Imports["talib"] and mode_tal:
|
||||
from talib import CMO
|
||||
cmo = CMO(close, length)
|
||||
else:
|
||||
mom = close.diff(drift)
|
||||
positive = mom.copy().clip(lower=0)
|
||||
negative = mom.copy().clip(upper=0).abs()
|
||||
|
||||
if mode_tal:
|
||||
pos_ = rma(positive, length)
|
||||
neg_ = rma(negative, length)
|
||||
else:
|
||||
pos_ = positive.rolling(length).sum()
|
||||
neg_ = negative.rolling(length).sum()
|
||||
|
||||
cmo = scalar * (pos_ - neg_) / (pos_ + neg_)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
cmo = cmo.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
cmo.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
cmo.name = f"CMO_{length}"
|
||||
cmo.category = "momentum"
|
||||
|
||||
return cmo
|
||||
@@ -1,70 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.overlap import wma
|
||||
from pandas_ta.utils import v_offset, v_pos_default, v_series
|
||||
from .roc import roc
|
||||
|
||||
|
||||
|
||||
def coppock(
|
||||
close: Series, length: Int = None,
|
||||
fast: Int = None, slow: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Coppock Curve
|
||||
|
||||
This indicator, by Edwin Coppock 1962, was originally called the
|
||||
"Trendex Model", attempts to identify major upturns and downturns.
|
||||
|
||||
Sources:
|
||||
* [wikipedia](https://en.wikipedia.org/wiki/Coppock_curve)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
length (int): WMA period. Default: ```10```
|
||||
fast (int): Fast ROC period. Default: ```11```
|
||||
slow (int): Slow ROC period. Default: ```14```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
|
||||
Note:
|
||||
Although designed for monthly use, a daily calculation over the same
|
||||
period length can be made, converting the periods to 294-day and
|
||||
231-day rate of changes, and a 210-day WMA.
|
||||
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 10)
|
||||
fast = v_pos_default(fast, 11)
|
||||
slow = v_pos_default(slow, 14)
|
||||
_length = length + fast + slow
|
||||
close = v_series(close, _length)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
total_roc = roc(close, fast) + roc(close, slow)
|
||||
coppock = wma(total_roc, length)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
coppock = coppock.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
coppock.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
coppock.name = f"COPC_{fast}_{slow}_{length}"
|
||||
coppock.category = "momentum"
|
||||
|
||||
return coppock
|
||||
@@ -1,106 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.maps import Imports
|
||||
from pandas_ta.momentum.rsi import rsi
|
||||
from pandas_ta.utils import (
|
||||
consecutive_streak,
|
||||
percent_rank,
|
||||
v_drift,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_scalar,
|
||||
v_series,
|
||||
v_talib,
|
||||
)
|
||||
|
||||
|
||||
|
||||
def crsi(
|
||||
close: Series, rsi_length: Int = None, streak_length: Int = None,
|
||||
rank_length: Int = None, scalar: IntFloat = None,
|
||||
talib: bool = None, drift: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike,
|
||||
) -> Series:
|
||||
"""Connors Relative Strength Index
|
||||
|
||||
This indicator attempts to identify momentum and potential reversals at
|
||||
"overbought" or "oversold" conditions.
|
||||
|
||||
Sources:
|
||||
* [alvarezquanttrading](https://alvarezquanttrading.com/blog/connorsrsi-analysis/)
|
||||
* [tradingview](https://www.tradingview.com/support/solutions/43000502017-connors-rsi-crsi/)
|
||||
* An Introduction to ConnorsRSI. Connors Research Trading Strategy Series.
|
||||
Connors, L., Alvarez, C., & Radtke, M. (2012). ISBN 978-0-9853072-9-5.
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
rsi_length (int): The RSI period. Default: ```3```
|
||||
streak_length (int): Streak RSI period. Default: ```2```
|
||||
rank_length (int): Percent Rank length. Default: ```100```
|
||||
scalar (float): Scalar. Default: ```100```
|
||||
talib (bool): If installed, use TA Lib. Default: ```True```
|
||||
drift (int): Difference amount. Default: ```1```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
rsi_length = v_pos_default(rsi_length, 3)
|
||||
streak_length = v_pos_default(streak_length, 2)
|
||||
rank_length = v_pos_default(rank_length, 100)
|
||||
_length = max(rsi_length, streak_length, rank_length)
|
||||
close = v_series(close, _length)
|
||||
|
||||
if "length" in kwargs:
|
||||
kwargs.pop("length")
|
||||
|
||||
if close is None:
|
||||
return None
|
||||
|
||||
scalar = v_scalar(scalar, 100)
|
||||
mode_tal = v_talib(talib)
|
||||
drift = v_drift(drift)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
np_close = close.to_numpy()
|
||||
streak = Series(consecutive_streak(np_close), index=close.index)
|
||||
|
||||
if Imports["talib"] and mode_tal:
|
||||
from talib import RSI
|
||||
_rsi = RSI(close, rsi_length)
|
||||
_streak_rsi = RSI(streak, streak_length)
|
||||
else:
|
||||
# Both TA-lib and Pandas-TA use the Wilder's RSI
|
||||
# and its smoothing function
|
||||
_rsi = rsi(
|
||||
close, length=rsi_length, scalar=scalar, talib=talib,
|
||||
drift=drift, offset=offset, **kwargs
|
||||
)
|
||||
|
||||
_streak_rsi = rsi(
|
||||
streak, length=streak_length, scalar=scalar, talib=talib,
|
||||
drift=drift, offset=offset, **kwargs
|
||||
)
|
||||
|
||||
_crsi = (_rsi + _streak_rsi + percent_rank(close, rank_length)) / 3.0
|
||||
crsi = Series(_crsi, index=close.index)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
crsi = crsi.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
crsi.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
crsi.name = f"CRSI_{rsi_length}_{streak_length}_{rank_length}"
|
||||
crsi.category = "momentum"
|
||||
|
||||
return crsi
|
||||
@@ -1,56 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.overlap import linreg
|
||||
from pandas_ta.utils import v_offset, v_pos_default, v_series
|
||||
|
||||
|
||||
|
||||
def cti(
|
||||
close: Series, length: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Correlation Trend Indicator
|
||||
|
||||
This oscillator, by John Ehlers' in 2020, attempts to identify the
|
||||
magnitude and direction of a trend using linear regession.
|
||||
|
||||
Note:
|
||||
This is a wrapper for ```ta.linreg(close, r=True)```.
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```12```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 12)
|
||||
close = v_series(close, length)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
cti = linreg(close, length=length, r=True)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
cti = cti.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
cti.fillna(method=kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
cti.name = f"CTI_{length}"
|
||||
cti.category = "momentum"
|
||||
|
||||
return cti
|
||||
@@ -1,94 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.ma import ma
|
||||
from pandas_ta.maps import Imports
|
||||
from pandas_ta.utils import (
|
||||
v_drift,
|
||||
v_mamode,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_series,
|
||||
v_talib,
|
||||
zero
|
||||
)
|
||||
|
||||
|
||||
|
||||
def dm(
|
||||
high: Series, low: Series, length: Int = None,
|
||||
mamode: str = None, talib: bool = None, drift: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> DataFrame:
|
||||
"""Directional Movement
|
||||
|
||||
This indicator, by J. Welles Wilder in 1978, attempts to
|
||||
determine direction.
|
||||
|
||||
Sources:
|
||||
* [sierrachart](https://www.sierrachart.com/index.php?page=doc/StudiesReference.php&ID=24&Name=Directional_Movement_Index)
|
||||
* [tradingview](https://www.tradingview.com/pine-script-reference/#fun_dmi)
|
||||
|
||||
Parameters:
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
mamode (str): See ```help(ta.ma)```. Default: ```"rma"```
|
||||
talib (bool): If installed, use TA Lib. Default: ```True```
|
||||
drift (int): Difference amount. Default: ```1```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(DataFrame): 2 columns
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 14)
|
||||
high = v_series(high, length)
|
||||
low = v_series(low, length)
|
||||
|
||||
if high is None or low is None:
|
||||
return
|
||||
|
||||
mamode = v_mamode(mamode, "rma")
|
||||
mode_tal = v_talib(talib)
|
||||
drift = v_drift(drift)
|
||||
offset = v_offset(offset)
|
||||
|
||||
if Imports["talib"] and mode_tal and high.size and low.size:
|
||||
from talib import MINUS_DM, PLUS_DM
|
||||
pos = PLUS_DM(high, low, length)
|
||||
neg = MINUS_DM(high, low, length)
|
||||
else:
|
||||
up = high - high.shift(drift)
|
||||
dn = low.shift(drift) - low
|
||||
|
||||
pos_ = ((up > dn) & (up > 0)) * up
|
||||
neg_ = ((dn > up) & (dn > 0)) * dn
|
||||
|
||||
pos_ = pos_.apply(zero)
|
||||
neg_ = neg_.apply(zero)
|
||||
|
||||
# Not the same values as TA Lib's -+DM (Good First Issue)
|
||||
pos = ma(mamode, pos_, length=length, talib=mode_tal)
|
||||
neg = ma(mamode, neg_, length=length, talib=mode_tal)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
pos = pos.shift(offset)
|
||||
neg = neg.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
pos.fillna(kwargs["fillna"], inplace=True)
|
||||
neg.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
_props = f"_{length}"
|
||||
data = {f"DMP{_props}": pos, f"DMN{_props}": neg}
|
||||
df = DataFrame(data, index=high.index)
|
||||
df.name = f"DM{_props}"
|
||||
df.category = "momentum"
|
||||
|
||||
return df
|
||||
@@ -1,93 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import DataFrame, Series, concat
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.utils import (
|
||||
signals,
|
||||
v_drift,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_series
|
||||
)
|
||||
|
||||
|
||||
|
||||
def er(
|
||||
close: Series, length: Int = None, drift: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Efficiency Ratio
|
||||
|
||||
This indicator, by Perry J. Kaufman, attempts to identify market noise
|
||||
or volatility.
|
||||
|
||||
Sources:
|
||||
* "New Trading Systems and Methods", Perry J. Kaufman
|
||||
* [tc2000](https://help.tc2000.com/m/69404/l/749623-kaufman-efficiency-ratio)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```1```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
|
||||
Note:
|
||||
It is calculated by dividing the net change in price movement over
|
||||
```n``` periods by the sum of the absolute net changes over the
|
||||
same ```n``` periods.
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 10)
|
||||
close = v_series(close, length + 1)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
drift = v_drift(drift)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
abs_diff = close.diff(length).abs()
|
||||
abs_volatility = close.diff(drift).abs()
|
||||
abs_volatility_rsum = abs_volatility.rolling(window=length).sum()
|
||||
|
||||
er = abs_diff / abs_volatility_rsum
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
er = er.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
er.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
er.name = f"ER_{length}"
|
||||
er.category = "momentum"
|
||||
|
||||
signal_indicators = kwargs.pop("signal_indicators", False)
|
||||
if not signal_indicators:
|
||||
return er
|
||||
else:
|
||||
signalsdf = concat(
|
||||
[
|
||||
DataFrame({er.name: er}),
|
||||
signals(
|
||||
indicator=er,
|
||||
xa=kwargs.pop("xa", 80),
|
||||
xb=kwargs.pop("xb", 20),
|
||||
xseries=kwargs.pop("xseries", None),
|
||||
xseries_a=kwargs.pop("xseries_a", None),
|
||||
xseries_b=kwargs.pop("xseries_b", None),
|
||||
cross_values=kwargs.pop("cross_values", False),
|
||||
cross_series=kwargs.pop("cross_series", True),
|
||||
offset=offset,
|
||||
),
|
||||
],
|
||||
axis=1,
|
||||
)
|
||||
return signalsdf
|
||||
@@ -1,75 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.overlap import ema
|
||||
from pandas_ta.utils import v_offset, v_pos_default, v_series
|
||||
|
||||
|
||||
|
||||
def eri(
|
||||
high: Series, low: Series, close: Series, length: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> DataFrame:
|
||||
"""Elder Ray Index
|
||||
|
||||
This indicator, by Dr Alexander Elder, attempts to identify market
|
||||
strength.
|
||||
|
||||
Sources:
|
||||
* [admiralmarkets](https://admiralmarkets.com/education/articles/forex-indicators/bears-and-bulls-power-indicator)
|
||||
|
||||
Parameters:
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```14```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(DataFrame): 2 columns
|
||||
|
||||
Note:
|
||||
* Possible entry signals when used in combination with a trend,
|
||||
* Bear Power attempts to quantify lower value appeal.
|
||||
* Bull Power attempts the to quantify higher value appeal.
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 13)
|
||||
high = v_series(high, length)
|
||||
low = v_series(low, length)
|
||||
close = v_series(close, length)
|
||||
|
||||
if high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
ema_ = ema(close, length)
|
||||
bull = high - ema_
|
||||
bear = low - ema_
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
bull = bull.shift(offset)
|
||||
bear = bear.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
bull.fillna(kwargs["fillna"], inplace=True)
|
||||
bear.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
bull.name = f"BULLP_{length}"
|
||||
bear.name = f"BEARP_{length}"
|
||||
bull.category = bear.category = "momentum"
|
||||
|
||||
data = {bull.name: bull, bear.name: bear}
|
||||
df = DataFrame(data, index=close.index)
|
||||
df.name = f"ERI_{length}"
|
||||
df.category = bull.category
|
||||
|
||||
return df
|
||||
@@ -1,110 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numba import njit
|
||||
from numpy import clip, cumsum, int64, nan, where
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.utils import (
|
||||
nb_ffill,
|
||||
nb_idiff,
|
||||
v_bool,
|
||||
v_int,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_series
|
||||
)
|
||||
|
||||
|
||||
|
||||
@njit(cache=True)
|
||||
def nb_exhc(x, n, cap, lb, ub, show_all):
|
||||
x_diff = nb_idiff(x, n)
|
||||
neg_diff, pos_diff = x_diff < 0, x_diff > 0
|
||||
|
||||
dn_csum = cumsum(neg_diff)
|
||||
up_csum = cumsum(pos_diff)
|
||||
|
||||
dn = dn_csum - nb_ffill(where(~neg_diff, dn_csum, nan))
|
||||
up = up_csum - nb_ffill(where(~pos_diff, up_csum, nan))
|
||||
|
||||
if cap > 0:
|
||||
dn = clip(dn, 0, cap)
|
||||
up = clip(up, 0, cap)
|
||||
|
||||
if show_all:
|
||||
dn = where(dn == 0, 0, dn)
|
||||
up = where(up == 0, 0, up)
|
||||
else:
|
||||
between_lu = (dn >= lb) & (dn <= ub)
|
||||
dn = where(between_lu, dn, 0)
|
||||
up = where(between_lu, up, 0)
|
||||
|
||||
return dn, up
|
||||
|
||||
|
||||
def exhc(
|
||||
close: Series, length: Int = None, cap: Int = None,
|
||||
asint: bool = None, show_all: bool = None, nozeros: bool = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> DataFrame:
|
||||
"""Exhaustion Count
|
||||
|
||||
This indicator attempts to identify rising/falling exhaustion.
|
||||
|
||||
Sources:
|
||||
* [demark](https://demark.com)
|
||||
* [practicaltechnicalanalysis](http://practicaltechnicalanalysis.blogspot.com/2013/01/tom-demark-sequential.html)
|
||||
|
||||
Parameters:
|
||||
close (Series): Series of close's
|
||||
length (int): The period. Default: ```4```
|
||||
cap (int): Count cap. For no cap, set to ```0```. Default: ```13```
|
||||
show_all (bool): Counts 1 - 13. For 6 - 9, set to ```False```.
|
||||
Default: ```True```
|
||||
asint (bool): Returns as ```Int```. Default: ```False```
|
||||
nozeros (bool): Replace zeros with ```np.nan```. Default: ```False```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Returns:
|
||||
(DataFrame): 2 columns
|
||||
|
||||
Note:
|
||||
Similar to TD Sequential
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 4)
|
||||
close = v_series(close, length + 1)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
cap = v_int(cap, 13, -1)
|
||||
show_all = v_bool(show_all, True)
|
||||
asint = v_bool(asint, False)
|
||||
nozeros = v_bool(nozeros, False)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
np_close = close.to_numpy()
|
||||
dn, up = nb_exhc(np_close, length, cap, 6, 9, show_all)
|
||||
|
||||
if asint:
|
||||
dn = dn.astype(int64)
|
||||
up = up.astype(int64)
|
||||
|
||||
# Name and Category
|
||||
data = {
|
||||
"EXHC_DNa" if show_all else "EXHC_DN": dn,
|
||||
"EXHC_UPa" if show_all else "EXHC_UP": up
|
||||
}
|
||||
df = DataFrame(data, index=close.index)
|
||||
df.name = "EXHCa" if show_all else "EXHC"
|
||||
df.category = "momentum"
|
||||
|
||||
if nozeros:
|
||||
df.replace({0: nan}, inplace=True)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
df = df.shift(offset)
|
||||
|
||||
return df
|
||||
@@ -1,95 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import isnan, log, nan
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.overlap import hl2
|
||||
from pandas_ta.utils import high_low_range, v_offset, v_pos_default, v_series
|
||||
|
||||
|
||||
|
||||
def fisher(
|
||||
high: Series, low: Series, length: Int = None, signal: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Fisher Transform
|
||||
|
||||
This indicator attempts to identify significant reversals through
|
||||
normalization.
|
||||
|
||||
Parameters:
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
length (int): The period. Default: ```9```
|
||||
signal (int): Signal period. Default: ```1```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(DataFrame): 2 columns
|
||||
|
||||
Tip: Reversal Signal
|
||||
When the two lines cross.
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 9)
|
||||
signal = v_pos_default(signal, 1)
|
||||
_length = max(length, signal)
|
||||
high = v_series(high, _length)
|
||||
low = v_series(low, _length)
|
||||
|
||||
if high is None or low is None:
|
||||
return
|
||||
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
hl2_ = hl2(high, low)
|
||||
highest_hl2 = hl2_.rolling(length).max()
|
||||
lowest_hl2 = hl2_.rolling(length).min()
|
||||
|
||||
hlr = high_low_range(highest_hl2, lowest_hl2)
|
||||
hlr[hlr < 0.001] = 0.001
|
||||
|
||||
position = ((hl2_ - lowest_hl2) / hlr) - 0.5
|
||||
|
||||
v = 0
|
||||
m = high.size
|
||||
result = [nan for _ in range(0, length - 1)] + [0]
|
||||
for i in range(length, m):
|
||||
v = 0.66 * position.iat[i] + 0.67 * v
|
||||
if v < -0.99:
|
||||
v = -0.999
|
||||
if v > 0.99:
|
||||
v = 0.999
|
||||
result.append(0.5 * (log((1 + v) / (1 - v)) + result[i - 1]))
|
||||
|
||||
fisher = Series(result, index=high.index)
|
||||
if all(isnan(fisher)):
|
||||
return # Emergency Break
|
||||
|
||||
signalma = fisher.shift(signal)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
fisher = fisher.shift(offset)
|
||||
signalma = signalma.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
fisher.fillna(kwargs["fillna"], inplace=True)
|
||||
signalma.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
_props = f"_{length}_{signal}"
|
||||
fisher.name = f"FISHERT{_props}"
|
||||
signalma.name = f"FISHERTs{_props}"
|
||||
fisher.category = signalma.category = "momentum"
|
||||
|
||||
data = {fisher.name: fisher, signalma.name: signalma}
|
||||
df = DataFrame(data, index=high.index)
|
||||
df.name = f"FISHERT{_props}"
|
||||
df.category = fisher.category
|
||||
|
||||
return df
|
||||
@@ -1,118 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import isnan
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.overlap import linreg
|
||||
from pandas_ta.utils import (
|
||||
v_bool,
|
||||
v_drift,
|
||||
v_mamode,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_scalar,
|
||||
v_series
|
||||
)
|
||||
from pandas_ta.volatility import rvi
|
||||
|
||||
|
||||
|
||||
def inertia(
|
||||
close: Series, high: Series = None, low: Series = None,
|
||||
length: Int = None, rvi_length: Int = None, scalar: IntFloat = None,
|
||||
refined: bool = None, thirds: bool = None,
|
||||
drift: Int = None, mamode: str = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Inertia
|
||||
|
||||
This indicator, by Donald Dorsey, is the _rvi_ smoothed by the Least Squares
|
||||
MA.
|
||||
|
||||
Sources:
|
||||
* Donald Dorsey, some article in September, 1995.
|
||||
* [sierrachart](https://www.sierrachart.com/index.php?page=doc/StudiesReference.php&ID=285&Name=Inertia)
|
||||
* [tradingview](https://www.tradingview.com/script/mLZJqxKn-Relative-Volatility-Index/)
|
||||
|
||||
Parameters:
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```20```
|
||||
rvi_length (int): RVI period. Default: ```14```
|
||||
refined (bool): Use 'refined' calculation. Default: ```False```
|
||||
thirds (bool): Use 'thirds' calculation. Default: ```False```
|
||||
mamode (str): See ```help(ta.ma)```. Default: ```"ema"```
|
||||
drift (int): Difference amount. Default: ```1```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
|
||||
Note:
|
||||
* Negative Inertia when less than 50.
|
||||
* Positive Inertia when greater than 50.
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 20)
|
||||
rvi_length = v_pos_default(rvi_length, 14)
|
||||
_length = 2 * max(length, rvi_length) - min(length, rvi_length) // 2 - 1
|
||||
close = v_series(close, _length)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
refined = v_bool(refined, False)
|
||||
thirds = v_bool(thirds, False)
|
||||
|
||||
if refined or thirds:
|
||||
high = v_series(high, _length)
|
||||
low = v_series(low, _length)
|
||||
if high is None or low is None:
|
||||
return
|
||||
|
||||
scalar = v_scalar(scalar, 100)
|
||||
mamode = v_mamode(mamode, "ema")
|
||||
drift = v_drift(drift)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
if refined:
|
||||
_mode = "r"
|
||||
rvi_ = rvi(
|
||||
close, high=high, low=low, length=rvi_length,
|
||||
scalar=scalar, refined=refined, mamode=mamode
|
||||
)
|
||||
elif thirds:
|
||||
_mode = "t"
|
||||
rvi_ = rvi(
|
||||
close, high=high, low=low, length=rvi_length,
|
||||
scalar=scalar, thirds=thirds, mamode=mamode
|
||||
)
|
||||
else:
|
||||
_mode = ""
|
||||
rvi_ = rvi(close, length=rvi_length, scalar=scalar, mamode=mamode)
|
||||
|
||||
if all(isnan(rvi_)):
|
||||
return # Emergency Break
|
||||
|
||||
inertia = linreg(rvi_, length=length)
|
||||
if all(isnan(inertia)):
|
||||
return # Emergency Break
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
inertia = inertia.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
inertia.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
_props = f"_{length}_{rvi_length}"
|
||||
inertia.name = f"INERTIA{_mode}{_props}"
|
||||
inertia.category = "momentum"
|
||||
|
||||
return inertia
|
||||
@@ -1,94 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.utils import (
|
||||
non_zero_range,
|
||||
pd_rma,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_series
|
||||
)
|
||||
|
||||
|
||||
|
||||
def kdj(
|
||||
high: Series, low: Series, close: Series,
|
||||
length: Int = None, signal: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""KDJ
|
||||
|
||||
This indicator, derived from the Slow Stochastic, includes an
|
||||
extra signal named the J line. The J line represents the divergence
|
||||
of the %D value from the %K.
|
||||
|
||||
Sources:
|
||||
* [anychart](https://docs.anychart.com/Stock_Charts/Technical_Indicators/Mathematical_Description#kdj)
|
||||
* [prorealcode](https://www.prorealcode.com/prorealtime-indicators/kdj/)
|
||||
|
||||
Parameters:
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```9```
|
||||
signal (int): Signal period. Default: ```3```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(DataFrame): 3 columns
|
||||
|
||||
Note:
|
||||
The J can go beyond ```[0, 100]``` for %K and %D lines when charted.
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 9)
|
||||
signal = v_pos_default(signal, 3)
|
||||
_length = length + signal + 1
|
||||
high = v_series(high, _length)
|
||||
low = v_series(low, _length)
|
||||
close = v_series(close, _length)
|
||||
|
||||
if high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
highest_high = high.rolling(length).max()
|
||||
lowest_low = low.rolling(length).min()
|
||||
|
||||
fastk = 100 * (close - lowest_low) / \
|
||||
non_zero_range(highest_high, lowest_low)
|
||||
|
||||
k = pd_rma(fastk, n=signal)
|
||||
d = pd_rma(k, n=signal)
|
||||
j = 3 * k - 2 * d
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
k = k.shift(offset)
|
||||
d = d.shift(offset)
|
||||
j = j.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
k.fillna(kwargs["fillna"], inplace=True)
|
||||
d.fillna(kwargs["fillna"], inplace=True)
|
||||
j.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
_props = f"_{length}_{signal}"
|
||||
k.name = f"K{_props}"
|
||||
d.name = f"D{_props}"
|
||||
j.name = f"J{_props}"
|
||||
k.category = d.category = j.category = "momentum"
|
||||
|
||||
data = {k.name: k, d.name: d, j.name: j}
|
||||
df = DataFrame(data, index=close.index)
|
||||
df.name = f"KDJ{_props}"
|
||||
df.category = "momentum"
|
||||
|
||||
return df
|
||||
@@ -1,97 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.utils import v_drift, v_offset, v_pos_default, v_series
|
||||
from .roc import roc
|
||||
|
||||
|
||||
|
||||
def kst(
|
||||
close: Series, signal: Int = None,
|
||||
roc1: Int = None, roc2: Int = None, roc3: Int = None, roc4: Int = None,
|
||||
sma1: Int = None, sma2: Int = None, sma3: Int = None, sma4: Int = None,
|
||||
drift: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> DataFrame:
|
||||
"""'Know Sure Thing'
|
||||
|
||||
This indicator, by Martin Pring, attempts to capture trends using a
|
||||
smoothed indicator of four different smoothed ROCs.
|
||||
|
||||
Sources:
|
||||
* [incrediblecharts](https://www.incrediblecharts.com/indicators/kst.php)
|
||||
* [tradingview](https://www.tradingview.com/wiki/Know_Sure_Thing_(KST))
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
roc1 (int): ROC 1 period. Default: ```10```
|
||||
roc2 (int): ROC 2 period. Default: ```15```
|
||||
roc3 (int): ROC 3 period. Default: ```20```
|
||||
roc4 (int): ROC 4 period. Default: ```30```
|
||||
sma1 (int): SMA 1 period. Default: ```10```
|
||||
sma2 (int): SMA 2 period. Default: ```10```
|
||||
sma3 (int): SMA 3 period. Default: ```10```
|
||||
sma4 (int): SMA 4 period. Default: ```15```
|
||||
signal (int): Signal period. Default: ```9```
|
||||
drift (int): Difference amount. Default: ```1```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(DataFrame): 2 columns
|
||||
"""
|
||||
# Validate
|
||||
roc1 = int(roc1) if roc1 and roc1 > 0 else 10
|
||||
roc2 = int(roc2) if roc2 and roc2 > 0 else 15
|
||||
roc3 = int(roc3) if roc3 and roc3 > 0 else 20
|
||||
roc4 = int(roc4) if roc4 and roc4 > 0 else 30
|
||||
|
||||
sma1 = int(sma1) if sma1 and sma1 > 0 else 10
|
||||
sma2 = int(sma2) if sma2 and sma2 > 0 else 10
|
||||
sma3 = int(sma3) if sma3 and sma3 > 0 else 10
|
||||
sma4 = int(sma4) if sma4 and sma4 > 0 else 15
|
||||
|
||||
signal = v_pos_default(signal, 9)
|
||||
_rmax = max(roc1, roc2, roc3, roc4)
|
||||
_smax = max(sma1, sma2, sma3, sma4)
|
||||
_length = _rmax + _smax
|
||||
close = v_series(close, _length)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
drift = v_drift(drift)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
rocma1 = roc(close, roc1).rolling(sma1).mean()
|
||||
rocma2 = roc(close, roc2).rolling(sma2).mean()
|
||||
rocma3 = roc(close, roc3).rolling(sma3).mean()
|
||||
rocma4 = roc(close, roc4).rolling(sma4).mean()
|
||||
|
||||
kst = 100 * (rocma1 + 2 * rocma2 + 3 * rocma3 + 4 * rocma4)
|
||||
kst_signal = kst.rolling(signal).mean()
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
kst = kst.shift(offset)
|
||||
kst_signal = kst_signal.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
kst.fillna(kwargs["fillna"], inplace=True)
|
||||
kst_signal.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
kst.name = f"KST_{roc1}_{roc2}_{roc3}_{roc4}_{sma1}_{sma2}_{sma3}_{sma4}"
|
||||
kst_signal.name = f"KSTs_{signal}"
|
||||
kst.category = kst_signal.category = "momentum"
|
||||
|
||||
data = {kst.name: kst, kst_signal.name: kst_signal}
|
||||
df = DataFrame(data, index=close.index)
|
||||
df.name = f"KST_{roc1}_{roc2}_{roc3}_{roc4}_{sma1}_{sma2}_{sma3}_{sma4}_{signal}"
|
||||
df.category = "momentum"
|
||||
|
||||
return df
|
||||
@@ -1,141 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import concat, DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.maps import Imports
|
||||
from pandas_ta.overlap import ema
|
||||
from pandas_ta.utils import (
|
||||
signals,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_series,
|
||||
v_talib
|
||||
)
|
||||
|
||||
|
||||
|
||||
def macd(
|
||||
close: Series, fast: Int = None, slow: Int = None,
|
||||
signal: Int = None, talib: bool = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> DataFrame:
|
||||
"""Moving Average Convergence Divergence
|
||||
|
||||
This indicator attempts to identify trends.
|
||||
|
||||
Sources:
|
||||
* [tradingview](https://www.tradingview.com/wiki/MACD_(Moving_Average_Convergence/Divergence))
|
||||
* [tradingview (AS Mode)](https://tr.tradingview.com/script/YFlKXHnP/)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
fast (int): Fast MA period. Default: ```12```
|
||||
slow (int): Slow MA period. Default: ```26```
|
||||
signal (int): Signal period. Default: ```9```
|
||||
talib (bool): If installed, use TA Lib. Default: ```True```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
asmode (value): Enable AS version of MACD. Default: ```False```
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(DataFrame): 3 columns
|
||||
"""
|
||||
# Validate
|
||||
fast = v_pos_default(fast, 12)
|
||||
slow = v_pos_default(slow, 26)
|
||||
signal = v_pos_default(signal, 9)
|
||||
if slow < fast:
|
||||
fast, slow = slow, fast
|
||||
_length = slow + signal - 1
|
||||
close = v_series(close, _length)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
mode_tal = v_talib(talib)
|
||||
offset = v_offset(offset)
|
||||
as_mode = kwargs.setdefault("asmode", False)
|
||||
|
||||
# Calculate
|
||||
if Imports["talib"] and mode_tal:
|
||||
from talib import MACD
|
||||
macd, signalma, histogram = MACD(close, fast, slow, signal)
|
||||
else:
|
||||
fastma = ema(close, length=fast, talib=mode_tal)
|
||||
slowma = ema(close, length=slow, talib=mode_tal)
|
||||
|
||||
macd = fastma - slowma
|
||||
macd_fvi = macd.loc[macd.first_valid_index():, ]
|
||||
signalma = ema(close=macd_fvi, length=signal, talib=mode_tal)
|
||||
histogram = macd - signalma
|
||||
|
||||
if as_mode:
|
||||
macd = macd - signalma
|
||||
macd_fvi = macd.loc[macd.first_valid_index():, ]
|
||||
signalma = ema(close=macd_fvi, length=signal, talib=mode_tal)
|
||||
histogram = macd - signalma
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
macd = macd.shift(offset)
|
||||
histogram = histogram.shift(offset)
|
||||
signalma = signalma.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
macd.fillna(kwargs["fillna"], inplace=True)
|
||||
histogram.fillna(kwargs["fillna"], inplace=True)
|
||||
signalma.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
_asmode = "AS" if as_mode else ""
|
||||
_props = f"_{fast}_{slow}_{signal}"
|
||||
macd.name = f"MACD{_asmode}{_props}"
|
||||
histogram.name = f"MACD{_asmode}h{_props}"
|
||||
signalma.name = f"MACD{_asmode}s{_props}"
|
||||
macd.category = histogram.category = signalma.category = "momentum"
|
||||
|
||||
data = {
|
||||
macd.name: macd,
|
||||
histogram.name: histogram,
|
||||
signalma.name: signalma
|
||||
}
|
||||
df = DataFrame(data, index=close.index)
|
||||
df.name = f"MACD{_asmode}{_props}"
|
||||
df.category = macd.category
|
||||
|
||||
signal_indicators = kwargs.pop("signal_indicators", False)
|
||||
if not signal_indicators:
|
||||
return df
|
||||
else:
|
||||
signalsdf = concat(
|
||||
[
|
||||
df,
|
||||
signals(
|
||||
indicator=histogram,
|
||||
xa=kwargs.pop("xa", 0),
|
||||
xb=kwargs.pop("xb", None),
|
||||
xseries=kwargs.pop("xseries", None),
|
||||
xseries_a=kwargs.pop("xseries_a", None),
|
||||
xseries_b=kwargs.pop("xseries_b", None),
|
||||
cross_values=kwargs.pop("cross_values", True),
|
||||
cross_series=kwargs.pop("cross_series", True),
|
||||
offset=offset,
|
||||
),
|
||||
signals(
|
||||
indicator=macd,
|
||||
xa=kwargs.pop("xa", 0),
|
||||
xb=kwargs.pop("xb", None),
|
||||
xseries=kwargs.pop("xseries", None),
|
||||
xseries_a=kwargs.pop("xseries_a", None),
|
||||
xseries_b=kwargs.pop("xseries_b", None),
|
||||
cross_values=kwargs.pop("cross_values", False),
|
||||
cross_series=kwargs.pop("cross_series", True),
|
||||
offset=offset,
|
||||
),
|
||||
],
|
||||
axis=1,
|
||||
)
|
||||
|
||||
return signalsdf
|
||||
@@ -1,76 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numba import njit
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.maps import Imports
|
||||
from pandas_ta.utils import (
|
||||
nb_idiff,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_series,
|
||||
v_talib
|
||||
)
|
||||
|
||||
|
||||
|
||||
@njit(cache=True)
|
||||
def nb_mom(x, n):
|
||||
return nb_idiff(x, n)
|
||||
|
||||
|
||||
def mom(
|
||||
close: Series, length: Int = None, talib: bool = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Momentum
|
||||
|
||||
This indicator attempts to quantify speed by using the differences over
|
||||
a bar length.
|
||||
|
||||
Sources:
|
||||
* [onlinetradingconcepts](http://www.onlinetradingconcepts.com/TechnicalAnalysis/Momentum.html)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```1```
|
||||
talib (bool): If installed, use TA Lib. Default: ```True```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 10)
|
||||
close = v_series(close, length + 1)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
mode_tal = v_talib(talib)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
if Imports["talib"] and mode_tal:
|
||||
from talib import MOM
|
||||
mom = MOM(close, length)
|
||||
else:
|
||||
np_close = close.to_numpy()
|
||||
_mom = nb_mom(np_close, length)
|
||||
mom = Series(_mom, index=close.index)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
mom = mom.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
mom.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
mom.name = f"MOM_{length}"
|
||||
mom.category = "momentum"
|
||||
|
||||
return mom
|
||||
@@ -1,68 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.overlap import ema, sma
|
||||
from pandas_ta.utils import v_offset, v_pos_default, v_series
|
||||
from pandas_ta.volatility import atr
|
||||
|
||||
|
||||
|
||||
def pgo(
|
||||
high: Series, low: Series, close: Series, length: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Pretty Good Oscillator
|
||||
|
||||
This indicator, by Mark Johnson, attempts to identify breakouts for longer
|
||||
time periods based on the distance of the current bar to its N-day
|
||||
SMA, expressed in terms of an ATR over a similar length.
|
||||
|
||||
Sources:
|
||||
* [tradingtechnologies](https://library.tradingtechnologies.com/trade/chrt-ti-pretty-good-oscillator.html)
|
||||
|
||||
Parameters:
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```14```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
|
||||
Note: Entry
|
||||
* Long when greater than 3.
|
||||
* Short when less than -3.
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 14)
|
||||
_length = 2 * length
|
||||
high = v_series(high, _length)
|
||||
low = v_series(low, _length)
|
||||
close = v_series(close, _length)
|
||||
|
||||
if high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
pgo = (close - sma(close, length)) \
|
||||
/ ema(atr(high, low, close, length), length)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
pgo = pgo.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
pgo.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
pgo.name = f"PGO_{length}"
|
||||
pgo.category = "momentum"
|
||||
|
||||
return pgo
|
||||
@@ -1,107 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import isnan
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.ma import ma
|
||||
from pandas_ta.maps import Imports
|
||||
from pandas_ta.utils import (
|
||||
tal_ma,
|
||||
v_mamode,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_scalar,
|
||||
v_series,
|
||||
v_talib
|
||||
)
|
||||
|
||||
|
||||
|
||||
def ppo(
|
||||
close: Series, fast: Int = None, slow: Int = None, signal: Int = None,
|
||||
scalar: IntFloat = None, mamode: str = None, talib: bool = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> DataFrame:
|
||||
"""Percentage Price Oscillator
|
||||
|
||||
Similar to MACD.
|
||||
|
||||
Sources:
|
||||
* [investopedia](https://www.investopedia.com/terms/p/ppo.asp)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
fast (int): Fast MA period. Default: ```12```
|
||||
slow (int): Slow MA period. Default: ```26```
|
||||
signal (int): Signal period. Default: ```9```
|
||||
scalar (float): Scalar. Default: ```100```
|
||||
mamode (str): See ```help(ta.ma)```. Default: ```"sma"```
|
||||
talib (bool): If installed, use TA Lib. Default: ```True```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(DataFrame): 3 columns
|
||||
"""
|
||||
# Validate
|
||||
fast = v_pos_default(fast, 12)
|
||||
slow = v_pos_default(slow, 26)
|
||||
signal = v_pos_default(signal, 9)
|
||||
if slow < fast:
|
||||
fast, slow = slow, fast
|
||||
_length = max(fast, slow, signal)
|
||||
close = v_series(close, _length)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
scalar = v_scalar(scalar, 100)
|
||||
mamode = v_mamode(mamode, "sma")
|
||||
mode_tal = v_talib(talib)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
if Imports["talib"] and mode_tal:
|
||||
from talib import PPO
|
||||
ppo = PPO(close, fast, slow, tal_ma(mamode))
|
||||
else:
|
||||
fastma = ma(mamode, close, length=fast, talib=mode_tal)
|
||||
slowma = ma(mamode, close, length=slow, talib=mode_tal)
|
||||
ppo = scalar * (fastma - slowma) / slowma
|
||||
|
||||
if all(isnan(ppo)):
|
||||
return # Emergency Break
|
||||
|
||||
signalma = ma("ema", ppo, length=signal, talib=mode_tal)
|
||||
histogram = ppo - signalma
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
ppo = ppo.shift(offset)
|
||||
histogram = histogram.shift(offset)
|
||||
signalma = signalma.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
ppo.fillna(kwargs["fillna"], inplace=True)
|
||||
histogram.fillna(kwargs["fillna"], inplace=True)
|
||||
signalma.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
_props = f"_{fast}_{slow}_{signal}"
|
||||
ppo.name = f"PPO{_props}"
|
||||
histogram.name = f"PPOh{_props}"
|
||||
signalma.name = f"PPOs{_props}"
|
||||
ppo.category = histogram.category = signalma.category = "momentum"
|
||||
|
||||
data = {
|
||||
ppo.name: ppo,
|
||||
histogram.name: histogram,
|
||||
signalma.name: signalma
|
||||
}
|
||||
df = DataFrame(data, index=close.index)
|
||||
df.name = f"PPO{_props}"
|
||||
df.category = ppo.category
|
||||
|
||||
return df
|
||||
@@ -1,79 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import sign
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.utils import (
|
||||
v_drift,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_scalar,
|
||||
v_series
|
||||
)
|
||||
|
||||
|
||||
|
||||
def psl(
|
||||
close: Series, open_: Series = None,
|
||||
length: Int = None, scalar: IntFloat = None, drift: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Psychological Line
|
||||
|
||||
This indicator compares the number of the rising bars to the total number
|
||||
of bars. In other words, it is the percentage of bars that are above the
|
||||
previous bar over a given length.
|
||||
|
||||
Sources:
|
||||
* [quantshare](https://www.quantshare.com/item-851-psychological-line)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
open_ (Series): ```open``` Series
|
||||
length (int): The period. Default: ```12```
|
||||
scalar (float): Scalar. Default: ```100```
|
||||
drift (int): Difference amount. Default: ```1```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 12)
|
||||
close = v_series(close, length)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
scalar = v_scalar(scalar, 100)
|
||||
drift = v_drift(drift)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
if open_ is not None:
|
||||
open_ = v_series(open_)
|
||||
diff = sign(close - open_)
|
||||
else:
|
||||
diff = sign(close.diff(drift))
|
||||
|
||||
diff.fillna(0, inplace=True)
|
||||
diff[diff <= 0] = 0 # Set negative values to zero
|
||||
|
||||
psl = scalar * diff.rolling(length).sum() / length
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
psl = psl.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
psl.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
_props = f"_{length}"
|
||||
psl.name = f"PSL{_props}"
|
||||
psl.category = "momentum"
|
||||
|
||||
return psl
|
||||
@@ -1,174 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import isnan, maximum, minimum, nan
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.ma import ma
|
||||
from pandas_ta.utils import (
|
||||
v_drift,
|
||||
v_mamode,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_scalar,
|
||||
v_series
|
||||
)
|
||||
from .rsi import rsi
|
||||
|
||||
|
||||
|
||||
def qqe(
|
||||
close: Series, length: Int = None,
|
||||
smooth: Int = None, factor: IntFloat = None,
|
||||
mamode: str = None, drift: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> DataFrame:
|
||||
"""Quantitative Qualitative Estimation
|
||||
|
||||
This indicator is similar to SuperTrend but uses a Smoothed ```rsi```
|
||||
with upper and lower bands.
|
||||
|
||||
Sources:
|
||||
* [prorealcode](https://www.prorealcode.com/prorealtime-indicators/qqe-quantitative-qualitative-estimation/)
|
||||
* [tradingpedia](https://www.tradingpedia.com/forex-trading-indicators/quantitative-qualitative-estimation)
|
||||
* [tradingview](https://www.tradingview.com/script/IYfA9R2k-QQE-MT4/)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
length (int): RSI period. Default: ```14```
|
||||
smooth (int): RSI smoothing period. Default: ```5```
|
||||
factor (float): QQE Factor. Default: ```4.236```
|
||||
mamode (str): See ```help(ta.ma)```. Default: ```"ema"```
|
||||
drift (int): Difference amount. Default: ```1```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(DataFrame): 4 columns
|
||||
|
||||
Tip: Trend
|
||||
* Long: When the Smoothed RSI crosses the previous upperband.
|
||||
* Short: When the Smoothed RSI crosses the previous lowerband.
|
||||
|
||||
Note: See also
|
||||
* QQE.mq5 by EarnForex Copyright © 2010
|
||||
* Tim Hyder (2008) version
|
||||
* Roman Ignatov (2006) version
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 14)
|
||||
smooth = v_pos_default(smooth, 5)
|
||||
wilders_length = 2 * length - 1
|
||||
_length = wilders_length + smooth
|
||||
close = v_series(close, _length)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
factor = v_scalar(factor, 4.236)
|
||||
mamode = v_mamode(mamode, "ema")
|
||||
drift = v_drift(drift)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
rsi_ = rsi(close, length)
|
||||
_mode = mamode.lower()[0] if mamode != "ema" else ""
|
||||
rsi_ma = ma(mamode, rsi_, length=smooth)
|
||||
|
||||
# RSI MA True Range
|
||||
rsi_ma_tr = rsi_ma.diff(drift).abs()
|
||||
if all(isnan(rsi_ma_tr)):
|
||||
return
|
||||
|
||||
# Double Smooth the RSI MA True Range using Wilder's Length with a default
|
||||
# width of 4.236.
|
||||
smoothed_rsi_tr_ma = ma("ema", rsi_ma_tr, length=wilders_length)
|
||||
if all(isnan(smoothed_rsi_tr_ma)):
|
||||
return # Emergency Break
|
||||
dar = factor * ma("ema", smoothed_rsi_tr_ma, length=wilders_length)
|
||||
if all(isnan(dar)):
|
||||
return # Emergency Break
|
||||
|
||||
# Create the Upper and Lower Bands around RSI MA.
|
||||
upperband = rsi_ma + dar
|
||||
lowerband = rsi_ma - dar
|
||||
|
||||
m = close.size
|
||||
long = Series(0, index=close.index)
|
||||
short = Series(0, index=close.index)
|
||||
trend = Series(1, index=close.index)
|
||||
qqe = Series(rsi_ma.iat[0], index=close.index)
|
||||
qqe_long = Series(nan, index=close.index)
|
||||
qqe_short = Series(nan, index=close.index)
|
||||
|
||||
for i in range(1, m):
|
||||
c_rsi, p_rsi = rsi_ma.iat[i], rsi_ma.iat[i - 1]
|
||||
c_long, p_long = long.iat[i - 1], long.iat[i - 2]
|
||||
c_short, p_short = short.iat[i - 1], short.iat[i - 2]
|
||||
|
||||
# Long Line
|
||||
if p_rsi > c_long and c_rsi > c_long:
|
||||
long.iat[i] = maximum(c_long, lowerband.iat[i])
|
||||
else:
|
||||
long.iat[i] = lowerband.iat[i]
|
||||
|
||||
# Short Line
|
||||
if p_rsi < c_short and c_rsi < c_short:
|
||||
short.iat[i] = minimum(c_short, upperband.iat[i])
|
||||
else:
|
||||
short.iat[i] = upperband.iat[i]
|
||||
|
||||
# Trend & QQE Calculation
|
||||
# Long: Current RSI_MA value Crosses the Prior Short Line Value
|
||||
# Short: Current RSI_MA Crosses the Prior Long Line Value
|
||||
if (c_rsi > c_short and p_rsi < p_short) or \
|
||||
(c_rsi <= c_short and p_rsi >= p_short):
|
||||
trend.iat[i] = 1
|
||||
qqe.iat[i] = qqe_long.iat[i] = long.iat[i]
|
||||
elif (c_rsi > c_long and p_rsi < p_long) or \
|
||||
(c_rsi <= c_long and p_rsi >= p_long):
|
||||
trend.iat[i] = -1
|
||||
qqe.iat[i] = qqe_short.iat[i] = short.iat[i]
|
||||
else:
|
||||
trend.iat[i] = trend.iat[i - 1]
|
||||
if trend.iat[i] == 1:
|
||||
qqe.iat[i] = qqe_long.iat[i] = long.iat[i]
|
||||
else:
|
||||
qqe.iat[i] = qqe_short.iat[i] = short.iat[i]
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
rsi_ma = rsi_ma.shift(offset)
|
||||
qqe = qqe.shift(offset)
|
||||
long = long.shift(offset)
|
||||
short = short.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
rsi_ma.fillna(kwargs["fillna"], inplace=True)
|
||||
qqe.fillna(kwargs["fillna"], inplace=True)
|
||||
qqe_long.fillna(kwargs["fillna"], inplace=True)
|
||||
qqe_short.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
_props = f"{_mode}_{length}_{smooth}_{factor}"
|
||||
qqe.name = f"QQE{_props}"
|
||||
rsi_ma.name = f"QQE{_props}_RSI{_mode.upper()}MA"
|
||||
qqe_long.name = f"QQEl{_props}"
|
||||
qqe_short.name = f"QQEs{_props}"
|
||||
qqe.category = rsi_ma.category = "momentum"
|
||||
qqe_long.category = qqe_short.category = qqe.category
|
||||
|
||||
data = {
|
||||
qqe.name: qqe,
|
||||
rsi_ma.name: rsi_ma,
|
||||
# long.name: long,
|
||||
# short.name: short
|
||||
qqe_long.name: qqe_long,
|
||||
qqe_short.name: qqe_short
|
||||
}
|
||||
df = DataFrame(data, index=close.index)
|
||||
df.name = f"QQE{_props}"
|
||||
df.category = qqe.category
|
||||
|
||||
return df
|
||||
@@ -1,84 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numba import njit
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.maps import Imports
|
||||
from pandas_ta.utils import (
|
||||
nb_idiff,
|
||||
nb_shift,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_scalar,
|
||||
v_series,
|
||||
v_talib
|
||||
)
|
||||
# from .mom import mom
|
||||
|
||||
|
||||
|
||||
@njit(cache=True)
|
||||
def nb_roc(x, n, k):
|
||||
return k * nb_idiff(x, n) / nb_shift(x, n)
|
||||
|
||||
|
||||
def roc(
|
||||
close: Series, length: Int = None,
|
||||
scalar: IntFloat = None, talib: bool = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Rate of Change
|
||||
|
||||
This indicator, also (confusingly) known as Momentum, is a pure
|
||||
oscillator that quantifies the percent change.
|
||||
|
||||
Sources:
|
||||
* [tradingview](https://www.tradingview.com/wiki/Rate_of_Change_(ROC))
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```10```
|
||||
scalar (float): Scalar. Default: ```100```
|
||||
talib (bool): If installed, use TA Lib. Default: ```True```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 10)
|
||||
close = v_series(close, length + 1)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
scalar = v_scalar(scalar, 100)
|
||||
mode_tal = v_talib(talib)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
if Imports["talib"] and mode_tal:
|
||||
from talib import ROC
|
||||
roc = ROC(close, length)
|
||||
else:
|
||||
# roc = scalar * mom(close=close, length=length, talib=mode_tal) \
|
||||
# / close.shift(length)
|
||||
np_close = close.to_numpy()
|
||||
_roc = nb_roc(np_close, length, scalar)
|
||||
roc = Series(_roc, index=close.index)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
roc = roc.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
roc.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
roc.name = f"ROC_{length}"
|
||||
roc.category = "momentum"
|
||||
|
||||
return roc
|
||||
@@ -1,115 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import DataFrame, Series, concat
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.maps import Imports
|
||||
from pandas_ta.ma import ma
|
||||
from pandas_ta.utils import (
|
||||
signals,
|
||||
v_drift,
|
||||
v_mamode,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_scalar,
|
||||
v_series,
|
||||
v_talib
|
||||
)
|
||||
|
||||
|
||||
|
||||
def rsi(
|
||||
close: Series, length: Int = None, scalar: IntFloat = None,
|
||||
mamode: str = None, talib: bool = None,
|
||||
drift: Int = None, offset: Int = None,
|
||||
**kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Relative Strength Index
|
||||
|
||||
This oscillator used to attempts to quantify "velocity" and "magnitude".
|
||||
|
||||
Sources:
|
||||
* [tradingview](https://www.tradingview.com/wiki/Relative_Strength_Index_(RSI))
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```14```
|
||||
scalar (float): Scalar. Default: ```100```
|
||||
mamode (str): See ```help(ta.ma)```. Default: ```"rma"```
|
||||
talib (bool): If installed, use TA Lib. Default: ```True```
|
||||
drift (int): Difference amount. Default: ```1```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
|
||||
Warning:
|
||||
TA-Lib Correlation: ```np.float64(0.9289853267851295)```
|
||||
|
||||
Tip:
|
||||
Corrective contributions welcome!
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 14)
|
||||
close = v_series(close, length + 1)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
scalar = v_scalar(scalar, 100)
|
||||
mamode = v_mamode(mamode, "rma")
|
||||
mode_tal = v_talib(talib)
|
||||
drift = v_drift(drift)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
if Imports["talib"] and mode_tal:
|
||||
from talib import RSI
|
||||
rsi = RSI(close, length)
|
||||
else:
|
||||
negative = close.diff(drift)
|
||||
positive = negative.copy()
|
||||
|
||||
positive[positive < 0] = 0 # Make negatives 0 for the positive series
|
||||
negative[negative > 0] = 0 # Make positives 0 for the negative series
|
||||
|
||||
positive_avg = ma(mamode, positive, length=length, talib=mode_tal)
|
||||
negative_avg = ma(mamode, negative, length=length, talib=mode_tal)
|
||||
|
||||
rsi = scalar * positive_avg / (positive_avg + negative_avg.abs())
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
rsi = rsi.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
rsi.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
rsi.name = f"RSI_{length}"
|
||||
rsi.category = "momentum"
|
||||
|
||||
signal_indicators = kwargs.pop("signal_indicators", False)
|
||||
if not signal_indicators:
|
||||
return rsi
|
||||
else:
|
||||
signalsdf = concat(
|
||||
[
|
||||
DataFrame({rsi.name: rsi}),
|
||||
signals(
|
||||
indicator=rsi,
|
||||
xa=kwargs.pop("xa", 80),
|
||||
xb=kwargs.pop("xb", 20),
|
||||
xseries=kwargs.pop("xseries", None),
|
||||
xseries_a=kwargs.pop("xseries_a", None),
|
||||
xseries_b=kwargs.pop("xseries_b", None),
|
||||
cross_values=kwargs.pop("cross_values", False),
|
||||
cross_series=kwargs.pop("cross_series", True),
|
||||
offset=offset,
|
||||
),
|
||||
],
|
||||
axis=1,
|
||||
)
|
||||
return signalsdf
|
||||
@@ -1,148 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import nan
|
||||
from pandas import DataFrame, Series, concat
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.utils import (
|
||||
signals,
|
||||
v_drift,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_series
|
||||
)
|
||||
|
||||
|
||||
|
||||
def rsx(
|
||||
close: Series, length: Int = None, drift: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Relative Strength Xtra
|
||||
|
||||
This indicator, by Jurik Research, is an enhanced version of the RSI which
|
||||
attemps to reduce noise and provide a clearer, though slightly
|
||||
delayed, signal.
|
||||
|
||||
Sources:
|
||||
* [jurikres](http://www.jurikres.com/catalog1/ms_rsx.htm)
|
||||
* [prorealcode](https://www.prorealcode.com/prorealtime-indicators/jurik-rsx/)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```14```
|
||||
drift (int): Difference amount. Default: ```1```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 14)
|
||||
close = v_series(close, length)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
drift = v_drift(drift)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
m = close.size
|
||||
vC, v1C = 0, 0
|
||||
v4, v8, v10, v14, v18, v20 = 0, 0, 0, 0, 0, 0
|
||||
|
||||
f0, f8, f10, f18, f20, f28, f30, f38 = 0, 0, 0, 0, 0, 0, 0, 0
|
||||
f40, f48, f50, f58, f60, f68, f70, f78 = 0, 0, 0, 0, 0, 0, 0, 0
|
||||
f80, f88, f90 = 0, 0, 0
|
||||
|
||||
result = [nan for _ in range(0, length - 1)] + [50]
|
||||
for i in range(length, m):
|
||||
if f90 == 0:
|
||||
f90 = 1.0
|
||||
f0 = 0.0
|
||||
if length - 1.0 >= 5:
|
||||
f88 = length - 1.0
|
||||
else:
|
||||
f88 = 5.0
|
||||
f8 = 100.0 * close.iat[i]
|
||||
f18 = 3.0 / (length + 2.0)
|
||||
f20 = 1.0 - f18
|
||||
else:
|
||||
if f88 <= f90:
|
||||
f90 = f88 + 1
|
||||
else:
|
||||
f90 = f90 + 1
|
||||
f10 = f8
|
||||
f8 = 100 * close.iat[i]
|
||||
v8 = f8 - f10
|
||||
f28 = f20 * f28 + f18 * v8
|
||||
f30 = f18 * f28 + f20 * f30
|
||||
vC = 1.5 * f28 - 0.5 * f30
|
||||
f38 = f20 * f38 + f18 * vC
|
||||
f40 = f18 * f38 + f20 * f40
|
||||
v10 = 1.5 * f38 - 0.5 * f40
|
||||
f48 = f20 * f48 + f18 * v10
|
||||
f50 = f18 * f48 + f20 * f50
|
||||
v14 = 1.5 * f48 - 0.5 * f50
|
||||
f58 = f20 * f58 + f18 * abs(v8)
|
||||
f60 = f18 * f58 + f20 * f60
|
||||
v18 = 1.5 * f58 - 0.5 * f60
|
||||
f68 = f20 * f68 + f18 * v18
|
||||
f70 = f18 * f68 + f20 * f70
|
||||
v1C = 1.5 * f68 - 0.5 * f70
|
||||
f78 = f20 * f78 + f18 * v1C
|
||||
f80 = f18 * f78 + f20 * f80
|
||||
v20 = 1.5 * f78 - 0.5 * f80
|
||||
|
||||
if f88 >= f90 and f8 != f10:
|
||||
f0 = 1.0
|
||||
if f88 == f90 and f0 == 0.0:
|
||||
f90 = 0.0
|
||||
|
||||
if f88 < f90 and v20 > 0.0000000001:
|
||||
v4 = (v14 / v20 + 1.0) * 50.0
|
||||
if v4 > 100.0:
|
||||
v4 = 100.0
|
||||
if v4 < 0.0:
|
||||
v4 = 0.0
|
||||
else:
|
||||
v4 = 50.0
|
||||
result.append(v4)
|
||||
rsx = Series(result, index=close.index)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
rsx = rsx.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
rsx.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
rsx.name = f"RSX_{length}"
|
||||
rsx.category = "momentum"
|
||||
|
||||
signal_indicators = kwargs.pop("signal_indicators", False)
|
||||
if not signal_indicators:
|
||||
return rsx
|
||||
else:
|
||||
signalsdf = concat(
|
||||
[
|
||||
DataFrame({rsx.name: rsx}),
|
||||
signals(
|
||||
indicator=rsx,
|
||||
xa=kwargs.pop("xa", 80),
|
||||
xb=kwargs.pop("xb", 20),
|
||||
xseries=kwargs.pop("xseries", None),
|
||||
xseries_a=kwargs.pop("xseries_a", None),
|
||||
xseries_b=kwargs.pop("xseries_b", None),
|
||||
cross_values=kwargs.pop("cross_values", False),
|
||||
cross_series=kwargs.pop("cross_series", True),
|
||||
offset=offset,
|
||||
),
|
||||
],
|
||||
axis=1
|
||||
)
|
||||
return signalsdf
|
||||
@@ -1,87 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import isnan
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.overlap import swma
|
||||
from pandas_ta.utils import non_zero_range, v_offset, v_pos_default, v_series
|
||||
|
||||
|
||||
|
||||
def rvgi(
|
||||
open_: Series, high: Series, low: Series, close: Series,
|
||||
length: Int = None, swma_length: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Relative Vigor Index
|
||||
|
||||
This indicator attempts to quantify the strength of a trend relative to
|
||||
its trading range.
|
||||
|
||||
Sources:
|
||||
* [investopedia](https://www.investopedia.com/terms/r/relative_vigor_index.asp)
|
||||
|
||||
Parameters:
|
||||
open_ (Series): ```open``` Series
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```14```
|
||||
swma_length (int): SWMA period. Default: ```4```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 14)
|
||||
swma_length = v_pos_default(swma_length, 4)
|
||||
_length = length + swma_length - 1
|
||||
open_ = v_series(open_, _length)
|
||||
high = v_series(high, _length)
|
||||
low = v_series(low, _length)
|
||||
close = v_series(close, _length)
|
||||
|
||||
if open_ is None or high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
high_low_range = non_zero_range(high, low)
|
||||
close_open_range = non_zero_range(close, open_)
|
||||
|
||||
numerator = swma(close_open_range, length=swma_length) \
|
||||
.rolling(length).sum()
|
||||
denominator = swma(high_low_range, length=swma_length) \
|
||||
.rolling(length).sum()
|
||||
|
||||
rvgi = numerator / denominator
|
||||
signal = swma(rvgi, length=swma_length)
|
||||
|
||||
if all(isnan(signal.to_numpy())):
|
||||
return # Emergency Break
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
rvgi = rvgi.shift(offset)
|
||||
signal = signal.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
rvgi.fillna(kwargs["fillna"], inplace=True)
|
||||
signal.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
rvgi.name = f"RVGI_{length}_{swma_length}"
|
||||
signal.name = f"RVGIs_{length}_{swma_length}"
|
||||
rvgi.category = signal.category = "momentum"
|
||||
|
||||
data = {rvgi.name: rvgi, signal.name: signal}
|
||||
df = DataFrame(data, index=close.index)
|
||||
df.name = f"RVGI_{length}_{swma_length}"
|
||||
df.category = rvgi.category
|
||||
|
||||
return df
|
||||
@@ -1,71 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import arctan, rad2deg
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.utils import (
|
||||
nb_idiff,
|
||||
v_bool,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_series
|
||||
)
|
||||
|
||||
|
||||
|
||||
def slope(
|
||||
close: Series, length: Int = None,
|
||||
as_angle: bool = None, to_degrees: bool = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Slope
|
||||
|
||||
Calculates a rolling slope.
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```1```
|
||||
as_angle (bool): Converts slope to an angle in radians
|
||||
per ```np.arctan()```. Default: ```False```
|
||||
to_degrees (value): If ```as_angle=True```, converts radians to
|
||||
degrees. Default: ```False```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 1)
|
||||
close = v_series(close, length + 1)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
as_angle = v_bool(as_angle, False)
|
||||
to_degrees = v_bool(to_degrees, False)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
np_close = close.to_numpy()
|
||||
_slope = nb_idiff(np_close, length) / length
|
||||
if as_angle:
|
||||
_slope = arctan(_slope)
|
||||
if to_degrees:
|
||||
_slope = rad2deg(_slope)
|
||||
slope = Series(_slope, index=close.index)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
slope = slope.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
slope.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
slope.name = f"SLOPE_{length}" if not as_angle else f"ANGLE{'d' if to_degrees else 'r'}_{length}"
|
||||
slope.category = "momentum"
|
||||
|
||||
return slope
|
||||
@@ -1,118 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from sys import float_info as sflt
|
||||
from numpy import maximum, minimum
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.ma import ma
|
||||
from pandas_ta.utils import (
|
||||
v_bool,
|
||||
v_mamode,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_scalar,
|
||||
v_series,
|
||||
v_talib
|
||||
)
|
||||
|
||||
|
||||
def smc(
|
||||
open_: Series, high: Series, low: Series, close: Series,
|
||||
abr_length: Int = None, close_length: Int = None, vol_length: Int = None,
|
||||
percent: Int = None, vol_ratio: IntFloat = None, asint: bool = None,
|
||||
mamode: str = None, talib: bool = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> DictLike:
|
||||
"""Smart Money Concept
|
||||
|
||||
This indicator combines several techniques in an attempt to identify
|
||||
significant movements that might indicate "smart money" actions.
|
||||
It uses candlestick patterns, moving averages, and imbalance calculations.
|
||||
|
||||
Sources:
|
||||
* [tradingview](https://www.tradingview.com/script/CnB3fSph-Smart-Money-Concepts-LuxAlgo/)
|
||||
|
||||
Parameters:
|
||||
abr_length (int): ABR length. Default: ```14```
|
||||
close_length (int): The ```close``` MA period. Default: ```50```
|
||||
vol_length (int): Volatility period. Default: ```20```
|
||||
percent (int): Percent of wick that exceeds the body. Default: ```5```
|
||||
vol_ratio (float): Volatility ratio (high) limit. Default: ```1.5```
|
||||
asint (bool): Returns as ```Int```. Default: ```True```
|
||||
mamode (str): See ```help(ta.ma)```. Default: ```"sma"```
|
||||
talib (bool): If installed, use TA Lib. Default: ```True```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Returns:
|
||||
(DataFrame): 7 columns
|
||||
"""
|
||||
# Validate
|
||||
abr_length = v_pos_default(abr_length, 14)
|
||||
close_length = v_pos_default(close_length, 50)
|
||||
vol_length = v_pos_default(vol_length, 20)
|
||||
if close_length < abr_length:
|
||||
abr_length, close_length = close_length, abr_length
|
||||
_length = max(abr_length, close_length, vol_length) + 1
|
||||
|
||||
open_ = v_series(open_, _length)
|
||||
high = v_series(high, _length)
|
||||
low = v_series(low, _length)
|
||||
close = v_series(close, _length)
|
||||
|
||||
if open_ is None or high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
percent = v_pos_default(percent, 5)
|
||||
body_percent = 0.01 * percent
|
||||
vol_ratio = v_scalar(vol_ratio, 1.5)
|
||||
asint = v_bool(asint)
|
||||
mamode = v_mamode(mamode, "sma")
|
||||
mode_tal = v_talib(talib)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
body_high, body_low = maximum(open_, close), minimum(open_, close)
|
||||
body = body_high - body_low + sflt.epsilon
|
||||
close_ma = ma(mamode, body, length=close_length, talib=mode_tal)
|
||||
|
||||
# Calculate imbalance sizes and percentages based on Average Bar Range (abr)
|
||||
abr = high.rolling(window=abr_length).max() - low.rolling(window=abr_length).min()
|
||||
top_imbalance = low.shift(2) - high
|
||||
btm_imbalance = low - high.shift(2)
|
||||
top_imbalance_pct = 100 * top_imbalance / abr
|
||||
btm_imbalance_pct = 100 * btm_imbalance / abr
|
||||
hld = high - low + sflt.epsilon
|
||||
high_volatility = hld > vol_ratio * ma(mamode, hld, length=vol_length, talib=mode_tal)
|
||||
|
||||
btm_imbalance_flag = (btm_imbalance > 0) & (btm_imbalance_pct > 1)
|
||||
top_imbalance_flag = (top_imbalance > 0) & (top_imbalance_pct > 1)
|
||||
|
||||
if asint:
|
||||
high_volatility = high_volatility.astype(int)
|
||||
btm_imbalance_flag = btm_imbalance_flag.astype(int)
|
||||
top_imbalance_flag = top_imbalance_flag.astype(int)
|
||||
|
||||
_props = f"_{abr_length}_{close_length}_{vol_length}_{percent}"
|
||||
data = {
|
||||
f"SMChv{_props}": high_volatility,
|
||||
f"SMCbf{_props}": btm_imbalance_flag,
|
||||
f"SMCbi{_props}": btm_imbalance,
|
||||
f"SMCbp{_props}": btm_imbalance_pct,
|
||||
f"SMCtf{_props}": top_imbalance_flag,
|
||||
f"SMCti{_props}": top_imbalance,
|
||||
f"SMCtp{_props}": top_imbalance_pct,
|
||||
}
|
||||
df = DataFrame(data, index=close.index)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
df = df.shift(offset)
|
||||
|
||||
# Fill
|
||||
df.ffill(inplace=True)
|
||||
df.bfill(inplace=True)
|
||||
|
||||
# Name and Category
|
||||
df.name = f"SMC{_props}"
|
||||
df.category = "momentum"
|
||||
|
||||
return df
|
||||
@@ -1,92 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import isnan
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.utils import v_offset, v_pos_default, v_scalar, v_series
|
||||
from .tsi import tsi
|
||||
|
||||
|
||||
|
||||
def smi(
|
||||
close: Series, fast: Int = None, slow: Int = None,
|
||||
signal: Int = None, scalar: IntFloat = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> DataFrame:
|
||||
"""SMI Ergodic Indicator
|
||||
|
||||
This indicator, by William Blau, is the same as the TSI except the SMI
|
||||
includes a signal line. A trend is considered bullish when crossing above
|
||||
zero and bearish when crossing below zero. This implementation includes
|
||||
both the SMI Ergodic Indicator and SMI Ergodic Oscillator.
|
||||
|
||||
Sources:
|
||||
* [motivewave](https://www.motivewave.com/studies/smi_ergodic_indicator.htm)
|
||||
* [tradingview A](https://www.tradingview.com/script/Xh5Q0une-SMI-Ergodic-Oscillator/)
|
||||
* [tradingview B](https://www.tradingview.com/script/cwrgy4fw-SMIIO/)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
fast (int): The short period. Default: ```5```
|
||||
slow (int): The long period. Default: ```20```
|
||||
signal (int): Signal period. Default: ```5```
|
||||
scalar (float): Scalar. Default: ```1```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(DataFrame): 3 columns
|
||||
"""
|
||||
# Validate
|
||||
fast = v_pos_default(fast, 5)
|
||||
slow = v_pos_default(slow, 20)
|
||||
signal = v_pos_default(signal, 5)
|
||||
if slow < fast:
|
||||
fast, slow = slow, fast
|
||||
_length = slow + signal + 1
|
||||
close = v_series(close, _length)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
scalar = v_scalar(scalar, 1)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
tsi_df = tsi(close, fast=fast, slow=slow, signal=signal, scalar=scalar)
|
||||
if tsi_df is None:
|
||||
return # Emergency Break
|
||||
|
||||
smi = tsi_df.iloc[:, 0]
|
||||
signalma = tsi_df.iloc[:, 1]
|
||||
if all(isnan(signalma)):
|
||||
return # Emergency Break
|
||||
osc = smi - signalma
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
smi = smi.shift(offset)
|
||||
signalma = signalma.shift(offset)
|
||||
osc = osc.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
smi.fillna(kwargs["fillna"], inplace=True)
|
||||
signalma.fillna(kwargs["fillna"], inplace=True)
|
||||
osc.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
# _scalar = f"_{scalar}" if scalar != 1 else ""
|
||||
_props = f"_{fast}_{slow}_{signal}_{scalar}"
|
||||
smi.name = f"SMI{_props}"
|
||||
signalma.name = f"SMIs{_props}"
|
||||
osc.name = f"SMIo{_props}"
|
||||
smi.category = signalma.category = osc.category = "momentum"
|
||||
|
||||
data = {smi.name: smi, signalma.name: signalma, osc.name: osc}
|
||||
df = DataFrame(data, index=close.index)
|
||||
df.name = f"SMI{_props}"
|
||||
df.category = smi.category
|
||||
|
||||
return df
|
||||
@@ -1,205 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import nan
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.overlap import ema, linreg, sma
|
||||
from pandas_ta.trend import decreasing, increasing
|
||||
from pandas_ta.utils import (
|
||||
simplify_columns,
|
||||
unsigned_differences,
|
||||
v_bool,
|
||||
v_mamode,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_series
|
||||
)
|
||||
from pandas_ta.volatility import bbands, kc
|
||||
from .mom import mom
|
||||
|
||||
|
||||
|
||||
def squeeze(
|
||||
high: Series, low: Series, close: Series,
|
||||
bb_length: Int = None, bb_std: IntFloat = None,
|
||||
kc_length: Int = None, kc_scalar: IntFloat = None,
|
||||
mom_length: Int = None, mom_smooth: Int = None,
|
||||
use_tr: bool = None, mamode: str = None,
|
||||
prenan: bool = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> DataFrame:
|
||||
"""Squeeze
|
||||
|
||||
This indicator, based on John Carter's "TTM Squeeze" indicator, attempts
|
||||
identify momentum using volatility.
|
||||
|
||||
Sources:
|
||||
* "Mastering the Trade" (chapter 11), John Carter
|
||||
* [thinkorswim](https://tlc.thinkorswim.com/center/reference/Tech-Indicators/studies-library/T-U/TTM-Squeeze)
|
||||
* [tradestation](https://tradestation.tradingappstore.com/products/TTMSqueeze)
|
||||
* [tradingview](https://www.tradingview.com/scripts/lazybear/)
|
||||
|
||||
Parameters:
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
close (Series): ```close``` Series
|
||||
bb_length (int): BB period. Default: ```20```
|
||||
bb_std (float): BB Std. Dev. Default: ```2```
|
||||
kc_length (int): KC period. Default: ```20```
|
||||
kc_scalar (float): KC scalar. Default: ```1.5```
|
||||
mom_length (int): Momentum Period. Default: ```12```
|
||||
mom_smooth (int): Momentum Smoothing period. Default: ```6```
|
||||
mamode (str): One of: "ema" or "sma". Default: ```"sma"```
|
||||
prenan (bool): Apply prenans. Default: ```False```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
tr (value): Use True Range for Keltner Channels. Default: ```True```
|
||||
asint (bool): Returns as ```Int```. Default: ```True```
|
||||
lazybear (value): LazyBear's TradingView. Default: ```False```
|
||||
detailed (value): Extra detailed. Default: ```False```
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(DataFrame):
|
||||
* Default: 4 columns
|
||||
* Detailed: 10 columns
|
||||
|
||||
Note: Volatility
|
||||
* Increasing: ```kc``` and ```bbands``` difference increases
|
||||
* Decreasing: ```kc``` and ```bbands``` difference decreases
|
||||
"""
|
||||
# Validate
|
||||
bb_length = v_pos_default(bb_length, 20)
|
||||
kc_length = v_pos_default(kc_length, 20)
|
||||
mom_length = v_pos_default(mom_length, 12)
|
||||
mom_smooth = v_pos_default(mom_smooth, 6)
|
||||
_length = max(bb_length, kc_length, mom_length, mom_smooth) + 1
|
||||
high = v_series(high, _length)
|
||||
low = v_series(low, _length)
|
||||
close = v_series(close, _length)
|
||||
|
||||
if high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
bb_std = v_pos_default(bb_std, 2.0)
|
||||
kc_scalar = v_pos_default(kc_scalar, 1.5)
|
||||
mamode = v_mamode(mamode, "sma")
|
||||
prenan = v_bool(prenan, False)
|
||||
offset = v_offset(offset)
|
||||
|
||||
use_tr = kwargs.pop("tr", True)
|
||||
asint = kwargs.pop("asint", True)
|
||||
detailed = kwargs.pop("detailed", False)
|
||||
lazybear = kwargs.pop("lazybear", False)
|
||||
|
||||
# Calculate
|
||||
bbd = bbands(close, length=bb_length, std=bb_std, mamode=mamode)
|
||||
kch = kc(
|
||||
high, low, close, length=kc_length, scalar=kc_scalar,
|
||||
mamode=mamode, tr=use_tr
|
||||
)
|
||||
|
||||
# Simplify KC and BBAND column names for dynamic access
|
||||
bbd.columns = simplify_columns(bbd)
|
||||
kch.columns = simplify_columns(kch)
|
||||
|
||||
if lazybear:
|
||||
highest_high = high.rolling(kc_length).max()
|
||||
lowest_low = low.rolling(kc_length).min()
|
||||
avg_ = 0.5 * (0.5 * (highest_high + lowest_low) + kch.b)
|
||||
|
||||
squeeze = linreg(close - avg_, length=kc_length)
|
||||
|
||||
else:
|
||||
momo = mom(close, length=mom_length)
|
||||
if mamode.lower() == "ema":
|
||||
squeeze = ema(momo, length=mom_smooth)
|
||||
else: # "sma"
|
||||
squeeze = sma(momo, length=mom_smooth)
|
||||
|
||||
# Classify Squeezes
|
||||
squeeze_on = (bbd.l > kch.l) & (bbd.u < kch.u)
|
||||
squeeze_off = (bbd.l < kch.l) & (bbd.u > kch.u)
|
||||
no_squeeze = ~squeeze_on & ~squeeze_off
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
squeeze = squeeze.shift(offset)
|
||||
squeeze_on = squeeze_on.shift(offset)
|
||||
squeeze_off = squeeze_off.shift(offset)
|
||||
no_squeeze = no_squeeze.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
squeeze.fillna(kwargs["fillna"], inplace=True)
|
||||
squeeze_on.fillna(kwargs["fillna"], inplace=True)
|
||||
squeeze_off.fillna(kwargs["fillna"], inplace=True)
|
||||
no_squeeze.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
_props = "" if use_tr else "hlr"
|
||||
_props += f"_{bb_length}_{bb_std}_{kc_length}_{kc_scalar}"
|
||||
_props += "_LB" if lazybear else ""
|
||||
squeeze.name = f"SQZ{_props}"
|
||||
|
||||
if asint:
|
||||
squeeze_on = squeeze_on.astype(int)
|
||||
squeeze_off = squeeze_off.astype(int)
|
||||
no_squeeze = no_squeeze.astype(int)
|
||||
|
||||
if prenan:
|
||||
nanlength = max(bb_length, kc_length) - 2
|
||||
squeeze_on[:nanlength] = nan
|
||||
squeeze_off[:nanlength] = nan
|
||||
no_squeeze[:nanlength] = nan
|
||||
|
||||
data = {
|
||||
squeeze.name: squeeze,
|
||||
f"SQZ_ON": squeeze_on,
|
||||
f"SQZ_OFF": squeeze_off,
|
||||
f"SQZ_NO": no_squeeze
|
||||
}
|
||||
df = DataFrame(data, index=close.index)
|
||||
df.name = squeeze.name
|
||||
df.category = squeeze.category = "momentum"
|
||||
|
||||
# More Detail
|
||||
if detailed:
|
||||
pos_squeeze = squeeze[squeeze >= 0]
|
||||
neg_squeeze = squeeze[squeeze < 0]
|
||||
|
||||
pos_inc, pos_dec = unsigned_differences(pos_squeeze, asint=True)
|
||||
neg_inc, neg_dec = unsigned_differences(neg_squeeze, asint=True)
|
||||
|
||||
pos_inc *= squeeze
|
||||
pos_dec *= squeeze
|
||||
neg_dec *= squeeze
|
||||
neg_inc *= squeeze
|
||||
|
||||
pos_inc.replace(0, nan, inplace=True)
|
||||
pos_dec.replace(0, nan, inplace=True)
|
||||
neg_dec.replace(0, nan, inplace=True)
|
||||
neg_inc.replace(0, nan, inplace=True)
|
||||
|
||||
sqz_inc = squeeze * increasing(squeeze)
|
||||
sqz_dec = squeeze * decreasing(squeeze)
|
||||
sqz_inc.replace(0, nan, inplace=True)
|
||||
sqz_dec.replace(0, nan, inplace=True)
|
||||
|
||||
# Handle fills
|
||||
if "fillna" in kwargs:
|
||||
sqz_inc.fillna(kwargs["fillna"], inplace=True)
|
||||
sqz_dec.fillna(kwargs["fillna"], inplace=True)
|
||||
pos_inc.fillna(kwargs["fillna"], inplace=True)
|
||||
pos_dec.fillna(kwargs["fillna"], inplace=True)
|
||||
neg_dec.fillna(kwargs["fillna"], inplace=True)
|
||||
neg_inc.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
df[f"SQZ_INC"] = sqz_inc
|
||||
df[f"SQZ_DEC"] = sqz_dec
|
||||
df[f"SQZ_PINC"] = pos_inc
|
||||
df[f"SQZ_PDEC"] = pos_dec
|
||||
df[f"SQZ_NDEC"] = neg_dec
|
||||
df[f"SQZ_NINC"] = neg_inc
|
||||
|
||||
return df
|
||||
@@ -1,222 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import nan
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.ma import ma
|
||||
from pandas_ta.momentum import mom
|
||||
from pandas_ta.trend import decreasing, increasing
|
||||
from pandas_ta.utils import (
|
||||
simplify_columns,
|
||||
unsigned_differences,
|
||||
v_bool,
|
||||
v_mamode,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_scalar,
|
||||
v_series
|
||||
)
|
||||
from pandas_ta.volatility import bbands, kc
|
||||
|
||||
|
||||
|
||||
def squeeze_pro(
|
||||
high: Series, low: Series, close: Series,
|
||||
bb_length: Int = None, bb_std: IntFloat = None,
|
||||
kc_length: Int = None, kc_scalar_narrow: IntFloat = None,
|
||||
kc_scalar_normal: IntFloat = None, kc_scalar_wide: IntFloat = None,
|
||||
mom_length: Int = None, mom_smooth: Int = None,
|
||||
use_tr: bool = None, mamode: str = None,
|
||||
prenan: bool = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> DataFrame:
|
||||
"""Squeeze Pro
|
||||
|
||||
This indicator, based on John Carter's "TTM Squeeze" indicator, attempts
|
||||
identify momentum using volatility with additional details.
|
||||
|
||||
Sources:
|
||||
* [usethinkscript](https://usethinkscript.com/threads/john-carters-squeeze-pro-indicator-for-thinkorswim-free.4021/)
|
||||
* [tradingview](https://www.tradingview.com/script/TAAt6eRX-Squeeze-PRO-Indicator-Makit0/)
|
||||
|
||||
Parameters:
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
close (Series): ```close``` Series
|
||||
bb_length (int): BB period. Default: ```20```
|
||||
bb_std (float): BB Std. Dev. Default: ```2```
|
||||
kc_length (int): KC period. Default: ```20```
|
||||
kc_scalar_normal (float): Keltner Channel scalar for normal channel.
|
||||
Default: ```1.5```
|
||||
kc_scalar_narrow (float): Narrow channel KC scalar. Default: ```1```
|
||||
kc_scalar_wide (float): Wide channel KC scalar. Default: ```2```
|
||||
mom_length (int): Momentum Period. Default: ```12```
|
||||
mom_smooth (int): Momentum Smoothing period. Default: ```6```
|
||||
mamode (str): One of: "ema" or "sma". Default: ```"sma"```
|
||||
prenan (bool): Apply prenans. Default: ```False```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
tr (value): Use True Range for Keltner Channels.
|
||||
Default: ```True```
|
||||
asint (bool): Returns as ```Int```. Default: ```True```
|
||||
mamode (value): Which MA to use. Default: ```"sma"```
|
||||
detailed (value): Extra detailed. Default: ```False```
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(DataFrame): 6 columns (_default_) or 12 columns if ```detailed=True```
|
||||
|
||||
Warning:
|
||||
May be depreciated in the future and combined with ```squeeze```.
|
||||
"""
|
||||
# Validate
|
||||
bb_length = v_pos_default(bb_length, 20)
|
||||
kc_length = v_pos_default(kc_length, 20)
|
||||
mom_length = v_pos_default(mom_length, 12)
|
||||
mom_smooth = v_pos_default(mom_smooth, 6)
|
||||
_length = max(bb_length, kc_length, mom_length, mom_smooth) + 1
|
||||
high = v_series(high, _length)
|
||||
low = v_series(low, _length)
|
||||
close = v_series(close, _length)
|
||||
|
||||
if high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
kc_scalar_narrow = v_scalar(kc_scalar_narrow, 1)
|
||||
kc_scalar_normal = v_scalar(kc_scalar_normal, 1.5)
|
||||
kc_scalar_wide = v_scalar(kc_scalar_wide, 2)
|
||||
prenan = v_bool(prenan, False)
|
||||
valid_kc_scaler = kc_scalar_wide > kc_scalar_normal \
|
||||
and kc_scalar_normal > kc_scalar_narrow
|
||||
|
||||
if not valid_kc_scaler:
|
||||
return
|
||||
|
||||
bb_std = v_pos_default(bb_std, 2.0)
|
||||
mamode = v_mamode(mamode, "sma")
|
||||
offset = v_offset(offset)
|
||||
use_tr = kwargs.pop("tr", True)
|
||||
asint = kwargs.pop("asint", True)
|
||||
detailed = kwargs.pop("detailed", False)
|
||||
|
||||
# Calculate
|
||||
bbd = bbands(close, length=bb_length, std=bb_std, mamode=mamode)
|
||||
kch_wide = kc(
|
||||
high, low, close, length=kc_length, scalar=kc_scalar_wide,
|
||||
mamode=mamode, tr=use_tr
|
||||
)
|
||||
kch_normal = kc(
|
||||
high, low, close, length=kc_length, scalar=kc_scalar_normal,
|
||||
mamode=mamode, tr=use_tr
|
||||
)
|
||||
kch_narrow = kc(
|
||||
high, low, close, length=kc_length, scalar=kc_scalar_narrow,
|
||||
mamode=mamode, tr=use_tr
|
||||
)
|
||||
|
||||
# Simplify KC and BBAND column names for dynamic access
|
||||
bbd.columns = simplify_columns(bbd)
|
||||
kch_wide.columns = simplify_columns(kch_wide)
|
||||
kch_normal.columns = simplify_columns(kch_normal)
|
||||
kch_narrow.columns = simplify_columns(kch_narrow)
|
||||
|
||||
momo = mom(close, length=mom_length)
|
||||
squeeze = ma(mamode, momo, length=mom_smooth)
|
||||
|
||||
# Classify Squeezes
|
||||
squeeze_on_wide = (bbd.l > kch_wide.l) & (bbd.u < kch_wide.u)
|
||||
squeeze_on_normal = (bbd.l > kch_normal.l) & (bbd.u < kch_normal.u)
|
||||
squeeze_on_narrow = (bbd.l > kch_narrow.l) & (bbd.u < kch_narrow.u)
|
||||
squeeze_off_wide = (bbd.l < kch_wide.l) & (bbd.u > kch_wide.u)
|
||||
no_squeeze = ~squeeze_on_wide & ~squeeze_off_wide
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
squeeze = squeeze.shift(offset)
|
||||
squeeze_on_wide = squeeze_on_wide.shift(offset)
|
||||
squeeze_on_normal = squeeze_on_normal.shift(offset)
|
||||
squeeze_on_narrow = squeeze_on_narrow.shift(offset)
|
||||
squeeze_off_wide = squeeze_off_wide.shift(offset)
|
||||
no_squeeze = no_squeeze.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
squeeze.fillna(kwargs["fillna"], inplace=True)
|
||||
squeeze_on_wide.fillna(kwargs["fillna"], inplace=True)
|
||||
squeeze_on_normal.fillna(kwargs["fillna"], inplace=True)
|
||||
squeeze_on_narrow.fillna(kwargs["fillna"], inplace=True)
|
||||
squeeze_off_wide.fillna(kwargs["fillna"], inplace=True)
|
||||
no_squeeze.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
_props = "" if use_tr else "hlr"
|
||||
_props += f"_{bb_length}_{bb_std}_{kc_length}_{kc_scalar_wide}_{kc_scalar_normal}_{kc_scalar_narrow}"
|
||||
squeeze.name = f"SQZPRO{_props}"
|
||||
|
||||
if asint:
|
||||
squeeze_on_wide = squeeze_on_wide.astype(int)
|
||||
squeeze_on_narrow = squeeze_on_narrow.astype(int)
|
||||
squeeze_on_normal = squeeze_on_normal.astype(int)
|
||||
squeeze_off_wide = squeeze_off_wide.astype(int)
|
||||
no_squeeze = no_squeeze.astype(int)
|
||||
|
||||
if prenan:
|
||||
nanlength = max(bb_length, kc_length) - 2
|
||||
squeeze_on_wide[:nanlength] = nan
|
||||
squeeze_on_narrow[:nanlength] = nan
|
||||
squeeze_on_normal[:nanlength] = nan
|
||||
squeeze_off_wide[:nanlength] = nan
|
||||
no_squeeze[:nanlength] = nan
|
||||
|
||||
data = {
|
||||
squeeze.name: squeeze,
|
||||
f"SQZPRO_ON_WIDE": squeeze_on_wide,
|
||||
f"SQZPRO_ON_NORMAL": squeeze_on_normal,
|
||||
f"SQZPRO_ON_NARROW": squeeze_on_narrow,
|
||||
f"SQZPRO_OFF": squeeze_off_wide,
|
||||
f"SQZPRO_NO": no_squeeze
|
||||
}
|
||||
df = DataFrame(data, index=close.index)
|
||||
df.name = squeeze.name
|
||||
df.category = squeeze.category = "momentum"
|
||||
|
||||
# More Detail
|
||||
if detailed:
|
||||
pos_squeeze = squeeze[squeeze >= 0]
|
||||
neg_squeeze = squeeze[squeeze < 0]
|
||||
|
||||
pos_inc, pos_dec = unsigned_differences(pos_squeeze, asint=True)
|
||||
neg_inc, neg_dec = unsigned_differences(neg_squeeze, asint=True)
|
||||
|
||||
pos_inc *= squeeze
|
||||
pos_dec *= squeeze
|
||||
neg_dec *= squeeze
|
||||
neg_inc *= squeeze
|
||||
|
||||
pos_inc.replace(0, nan, inplace=True)
|
||||
pos_dec.replace(0, nan, inplace=True)
|
||||
neg_dec.replace(0, nan, inplace=True)
|
||||
neg_inc.replace(0, nan, inplace=True)
|
||||
|
||||
sqz_inc = squeeze * increasing(squeeze)
|
||||
sqz_dec = squeeze * decreasing(squeeze)
|
||||
sqz_inc.replace(0, nan, inplace=True)
|
||||
sqz_dec.replace(0, nan, inplace=True)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
sqz_inc.fillna(kwargs["fillna"], inplace=True)
|
||||
sqz_dec.fillna(kwargs["fillna"], inplace=True)
|
||||
pos_inc.fillna(kwargs["fillna"], inplace=True)
|
||||
pos_dec.fillna(kwargs["fillna"], inplace=True)
|
||||
neg_dec.fillna(kwargs["fillna"], inplace=True)
|
||||
neg_inc.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
df[f"SQZPRO_INC"] = sqz_inc
|
||||
df[f"SQZPRO_DEC"] = sqz_dec
|
||||
df[f"SQZPRO_PINC"] = pos_inc
|
||||
df[f"SQZPRO_PDEC"] = pos_dec
|
||||
df[f"SQZPRO_NDEC"] = neg_dec
|
||||
df[f"SQZPRO_NINC"] = neg_inc
|
||||
|
||||
return df
|
||||
@@ -1,175 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import nan
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.overlap import ema
|
||||
from pandas_ta.utils import (
|
||||
non_zero_range,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_series
|
||||
)
|
||||
|
||||
|
||||
|
||||
def schaff_tc(close: Series, seed: Series, tc_length: int, factor: IntFloat):
|
||||
lowest_xmacd = seed.rolling(tc_length).min()
|
||||
xmacd_range = non_zero_range(seed.rolling(tc_length).max(), lowest_xmacd)
|
||||
m = len(seed)
|
||||
|
||||
# Initialize lists
|
||||
stoch1, pf = [0] * m, [0] * m
|
||||
stoch2, pff = [0] * m, [0] * m
|
||||
|
||||
for i in range(1, m):
|
||||
# %Fast K of MACD
|
||||
if lowest_xmacd.iloc[i] > 0:
|
||||
stoch1[i] = 100 * ((seed.iloc[i] - lowest_xmacd.iloc[i]) / xmacd_range.iloc[i])
|
||||
else:
|
||||
stoch1[i] = stoch1[i - 1]
|
||||
# Smoothed Calculation for % Fast D of MACD
|
||||
pf[i] = round(pf[i - 1] + (factor * (stoch1[i] - pf[i - 1])), 8)
|
||||
|
||||
# find min and max so far
|
||||
if i < tc_length:
|
||||
# If there are not enough elements for a full tclength window,
|
||||
# use what is available
|
||||
lowest_pf = min(pf[:i+1])
|
||||
highest_pf = max(pf[:i+1])
|
||||
else:
|
||||
lowest_pf = min(pf[i - tc_length + 1:i + 1])
|
||||
highest_pf = max(pf[i - tc_length + 1:i + 1])
|
||||
|
||||
# Ensure non-zero range
|
||||
pf_range = highest_pf - lowest_pf if highest_pf - lowest_pf > 0 else 1
|
||||
|
||||
# % of Fast K of PF
|
||||
if pf_range > 0:
|
||||
stoch2[i] = 100 * ((pf[i] - lowest_pf) / pf_range)
|
||||
else:
|
||||
stoch2[i] = stoch2[i - 1]
|
||||
pff[i] = round(pff[i - 1] + (factor * (stoch2[i] - pff[i - 1])), 8)
|
||||
|
||||
pf_series = Series(pf, index=close.index)
|
||||
pff_series = Series(pff, index=close.index)
|
||||
|
||||
return pff_series, pf_series
|
||||
|
||||
|
||||
def stc(
|
||||
close: Series, tc_length: Int = None,
|
||||
fast: Int = None, slow: Int = None, factor: IntFloat = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> DataFrame:
|
||||
"""Schaff Trend Cycle
|
||||
|
||||
This indicator is an evolved MACD with additional smoothing.
|
||||
|
||||
Sources:
|
||||
* [rengel8](https://github.com/rengel8)
|
||||
* [prorealcode](https://www.prorealcode.com/prorealtime-indicators/schaff-trend-cycle2/)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
tc_length (int): TC period. (Adjust to the half of cycle)
|
||||
Default: ```10```
|
||||
fast (int): Fast MA period. Default: ```12```
|
||||
slow (int): Slow MA period. Default: ```26```
|
||||
factor (float): Smoothing factor for last stoch. calculation.
|
||||
Default: ```0.5```
|
||||
offset (int): How many bars to shift the results. Default: ```0``
|
||||
|
||||
Other Parameters:
|
||||
ma1 (Series): User chosen MA. Default: ```False```
|
||||
ma2 (Series): User chosen MA. Default: ```False```
|
||||
osc (Series): User chosen oscillator. Default: ```False```
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(DataFrame): 3 columns
|
||||
|
||||
Note:
|
||||
Can also seed STC with two MAs, ```ma1``` and ```ma2```, or an oscillator ```osc```.
|
||||
|
||||
* ```ma1``` and ```ma2``` are **both** required if this option is used.
|
||||
"""
|
||||
# Validate
|
||||
fast = v_pos_default(fast, 12)
|
||||
slow = v_pos_default(slow, 26)
|
||||
tc_length = v_pos_default(tc_length, 10)
|
||||
if slow < fast:
|
||||
fast, slow = slow, fast
|
||||
_length = max(tc_length, fast, slow)
|
||||
close = v_series(close, _length)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
factor = v_pos_default(factor, 0.5)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
# kwargs allows for three more series (ma1, ma2 and osc) which can be passed
|
||||
# here ma1 and ma2 input negate internal ema calculations, osc substitutes
|
||||
# both ma's.
|
||||
ma1 = kwargs.pop("ma1", False)
|
||||
ma2 = kwargs.pop("ma2", False)
|
||||
osc = kwargs.pop("osc", False)
|
||||
|
||||
if isinstance(ma1, Series) and isinstance(ma2, Series) and not osc:
|
||||
ma1 = v_series(ma1, _length)
|
||||
ma2 = v_series(ma2, _length)
|
||||
|
||||
if ma1 is None or ma2 is None:
|
||||
return
|
||||
seed = ma1 - ma2
|
||||
|
||||
elif isinstance(osc, Series):
|
||||
osc = v_series(osc, _length)
|
||||
if osc is None:
|
||||
return
|
||||
seed = osc
|
||||
|
||||
else:
|
||||
fastma = ema(close, length=fast)
|
||||
slowma = ema(close, length=slow)
|
||||
seed = fastma - slowma
|
||||
|
||||
pff, pf = schaff_tc(close, seed, tc_length, factor)
|
||||
pf[:_length - 1] = nan
|
||||
|
||||
stc = Series(pff, index=close.index)
|
||||
macd = Series(seed, index=close.index)
|
||||
stoch = Series(pf, index=close.index)
|
||||
|
||||
stc.iloc[:_length - 1] = nan
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
stc = stc.shift(offset)
|
||||
macd = macd.shift(offset)
|
||||
stoch = stoch.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
stc.fillna(kwargs["fillna"], inplace=True)
|
||||
macd.fillna(kwargs["fillna"], inplace=True)
|
||||
stoch.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
_props = f"_{tc_length}_{fast}_{slow}_{factor}"
|
||||
stc.name = f"STC{_props}"
|
||||
macd.name = f"STCmacd{_props}"
|
||||
stoch.name = f"STCstoch{_props}"
|
||||
stc.category = macd.category = stoch.category = "momentum"
|
||||
|
||||
data = {
|
||||
stc.name: stc,
|
||||
macd.name: macd,
|
||||
stoch.name: stoch
|
||||
}
|
||||
df = DataFrame(data, index=close.index)
|
||||
df.name = f"STC{_props}"
|
||||
df.category = stc.category
|
||||
|
||||
return df
|
||||
@@ -1,121 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.ma import ma
|
||||
from pandas_ta.maps import Imports
|
||||
from pandas_ta.utils import (
|
||||
non_zero_range,
|
||||
tal_ma,
|
||||
v_mamode,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_series,
|
||||
v_talib
|
||||
)
|
||||
|
||||
|
||||
|
||||
def stoch(
|
||||
high: Series, low: Series, close: Series,
|
||||
k: Int = None, d: Int = None, smooth_k: Int = None,
|
||||
mamode: str = None, talib: bool = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> DataFrame:
|
||||
"""Stochastic
|
||||
|
||||
This indicator, by George Lane in the 1950's, attempts to identify and
|
||||
quantify momentum; it assumes that momentum precedes value change.
|
||||
|
||||
Sources:
|
||||
* [sierrachart](https://www.sierrachart.com/index.php?page=doc/StudiesReference.php&ID=332&Name=KD_-_Slow)
|
||||
* [tradingview](https://www.tradingview.com/wiki/Stochastic_(STOCH))
|
||||
|
||||
Parameters:
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
close (Series): ```close``` Series
|
||||
k (int): The Fast %K period. Default: ```14```
|
||||
d (int): The Slow %D period. Default: ```3```
|
||||
smooth_k (int): The Slow %K period. Default: ```3```
|
||||
mamode (str): See ```help(ta.ma)```. Default: ```"sma"```
|
||||
talib (bool): If installed, use TA Lib. Default: ```True```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(DataFrame): 3 columns
|
||||
"""
|
||||
# Validate
|
||||
k = v_pos_default(k, 14)
|
||||
d = v_pos_default(d, 3)
|
||||
smooth_k = v_pos_default(smooth_k, 3)
|
||||
_length = k + d + smooth_k
|
||||
high = v_series(high, _length)
|
||||
low = v_series(low, _length)
|
||||
close = v_series(close, _length)
|
||||
|
||||
if high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
mode_tal = v_talib(talib)
|
||||
mamode = v_mamode(mamode, "sma")
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
if Imports["talib"] and mode_tal and smooth_k > 2:
|
||||
from talib import STOCH
|
||||
stoch_ = STOCH(
|
||||
high, low, close, k, d, tal_ma(mamode), d, tal_ma(mamode)
|
||||
)
|
||||
stoch_k, stoch_d = stoch_[0], stoch_[1]
|
||||
else:
|
||||
ll = low.rolling(k).min()
|
||||
hh = high.rolling(k).max()
|
||||
|
||||
stoch = 100 * (close - ll) / non_zero_range(hh, ll)
|
||||
|
||||
if stoch is None: return
|
||||
|
||||
stoch_fvi = stoch.loc[stoch.first_valid_index():, ]
|
||||
if smooth_k == 1:
|
||||
stoch_k = stoch
|
||||
else:
|
||||
stoch_k = ma(mamode, stoch_fvi, length=smooth_k)
|
||||
|
||||
stochk_fvi = stoch_k.loc[stoch_k.first_valid_index():, ]
|
||||
stoch_d = ma(mamode, stochk_fvi, length=d)
|
||||
|
||||
stoch_h = stoch_k - stoch_d # Histogram
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
stoch_k = stoch_k.shift(offset)
|
||||
stoch_d = stoch_d.shift(offset)
|
||||
stoch_h = stoch_h.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
stoch_k.fillna(kwargs["fillna"], inplace=True)
|
||||
stoch_d.fillna(kwargs["fillna"], inplace=True)
|
||||
stoch_h.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
_name = "STOCH"
|
||||
_props = f"_{k}_{d}_{smooth_k}"
|
||||
stoch_k.name = f"{_name}k{_props}"
|
||||
stoch_d.name = f"{_name}d{_props}"
|
||||
stoch_h.name = f"{_name}h{_props}"
|
||||
stoch_k.category = stoch_d.category = stoch_h.category = "momentum"
|
||||
|
||||
data = {
|
||||
stoch_k.name: stoch_k,
|
||||
stoch_d.name: stoch_d,
|
||||
stoch_h.name: stoch_h
|
||||
}
|
||||
df = DataFrame(data, index=close.index)
|
||||
df.name = f"{_name}{_props}"
|
||||
df.category = stoch_k.category
|
||||
|
||||
return df
|
||||
@@ -1,100 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.ma import ma
|
||||
from pandas_ta.maps import Imports
|
||||
from pandas_ta.utils import (
|
||||
non_zero_range,
|
||||
tal_ma,
|
||||
v_mamode,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_series,
|
||||
v_talib
|
||||
)
|
||||
|
||||
|
||||
|
||||
def stochf(
|
||||
high: Series, low: Series, close: Series,
|
||||
k: Int = None, d: Int = None,
|
||||
mamode: str = None, talib: bool = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> DataFrame:
|
||||
"""Fast Stochastic
|
||||
|
||||
This indicator, by George Lane in the 1950's, attempts to identify and
|
||||
quantify momentum like STOCH, but is more volatile.
|
||||
|
||||
Sources:
|
||||
* [corporatefinanceinstitute](https://corporatefinanceinstitute.com/resources/knowledge/trading-investing/fast-stochastic-indicator/)
|
||||
* [sierrachart](https://www.sierrachart.com/index.php?page=doc/StudiesReference.php&ID=333&Name=KD_-_Fast)
|
||||
|
||||
Parameters:
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
close (Series): ```close``` Series
|
||||
k (int): The Fast %K period. Default: ```14```
|
||||
d (int): The Slow %D period. Default: ```3```
|
||||
mamode (str): See ```help(ta.ma)```. Default: ```"sma"```
|
||||
talib (bool): If installed, use TA Lib. Default: ```True```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(DataFrame): 2 columns
|
||||
"""
|
||||
# Validate
|
||||
k = v_pos_default(k, 14)
|
||||
d = v_pos_default(d, 3)
|
||||
_length = k + d - 1
|
||||
high = v_series(high, _length)
|
||||
low = v_series(low, _length)
|
||||
close = v_series(close, _length)
|
||||
|
||||
if high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
mamode = v_mamode(mamode, "sma")
|
||||
mode_tal = v_talib(talib)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
if Imports["talib"] and mode_tal:
|
||||
from talib import STOCHF
|
||||
stochf_ = STOCHF(high, low, close, k, d, tal_ma(mamode))
|
||||
stochf_k, stochf_d = stochf_[0], stochf_[1]
|
||||
else:
|
||||
lowest_low = low.rolling(k).min()
|
||||
highest_high = high.rolling(k).max()
|
||||
|
||||
stochf_k = 100 * (close - lowest_low) \
|
||||
/ non_zero_range(highest_high, lowest_low)
|
||||
stochfk_fvi = stochf_k.loc[stochf_k.first_valid_index():, ]
|
||||
stochf_d = ma(mamode, stochfk_fvi, length=d, talib=mode_tal)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
stochf_k = stochf_k.shift(offset)
|
||||
stochf_d = stochf_d.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
stochf_k.fillna(kwargs["fillna"], inplace=True)
|
||||
stochf_d.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
_name = "STOCHF"
|
||||
_props = f"_{k}_{d}"
|
||||
stochf_k.name = f"{_name}k{_props}"
|
||||
stochf_d.name = f"{_name}d{_props}"
|
||||
stochf_k.category = stochf_d.category = "momentum"
|
||||
|
||||
data = {stochf_k.name: stochf_k, stochf_d.name: stochf_d}
|
||||
df = DataFrame(data, index=close.index)
|
||||
df.name = f"{_name}{_props}"
|
||||
df.category = stochf_k.category
|
||||
|
||||
return df
|
||||
@@ -1,104 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.ma import ma
|
||||
from pandas_ta.maps import Imports
|
||||
from pandas_ta.momentum import rsi
|
||||
from pandas_ta.utils import (
|
||||
non_zero_range,
|
||||
v_mamode,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_series,
|
||||
v_talib
|
||||
)
|
||||
|
||||
|
||||
|
||||
def stochrsi(
|
||||
close: Series, length: Int = None, rsi_length: Int = None,
|
||||
k: Int = None, d: Int = None, mamode: str = None,
|
||||
talib: bool = None, offset: Int = None, **kwargs: DictLike
|
||||
) -> DataFrame:
|
||||
"""Stochastic RSI
|
||||
|
||||
This indicator attempts to quantify RSI relative to its High-Low range.
|
||||
|
||||
Sources:
|
||||
* "Stochastic RSI and Dynamic Momentum Index", Tushar Chande and
|
||||
Stanley Kroll, Stock & Commodities V.11:5 (189-199)
|
||||
* [tradingview](https://www.tradingview.com/wiki/Stochastic_(STOCH))
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```14```
|
||||
rsi_length (int): RSI period. Default: ```14```
|
||||
k (int): The Fast %K period. Default: ```3```
|
||||
d (int): The Slow %K period. Default: ```3```
|
||||
mamode (str): See ```help(ta.ma)```. Default: ```"sma"```
|
||||
talib (bool): If installed, use TA Lib. Default: ```True```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(DataFrame): 2 columns
|
||||
|
||||
Note:
|
||||
May be more sensitive to RSI and thus identify potential "overbought"
|
||||
or "oversold" signals.
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 14)
|
||||
rsi_length = v_pos_default(rsi_length, 14)
|
||||
k = v_pos_default(k, 3)
|
||||
d = v_pos_default(d, 3)
|
||||
_length = length + rsi_length + 2
|
||||
close = v_series(close, _length)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
mamode = v_mamode(mamode, "sma")
|
||||
mode_tal = v_talib(talib)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
# if Imports["talib"] and mode_tal:
|
||||
# from talib import RSI
|
||||
# rsi_ = RSI(close, length)
|
||||
# else:
|
||||
|
||||
rsi_ = rsi(close, length=rsi_length)
|
||||
lowest_rsi = rsi_.rolling(length).min()
|
||||
highest_rsi = rsi_.rolling(length).max()
|
||||
|
||||
stoch = 100 * (rsi_ - lowest_rsi) / non_zero_range(highest_rsi, lowest_rsi)
|
||||
|
||||
stochrsi_k = ma(mamode, stoch, length=k)
|
||||
stochrsi_d = ma(mamode, stochrsi_k, length=d)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
stochrsi_k = stochrsi_k.shift(offset)
|
||||
stochrsi_d = stochrsi_d.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
stochrsi_k.fillna(kwargs["fillna"], inplace=True)
|
||||
stochrsi_d.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
_name = "STOCHRSI"
|
||||
_props = f"_{length}_{rsi_length}_{k}_{d}"
|
||||
stochrsi_k.name = f"{_name}k{_props}"
|
||||
stochrsi_d.name = f"{_name}d{_props}"
|
||||
stochrsi_k.category = stochrsi_d.category = "momentum"
|
||||
|
||||
data = {stochrsi_k.name: stochrsi_k, stochrsi_d.name: stochrsi_d}
|
||||
df = DataFrame(data, index=close.index)
|
||||
df.name = f"{_name}{_props}"
|
||||
df.category = stochrsi_k.category
|
||||
|
||||
return df
|
||||
@@ -1,129 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import isnan, zeros
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.ma import ma
|
||||
from pandas_ta.utils import (
|
||||
sum_signed_rolling_deltas,
|
||||
v_bool,
|
||||
v_mamode,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_series
|
||||
)
|
||||
|
||||
|
||||
def tmo(
|
||||
open_: Series, close: Series, tmo_length: Int = None,
|
||||
calc_length: Int = None, smooth_length: Int = None,
|
||||
momentum: bool = None, normalize: bool = None, exclusive: bool = None,
|
||||
mamode: str = None, offset: Int = None, **kwargs: DictLike,
|
||||
) -> DataFrame:
|
||||
"""True Momentum Oscillator
|
||||
|
||||
This indicator attempts to quantify momentum.
|
||||
|
||||
Sources:
|
||||
* [tradingview A](https://www.tradingview.com/script/VRwDppqd-True-Momentum-Oscillator/)
|
||||
* [tradingview B](https://www.tradingview.com/script/65vpO7T5-True-Momentum-Oscillator-Universal-Edition/)
|
||||
|
||||
Parameters:
|
||||
open_ (Series): ```open``` Series
|
||||
close (Series): ```close``` Series
|
||||
tmo_length (int): TMO period. Default: ```14```
|
||||
calc_length (int): Initial MA period. Default: ```5```
|
||||
smooth_length (int): Main and smooth signal MA period. Default: ```3```
|
||||
mamode (str): See ```help(ta.ma)```. Default: ```"ema"```
|
||||
momentum (bool): Compute main and smooth momentum. Default: ```False```
|
||||
normalize (bool): Normalize. Default: ```False```
|
||||
exclusive (bool): Exclusive period over ```n``` bars, or inclusively
|
||||
over ```n-1``` bars. Default: ```True```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): DataFrame.fillna(value)
|
||||
|
||||
Returns:
|
||||
(DataFrame): 4 columns
|
||||
"""
|
||||
# Validate
|
||||
tmo_length = v_pos_default(tmo_length, 14)
|
||||
calc_length = v_pos_default(calc_length, 5)
|
||||
smooth_length = v_pos_default(smooth_length, 3)
|
||||
_length = max(tmo_length, calc_length, smooth_length)
|
||||
|
||||
open_ = v_series(open_, _length)
|
||||
close = v_series(close, _length)
|
||||
offset = v_offset(offset)
|
||||
|
||||
if "length" in kwargs:
|
||||
kwargs.pop("length")
|
||||
|
||||
if open_ is None or close is None:
|
||||
return None
|
||||
|
||||
mamode = v_mamode(mamode, "ema")
|
||||
compute_momentum = v_bool(momentum, False)
|
||||
normalize_signal = v_bool(normalize, False)
|
||||
exclusive = v_bool(exclusive, True)
|
||||
|
||||
signed_diff_sum = sum_signed_rolling_deltas(
|
||||
open_, close, tmo_length, exclusive=exclusive
|
||||
)
|
||||
if all(isnan(signed_diff_sum)):
|
||||
return None # Emergency Break
|
||||
|
||||
initial_ma = ma(mamode, signed_diff_sum, length=calc_length)
|
||||
if all(isnan(initial_ma)):
|
||||
return None # Emergency Break
|
||||
|
||||
main = ma(mamode, initial_ma, length=smooth_length)
|
||||
if all(isnan(main)):
|
||||
return None # Emergency Break
|
||||
|
||||
smooth = ma(mamode, main, length=smooth_length)
|
||||
if all(isnan(smooth)):
|
||||
return None # Emergency Break
|
||||
|
||||
if compute_momentum:
|
||||
mom_main = main - main.shift(tmo_length)
|
||||
mom_smooth = smooth - smooth.shift(tmo_length)
|
||||
else:
|
||||
zero_array = zeros(main.size)
|
||||
mom_main = Series(zero_array, index=main.index)
|
||||
mom_smooth = Series(zero_array, index=smooth.index)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
main = main.shift(offset)
|
||||
smooth = smooth.shift(offset)
|
||||
mom_main = mom_main.shift(offset)
|
||||
mom_smooth = mom_smooth.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
main.fillna(kwargs["fillna"], inplace=True)
|
||||
smooth.fillna(kwargs["fillna"], inplace=True)
|
||||
mom_main.fillna(kwargs["fillna"], inplace=True)
|
||||
mom_smooth.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
_props = f"_{tmo_length}_{calc_length}_{smooth_length}"
|
||||
main.name = f"TMO{_props}"
|
||||
smooth.name = f"TMOs{_props}"
|
||||
mom_main.name = f"TMOM{_props}"
|
||||
mom_smooth.name = f"TMOMs{_props}"
|
||||
main.category = smooth.category = "momentum"
|
||||
mom_main.category = mom_smooth.category = main.category
|
||||
|
||||
data = {
|
||||
main.name: main,
|
||||
smooth.name: smooth,
|
||||
mom_main.name: mom_main,
|
||||
mom_smooth.name: mom_smooth,
|
||||
}
|
||||
df = DataFrame(data, index=close.index)
|
||||
df.name = f"TMO{_props}"
|
||||
df.category = main.category
|
||||
|
||||
return df
|
||||
@@ -1,93 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import isnan
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.overlap.ema import ema
|
||||
from pandas_ta.utils import (
|
||||
v_drift,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_scalar,
|
||||
v_series
|
||||
)
|
||||
|
||||
|
||||
|
||||
def trix(
|
||||
close: Series, length: Int = None, signal: Int = None,
|
||||
scalar: IntFloat = None, drift: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Trix
|
||||
|
||||
This indicator attempts to identify divergences as an oscillator.
|
||||
|
||||
Sources:
|
||||
* [tradingview](https://www.tradingview.com/wiki/TRIX)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```18```
|
||||
signal (int): Signal period. Default: ```9```
|
||||
scalar (float): Scalar. Default: ```100```
|
||||
drift (int): Difference amount. Default: ```1```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 30)
|
||||
signal = v_pos_default(signal, 9)
|
||||
if length < signal:
|
||||
length, signal = signal, length
|
||||
_length = 3 * length - 1
|
||||
close = v_series(close, _length)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
scalar = v_scalar(scalar, 100)
|
||||
drift = v_drift(drift)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
ema1 = ema(close=close, length=length, **kwargs)
|
||||
if all(isnan(ema1)):
|
||||
return # Emergency Break
|
||||
|
||||
ema2 = ema(close=ema1, length=length, **kwargs)
|
||||
if all(isnan(ema2)):
|
||||
return # Emergency Break
|
||||
|
||||
ema3 = ema(close=ema2, length=length, **kwargs)
|
||||
if all(isnan(ema3)):
|
||||
return # Emergency Break
|
||||
|
||||
trix = scalar * ema3.pct_change(drift)
|
||||
trix_signal = trix.rolling(signal).mean()
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
trix = trix.shift(offset)
|
||||
trix_signal = trix_signal.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
trix.fillna(kwargs["fillna"], inplace=True)
|
||||
trix_signal.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
trix.name = f"TRIX_{length}_{signal}"
|
||||
trix_signal.name = f"TRIXs_{length}_{signal}"
|
||||
trix.category = trix_signal.category = "momentum"
|
||||
|
||||
data = {trix.name: trix, trix_signal.name: trix_signal}
|
||||
df = DataFrame(data, index=close.index)
|
||||
df.name = f"TRIX_{length}_{signal}"
|
||||
df.category = "momentum"
|
||||
|
||||
return df
|
||||
@@ -1,106 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import isnan
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.ma import ma
|
||||
from pandas_ta.overlap import ema
|
||||
from pandas_ta.utils import (
|
||||
v_drift,
|
||||
v_mamode,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_scalar,
|
||||
v_series
|
||||
)
|
||||
|
||||
|
||||
|
||||
def tsi(
|
||||
close: Series, fast: Int = None, slow: Int = None,
|
||||
signal: Int = None, scalar: IntFloat = None,
|
||||
mamode: str = None, drift: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> DataFrame:
|
||||
"""True Strength Index
|
||||
|
||||
This indicator attempts to identify short-term swings in trend direction
|
||||
as well as identifying possible "overbought" and "oversold" signals.
|
||||
|
||||
Sources:
|
||||
* [investopedia](https://www.investopedia.com/terms/t/tsi.asp)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
fast (int): Fast MA period. Default: ```13```
|
||||
slow (int): Slow MA period. Default: ```25```
|
||||
signal (int): Signal period. Default: ```13```
|
||||
scalar (float): Scalar. Default: ```100```
|
||||
mamode (str): Signal MA. See ```help(ta.ma)```. Default: ```"ema"```
|
||||
drift (int): Difference amount. Default: ```1```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(DataFrame): 2 columns
|
||||
"""
|
||||
# Validate
|
||||
fast = v_pos_default(fast, 13)
|
||||
slow = v_pos_default(slow, 25)
|
||||
signal = v_pos_default(signal, 13)
|
||||
if slow < fast:
|
||||
fast, slow = slow, fast
|
||||
_length = slow + signal + 1
|
||||
close = v_series(close, _length)
|
||||
|
||||
if "length" in kwargs:
|
||||
kwargs.pop("length")
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
scalar = v_scalar(scalar, 100)
|
||||
mamode = v_mamode(mamode, "ema")
|
||||
drift = v_drift(drift)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
diff = close.diff(drift)
|
||||
slow_ema = ema(close=diff, length=slow, **kwargs)
|
||||
if all(isnan(slow_ema)):
|
||||
return # Emergency Break
|
||||
fast_slow_ema = ema(close=slow_ema, length=fast, **kwargs)
|
||||
|
||||
abs_diff = diff.abs()
|
||||
abs_slow_ema = ema(close=abs_diff, length=slow, **kwargs)
|
||||
if all(isnan(abs_slow_ema)):
|
||||
return # Emergency Break
|
||||
abs_fast_slow_ema = ema(close=abs_slow_ema, length=fast, **kwargs)
|
||||
|
||||
tsi = scalar * fast_slow_ema / abs_fast_slow_ema
|
||||
if all(isnan(tsi)):
|
||||
return # Emergency Break
|
||||
tsi_signal = ma(mamode, tsi, length=signal)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
tsi = tsi.shift(offset)
|
||||
tsi_signal = tsi_signal.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
tsi.fillna(kwargs["fillna"], inplace=True)
|
||||
tsi_signal.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
tsi.name = f"TSI_{fast}_{slow}_{signal}"
|
||||
tsi_signal.name = f"TSIs_{fast}_{slow}_{signal}"
|
||||
tsi.category = tsi_signal.category = "momentum"
|
||||
|
||||
data = {tsi.name: tsi, tsi_signal.name: tsi_signal}
|
||||
df = DataFrame(data, index=close.index)
|
||||
df.name = f"TSI_{fast}_{slow}_{signal}"
|
||||
df.category = "momentum"
|
||||
|
||||
return df
|
||||
@@ -1,105 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas_ta.maps import Imports
|
||||
from pandas_ta.utils import (
|
||||
v_drift,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_series,
|
||||
v_talib
|
||||
)
|
||||
|
||||
|
||||
|
||||
def uo(
|
||||
high: Series, low: Series, close: Series,
|
||||
fast: Int = None, medium: Int = None, slow: Int = None,
|
||||
fast_w: IntFloat = None, medium_w: IntFloat = None, slow_w: IntFloat = None,
|
||||
talib: bool = None, drift: Int = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Ultimate Oscillator
|
||||
|
||||
This indicator, by Larry Williams, attempts to identify momentum.
|
||||
|
||||
Sources:
|
||||
* [tradingview](https://www.tradingview.com/wiki/Ultimate_Oscillator_(UO))
|
||||
|
||||
Parameters:
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
close (Series): ```close``` Series
|
||||
fast (int): The Fast %K period. Default: ```7```
|
||||
medium (int): The Slow %K period. Default: ```14```
|
||||
slow (int): The Slow %D period. Default: ```28```
|
||||
fast_w (float): The Fast %K period. Default: ```4.0```
|
||||
medium_w (float): The Slow %K period. Default: ```2.0```
|
||||
slow_w (float): The Slow %D period. Default: ```1.0```
|
||||
talib (bool): If installed, use TA Lib. Default: ```True```
|
||||
drift (int): Difference amount. Default: ```1```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
fast = v_pos_default(fast, 7)
|
||||
medium = v_pos_default(medium, 14)
|
||||
slow = v_pos_default(slow, 28)
|
||||
_length = max(fast, medium, slow) + 1
|
||||
high = v_series(high, _length)
|
||||
low = v_series(low, _length)
|
||||
close = v_series(close, _length)
|
||||
|
||||
if high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
fast_w = v_pos_default(fast_w, 4.0)
|
||||
medium_w = v_pos_default(medium_w, 2.0)
|
||||
slow_w = v_pos_default(slow_w, 1.0)
|
||||
mode_tal = v_talib(talib)
|
||||
drift = v_drift(drift)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
if Imports["talib"] and mode_tal:
|
||||
from talib import ULTOSC
|
||||
uo = ULTOSC(high, low, close, fast, medium, slow)
|
||||
else:
|
||||
close_drift = close.shift(drift)
|
||||
tdf = DataFrame({
|
||||
"high": high, "low": low, f"close_{drift}": close_drift
|
||||
})
|
||||
max_h_or_pc = tdf.loc[:, ["high", f"close_{drift}"]].max(axis=1)
|
||||
min_l_or_pc = tdf.loc[:, ["low", f"close_{drift}"]].min(axis=1)
|
||||
del tdf
|
||||
|
||||
bp = close - min_l_or_pc
|
||||
tr = max_h_or_pc - min_l_or_pc
|
||||
|
||||
fast_avg = bp.rolling(fast).sum() / tr.rolling(fast).sum()
|
||||
medium_avg = bp.rolling(medium).sum() / tr.rolling(medium).sum()
|
||||
slow_avg = bp.rolling(slow).sum() / tr.rolling(slow).sum()
|
||||
|
||||
total_weight = fast_w + medium_w + slow_w
|
||||
weights = (fast_w * fast_avg) + (medium_w * medium_avg) \
|
||||
+ (slow_w * slow_avg)
|
||||
uo = 100 * weights / total_weight
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
uo = uo.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
uo.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
uo.name = f"UO_{fast}_{medium}_{slow}"
|
||||
uo.category = "momentum"
|
||||
|
||||
return uo
|
||||
@@ -1,75 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.maps import Imports
|
||||
from pandas_ta.utils import v_offset, v_pos_default, v_series, v_talib
|
||||
|
||||
|
||||
|
||||
def willr(
|
||||
high: Series, low: Series, close: Series,
|
||||
length: Int = None, talib: bool = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""William's Percent R
|
||||
|
||||
This indicator attempts to identify "overbought" and "oversold"
|
||||
conditions similar to the RSI.
|
||||
|
||||
Sources:
|
||||
* [tradingview](https://www.tradingview.com/wiki/Williams_%25R_(%25R))
|
||||
|
||||
Parameters:
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```14```
|
||||
talib (bool): If installed, use TA Lib. Default: ```True```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 14)
|
||||
if "min_periods" in kwargs and kwargs["min_periods"] is not None:
|
||||
min_periods = int(kwargs["min_periods"])
|
||||
else:
|
||||
min_periods = length
|
||||
_length = max(length, min_periods)
|
||||
high = v_series(high, _length)
|
||||
low = v_series(low, _length)
|
||||
close = v_series(close, _length)
|
||||
|
||||
if high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
mode_tal = v_talib(talib)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
if Imports["talib"] and mode_tal:
|
||||
from talib import WILLR
|
||||
willr = WILLR(high, low, close, length)
|
||||
else:
|
||||
lowest_low = low.rolling(length, min_periods=min_periods).min()
|
||||
highest_high = high.rolling(length, min_periods=min_periods).max()
|
||||
|
||||
willr = 100 * ((close - lowest_low) / (highest_high - lowest_low) - 1)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
willr = willr.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
willr.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
willr.name = f"WILLR_{length}"
|
||||
willr.category = "momentum"
|
||||
|
||||
return willr
|
||||
@@ -1,77 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from .alligator import alligator
|
||||
from .alma import alma
|
||||
from .dema import dema
|
||||
from .ema import ema
|
||||
from .fwma import fwma
|
||||
from .hilo import hilo
|
||||
from .hl2 import hl2
|
||||
from .hlc3 import hlc3
|
||||
from .hma import hma
|
||||
from .hwma import hwma
|
||||
from .ichimoku import ichimoku
|
||||
from .jma import jma
|
||||
from .kama import kama
|
||||
from .linreg import linreg
|
||||
from .mama import mama
|
||||
from .mcgd import mcgd
|
||||
from .midpoint import midpoint
|
||||
from .midprice import midprice
|
||||
from .ohlc4 import ohlc4
|
||||
from .pivots import pivots
|
||||
from .pwma import pwma
|
||||
from .rma import rma
|
||||
from .sinwma import sinwma
|
||||
from .sma import sma
|
||||
from .smma import smma
|
||||
from .ssf import ssf
|
||||
from .ssf3 import ssf3
|
||||
from .supertrend import supertrend
|
||||
from .swma import swma
|
||||
from .t3 import t3
|
||||
from .tema import tema
|
||||
from .trima import trima
|
||||
from .vidya import vidya
|
||||
from .wcp import wcp
|
||||
from .wma import wma
|
||||
from .zlma import zlma
|
||||
|
||||
|
||||
__all__ = [
|
||||
"alligator",
|
||||
"alma",
|
||||
"dema",
|
||||
"ema",
|
||||
"fwma",
|
||||
"hilo",
|
||||
"hl2",
|
||||
"hlc3",
|
||||
"hma",
|
||||
"hwma",
|
||||
"ichimoku",
|
||||
"jma",
|
||||
"kama",
|
||||
"linreg",
|
||||
"mama",
|
||||
"mcgd",
|
||||
"midpoint",
|
||||
"midprice",
|
||||
"ohlc4",
|
||||
"pivots",
|
||||
"pwma",
|
||||
"rma",
|
||||
"sinwma",
|
||||
"sma",
|
||||
"smma",
|
||||
"ssf",
|
||||
"ssf3",
|
||||
"supertrend",
|
||||
"swma",
|
||||
"t3",
|
||||
"tema",
|
||||
"trima",
|
||||
"vidya",
|
||||
"wcp",
|
||||
"wma",
|
||||
"zlma",
|
||||
]
|
||||
@@ -1,86 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.utils import v_offset, v_pos_default, v_series, v_talib
|
||||
from .smma import smma
|
||||
|
||||
|
||||
|
||||
def alligator(
|
||||
close: Series, jaw: Int = None, teeth: Int = None, lips: Int = None,
|
||||
talib: bool = None, offset: Int = None, **kwargs: DictLike
|
||||
) -> DataFrame:
|
||||
"""Bill Williams Alligator
|
||||
|
||||
This indicator, by Bill Williams, attempts to identify trends.
|
||||
|
||||
Sources:
|
||||
* [sierrachart](https://www.sierrachart.com/index.php?page=doc/StudiesReference.php&ID=175&Name=Bill_Williams_Alligator)
|
||||
* [tradingview](https://www.tradingview.com/scripts/alligator/)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
jaw (int): Jaw period. Default: ```13```
|
||||
teeth (int): Teeth period. Default: ```8```
|
||||
lips (int): Lips period. Default: ```5```
|
||||
talib (bool): If installed, use TA Lib. Default: ```True```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(DataFrame): 3 columns
|
||||
|
||||
Tip:
|
||||
To avoid data leaks, offsets are to be done manually.
|
||||
|
||||
Note:
|
||||
Williams believed the fx market trends between 15% and 30% of the
|
||||
time. Otherwise it is range bound. Inspired by fractal geometry,
|
||||
where the outputs are meant to resemble an alligator opening and
|
||||
closing its mouth. It It consists of 3 lines: Jaw, Teeth, and
|
||||
Lips which each have differing lengths.
|
||||
"""
|
||||
# Validate
|
||||
jaw = v_pos_default(jaw, 13)
|
||||
teeth = v_pos_default(teeth, 8)
|
||||
lips = v_pos_default(lips, 5)
|
||||
close = v_series(close, max(jaw, teeth, lips))
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
mode_tal = v_talib(talib)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
gator_jaw = smma(close, length=jaw, talib=mode_tal)
|
||||
gator_teeth = smma(close, length=teeth, talib=mode_tal)
|
||||
gator_lips = smma(close, length=lips, talib=mode_tal)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
gator_jaw = gator_jaw.shift(offset)
|
||||
gator_teeth = gator_teeth.shift(offset)
|
||||
gator_lips = gator_lips.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
gator_jaw.fillna(kwargs["fillna"], inplace=True)
|
||||
gator_teeth.fillna(kwargs["fillna"], inplace=True)
|
||||
gator_lips.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
_props = f"_{jaw}_{teeth}_{lips}"
|
||||
data = {
|
||||
f"AGj{_props}": gator_jaw,
|
||||
f"AGt{_props}": gator_teeth,
|
||||
f"AGl{_props}": gator_lips
|
||||
}
|
||||
df = DataFrame(data, index=close.index)
|
||||
|
||||
df.name = f"AG{_props}"
|
||||
df.category = "overlap"
|
||||
|
||||
return df
|
||||
@@ -1,81 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import append, arange, array, exp, floor, nan, tensordot
|
||||
from numpy.version import version as np_version
|
||||
from pandas_ta._typing import DictLike, Int, IntFloat
|
||||
from pandas import Series
|
||||
from pandas_ta.utils import strided_window, v_offset, v_pos_default, v_series
|
||||
|
||||
|
||||
|
||||
def alma(
|
||||
close: Series, length: Int = None,
|
||||
sigma: IntFloat = None, dist_offset: IntFloat = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Arnaud Legoux Moving Average
|
||||
|
||||
This indicator attempts to reduce lag with Gaussian smoothing.
|
||||
|
||||
Sources:
|
||||
* [prorealcode](https://www.prorealcode.com/prorealtime-indicators/alma-arnaud-legoux-moving-average/)
|
||||
* [sierrachart](https://www.sierrachart.com/index.php?page=doc/StudiesReference.php&ID=475&Name=Moving_Average_-_Arnaud_Legoux)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```9```
|
||||
sigma (float): Smoothing value. Default ```6.0```
|
||||
dist_offset (float): Distribution offset, range ```[0, 1]```.
|
||||
Default ```0.85```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 9)
|
||||
close = v_series(close, length)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
sigma = v_pos_default(sigma, 6.0)
|
||||
|
||||
if isinstance(dist_offset, float) and 0 <= dist_offset <= 1:
|
||||
offset_ = float(dist_offset)
|
||||
else:
|
||||
offset_ = 0.85
|
||||
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
np_close = close.to_numpy()
|
||||
x = arange(length)
|
||||
k = floor(offset_ * (length - 1))
|
||||
weights = exp(-0.5 * ((sigma / length) * (x - k)) ** 2)
|
||||
weights /= weights.sum()
|
||||
|
||||
if np_version >= "1.20.0":
|
||||
from numpy.lib.stride_tricks import sliding_window_view
|
||||
window = sliding_window_view(np_close, length)
|
||||
else:
|
||||
window = strided_window(np_close, length)
|
||||
result = append(array([nan] * (length - 1)),
|
||||
tensordot(window, weights, axes=1))
|
||||
alma = Series(result, index=close.index)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
alma = alma.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
alma.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
alma.name = f"ALMA_{length}_{sigma}_{offset_}"
|
||||
alma.category = "overlap"
|
||||
|
||||
return alma
|
||||
@@ -1,75 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import isnan
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.maps import Imports
|
||||
from pandas_ta.utils import v_offset, v_pos_default, v_series, v_talib
|
||||
from .ema import ema
|
||||
|
||||
|
||||
|
||||
def dema(
|
||||
close: Series, length: Int = None, talib: bool = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Double Exponential Moving Average
|
||||
|
||||
This indicator attempts to create a smoother average with less lag than
|
||||
the EMA.
|
||||
|
||||
Sources:
|
||||
* [tradingtechnologies](https://www.tradingtechnologies.com/help/x-study/technical-indicator-definitions/double-exponential-moving-average-dema/)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```10```
|
||||
talib (bool): If installed, use TA Lib. Default: ```True```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
|
||||
Warning:
|
||||
TA-Lib Correlation: ```np.float64(0.9999894518202522)```
|
||||
|
||||
Tip:
|
||||
Corrective contributions welcome!
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 10)
|
||||
close = v_series(close, length)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
mode_tal = v_talib(talib)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
if Imports["talib"] and mode_tal:
|
||||
from talib import DEMA
|
||||
dema = DEMA(close, length)
|
||||
else:
|
||||
ema1 = ema(close=close, length=length, talib=mode_tal)
|
||||
ema2 = ema(close=ema1, length=length, talib=mode_tal)
|
||||
dema = 2 * ema1 - ema2
|
||||
|
||||
if all(isnan(dema.to_numpy())):
|
||||
return # Emergency Break
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
dema = dema.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
dema.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
dema.name = f"DEMA_{length}"
|
||||
dema.category = "overlap"
|
||||
|
||||
return dema
|
||||
@@ -1,80 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import nan
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.maps import Imports
|
||||
from pandas_ta.utils import (
|
||||
v_bool,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_series,
|
||||
v_talib
|
||||
)
|
||||
|
||||
|
||||
|
||||
def ema(
|
||||
close: Series, length: Int = None,
|
||||
talib: bool = None, presma: bool = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Exponential Moving Average
|
||||
|
||||
This Moving Average is more responsive than the Simple Moving
|
||||
Average (SMA).
|
||||
|
||||
Sources:
|
||||
* [investopedia](https://www.investopedia.com/ask/answers/122314/what-exponential-moving-average-ema-formula-and-how-ema-calculated.asp)
|
||||
* [stockcharts](https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:moving_averages)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```10```
|
||||
talib (bool): If installed, use TA Lib. Default: ```True```
|
||||
presma (bool): Initialize with SMA like TA Lib. Default: ```True```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
adjust (bool): Default: ```False```
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 10)
|
||||
close = v_series(close, length)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
mode_tal = v_talib(talib)
|
||||
presma = v_bool(presma, True)
|
||||
offset = v_offset(offset)
|
||||
adjust = kwargs.setdefault("adjust", False)
|
||||
|
||||
# Calculate
|
||||
if Imports["talib"] and mode_tal and length > 1:
|
||||
from talib import EMA
|
||||
ema = EMA(close, length)
|
||||
else:
|
||||
if presma: # TA Lib implementation
|
||||
close = close.copy()
|
||||
sma_nth = close.iloc[0:length].mean()
|
||||
close.iloc[:length - 1] = nan
|
||||
close.iloc[length - 1] = sma_nth
|
||||
ema = close.ewm(span=length, adjust=adjust).mean()
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
ema = ema.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
ema.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
ema.name = f"EMA_{length}"
|
||||
ema.category = "overlap"
|
||||
|
||||
return ema
|
||||
@@ -1,66 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.utils import (
|
||||
fibonacci,
|
||||
v_ascending,
|
||||
v_offset,
|
||||
v_pos_default,
|
||||
v_series,
|
||||
weights
|
||||
)
|
||||
|
||||
|
||||
|
||||
def fwma(
|
||||
close: Series, length: Int = None, asc: bool = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Fibonacci's Weighted Moving Average
|
||||
|
||||
This indicator, by Kevin Johnson, is similar to a Weighted Moving Average
|
||||
(WMA) where the weights are based on the Fibonacci Sequence.
|
||||
|
||||
Sources:
|
||||
* Kevin Johnson
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```10```
|
||||
asc (bool): Recent values weigh more. Default: ```True```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 10)
|
||||
close = v_series(close, length)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
asc = v_ascending(asc)
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
fibs = fibonacci(n=length, weighted=True)
|
||||
fwma = close.rolling(length, min_periods=length) \
|
||||
.apply(weights(fibs), raw=True)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
fwma = fwma.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
fwma.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
fwma.name = f"FWMA_{length}"
|
||||
fwma.category = "overlap"
|
||||
|
||||
return fwma
|
||||
@@ -1,100 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from numpy import nan
|
||||
from pandas import DataFrame, Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.ma import ma
|
||||
from pandas_ta.utils import v_mamode, v_offset, v_pos_default, v_series
|
||||
|
||||
|
||||
|
||||
def hilo(
|
||||
high: Series, low: Series, close: Series,
|
||||
high_length: Int = None, low_length: Int = None, mamode: str = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> DataFrame:
|
||||
"""Gann HiLo Activator
|
||||
|
||||
This indicator, by Robert Krausz, uses two different Moving Averages to
|
||||
identify trends.
|
||||
|
||||
Sources:
|
||||
* Gann HiLo Activator, , Stocks & Commodities Magazine, 1998
|
||||
* [sierrachart](https://www.sierrachart.com/index.php?page=doc/StudiesReference.php&ID=447&Name=Gann_HiLo_Activator)
|
||||
* [tradingview](https://www.tradingview.com/script/XNQSLIYb-Gann-High-Low/)
|
||||
|
||||
Parameters:
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
close (Series): ```close``` Series
|
||||
high_length (int): High period. Default: ```13```
|
||||
low_length (int): Low period. Default: ```21```
|
||||
mamode (str): See ```help(ta.ma)```. Default: ```"sma"```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(DataFrame): 3 columns
|
||||
|
||||
Note:
|
||||
Increasing ```high_length``` and decreasing ```low_length``` is
|
||||
better for short trades and vice versa for long trades.
|
||||
"""
|
||||
# Validate
|
||||
high_length = v_pos_default(high_length, 13)
|
||||
low_length = v_pos_default(low_length, 21)
|
||||
_length = max(high_length, low_length) + 1
|
||||
high = v_series(high, _length)
|
||||
low = v_series(low, _length)
|
||||
close = v_series(close, _length)
|
||||
|
||||
if high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
mamode = v_mamode(mamode, "sma")
|
||||
offset = v_offset(offset)
|
||||
|
||||
# Calculate
|
||||
m = close.size
|
||||
hilo = Series(nan, index=close.index)
|
||||
long = Series(nan, index=close.index)
|
||||
short = Series(nan, index=close.index)
|
||||
|
||||
high_ma = ma(mamode, high, length=high_length)
|
||||
low_ma = ma(mamode, low, length=low_length)
|
||||
|
||||
for i in range(1, m):
|
||||
if close.iat[i] > high_ma.iat[i - 1]:
|
||||
hilo.iat[i] = long.iat[i] = low_ma.iat[i]
|
||||
elif close.iat[i] < low_ma.iat[i - 1]:
|
||||
hilo.iat[i] = short.iat[i] = high_ma.iat[i]
|
||||
else:
|
||||
hilo.iat[i] = hilo.iat[i - 1]
|
||||
long.iat[i] = short.iat[i] = hilo.iat[i - 1]
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
hilo = hilo.shift(offset)
|
||||
long = long.shift(offset)
|
||||
short = short.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
hilo.fillna(kwargs["fillna"], inplace=True)
|
||||
long.fillna(kwargs["fillna"], inplace=True)
|
||||
short.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
_props = f"_{high_length}_{low_length}"
|
||||
data = {
|
||||
f"HILO{_props}": hilo,
|
||||
f"HILOl{_props}": long,
|
||||
f"HILOs{_props}": short
|
||||
}
|
||||
df = DataFrame(data, index=close.index)
|
||||
|
||||
df.name = f"HILO{_props}"
|
||||
df.category = "overlap"
|
||||
|
||||
return df
|
||||
@@ -1,52 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.utils import v_offset, v_series
|
||||
|
||||
|
||||
|
||||
def hl2(
|
||||
high: Series, low: Series,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""HL2
|
||||
|
||||
HL2 is the midpoint/average of high and low.
|
||||
|
||||
Parameters:
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```.
|
||||
Only works when offset.
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
high = v_series(high)
|
||||
low = v_series(low)
|
||||
offset = v_offset(offset)
|
||||
|
||||
if high is None or low is None:
|
||||
return
|
||||
|
||||
# Calculate
|
||||
avg = 0.5 * (high.to_numpy() + low.to_numpy())
|
||||
hl2 = Series(avg, index=high.index)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
hl2 = hl2.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
hl2.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
hl2.name = "HL2"
|
||||
hl2.category = "overlap"
|
||||
|
||||
return hl2
|
||||
@@ -1,60 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.maps import Imports
|
||||
from pandas_ta.utils import v_offset, v_series, v_talib
|
||||
|
||||
|
||||
|
||||
def hlc3(
|
||||
high: Series, low: Series, close: Series, talib: bool = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""HLC3
|
||||
|
||||
HLC3 is the average of high, low and close.
|
||||
|
||||
Parameters:
|
||||
high (Series): ```high``` Series
|
||||
low (Series): ```low``` Series
|
||||
close (Series): ```close``` Series
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```.
|
||||
Only works when offset.
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
high = v_series(high)
|
||||
low = v_series(low)
|
||||
close = v_series(close)
|
||||
mode_tal = v_talib(talib)
|
||||
offset = v_offset(offset)
|
||||
|
||||
if high is None or low is None or close is None:
|
||||
return
|
||||
|
||||
# Calculate
|
||||
if Imports["talib"] and mode_tal and close.size:
|
||||
from talib import TYPPRICE
|
||||
hlc3 = TYPPRICE(high, low, close)
|
||||
else:
|
||||
avg = (high.to_numpy() + low.to_numpy() + close.to_numpy()) / 3.0
|
||||
hlc3 = Series(avg, index=close.index)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
hlc3 = hlc3.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
hlc3.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
hlc3.name = "HLC3"
|
||||
hlc3.category = "overlap"
|
||||
|
||||
return hlc3
|
||||
@@ -1,72 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from sys import modules as module_
|
||||
from numpy import sqrt
|
||||
from pandas import Series
|
||||
from pandas_ta._typing import DictLike, Int
|
||||
from pandas_ta.utils import v_mamode, v_offset, v_pos_default, v_series
|
||||
from .ema import ema
|
||||
from .sma import sma
|
||||
from .wma import wma
|
||||
|
||||
|
||||
|
||||
def hma(
|
||||
close: Series, length: Int = None, mamode: str = None,
|
||||
offset: Int = None, **kwargs: DictLike
|
||||
) -> Series:
|
||||
"""Hull Moving Average
|
||||
|
||||
This indicator, by Alan Hull, attempts to reduce lag compared to
|
||||
classical moving averages.
|
||||
|
||||
Sources:
|
||||
* [Alan Hull](https://alanhull.com/hull-moving-average)
|
||||
|
||||
Parameters:
|
||||
close (Series): ```close``` Series
|
||||
length (int): The period. Default: ```10```
|
||||
mamode (str): One of: 'ema', 'sma', or 'wma'. Default: ```"wma"```
|
||||
offset (int): Post shift. Default: ```0```
|
||||
|
||||
Other Parameters:
|
||||
fillna (value): ```pd.DataFrame.fillna(value)```
|
||||
|
||||
Returns:
|
||||
(Series): 1 column
|
||||
"""
|
||||
# Validate
|
||||
length = v_pos_default(length, 10)
|
||||
close = v_series(close, length + 2)
|
||||
|
||||
if close is None:
|
||||
return
|
||||
|
||||
mamode = v_mamode(mamode, "wma")
|
||||
offset = v_offset(offset)
|
||||
|
||||
if mamode not in ["ema", "sma", "wma"]:
|
||||
return
|
||||
|
||||
_ma = getattr(module_[__name__], mamode)
|
||||
|
||||
# Calculate
|
||||
half_length = int(length / 2)
|
||||
sqrt_length = int(sqrt(length))
|
||||
|
||||
maf = _ma(close, length=half_length)
|
||||
mas = _ma(close, length=length)
|
||||
hma = _ma(close=2 * maf - mas, length=sqrt_length)
|
||||
|
||||
# Offset
|
||||
if offset != 0:
|
||||
hma = hma.shift(offset)
|
||||
|
||||
# Fill
|
||||
if "fillna" in kwargs:
|
||||
hma.fillna(kwargs["fillna"], inplace=True)
|
||||
|
||||
# Name and Category
|
||||
hma.name = f"HMA{"" if mamode == "wma" else mamode[0]}_{length}"
|
||||
hma.category = "overlap"
|
||||
|
||||
return hma
|
||||