├── .github ├── dependabot.yml └── workflows │ ├── release.yml │ └── unit_testing.yml ├── .gitignore ├── LICENSE ├── MANIFEST.in ├── README.md ├── VERSION ├── deploy_pypi.sh ├── docs ├── getting-started.md ├── images │ └── sma20-comparison.svg ├── index.md ├── indicator-catalogue.md ├── indicator-chaining.md ├── indicator-operations.md ├── input-types.md ├── output-types.md ├── overrides │ └── main.html ├── serialization.md └── timeframe-sampling.md ├── examples ├── binance_online.py ├── draw_graph.py ├── indicators.py ├── performance.py ├── performance_talib.py ├── readme_example.py └── serialization.py ├── images ├── SMA_20.svg ├── StochRSI_14_3_3.svg └── TEMA_20.svg ├── mkdocs.yml ├── requirements-mkdocs.txt ├── requirements.txt ├── scripts └── gen_ref_pages.py ├── setup.py ├── talipp ├── __init__.py ├── exceptions.py ├── indicator_util.py ├── indicators │ ├── ADX.py │ ├── ALMA.py │ ├── AO.py │ ├── ATR.py │ ├── AccuDist.py │ ├── Aroon.py │ ├── BB.py │ ├── BOP.py │ ├── CCI.py │ ├── CHOP.py │ ├── ChaikinOsc.py │ ├── ChandeKrollStop.py │ ├── CoppockCurve.py │ ├── DEMA.py │ ├── DPO.py │ ├── DonchianChannels.py │ ├── EMA.py │ ├── EMV.py │ ├── FibonacciRetracement.py │ ├── ForceIndex.py │ ├── HMA.py │ ├── IBS.py │ ├── Ichimoku.py │ ├── Indicator.py │ ├── KAMA.py │ ├── KST.py │ ├── KVO.py │ ├── KeltnerChannels.py │ ├── MACD.py │ ├── MassIndex.py │ ├── McGinleyDynamic.py │ ├── MeanDev.py │ ├── NATR.py │ ├── OBV.py │ ├── ParabolicSAR.py │ ├── PivotsHL.py │ ├── ROC.py │ ├── RSI.py │ ├── RogersSatchell.py │ ├── SFX.py │ ├── SMA.py │ ├── SMMA.py │ ├── SOBV.py │ ├── STC.py │ ├── StdDev.py │ ├── Stoch.py │ ├── StochRSI.py │ ├── SuperTrend.py │ ├── T3.py │ ├── TEMA.py │ ├── TRIX.py │ ├── TSI.py │ ├── TTM.py │ ├── UO.py │ ├── VTX.py │ ├── VWAP.py │ ├── VWMA.py │ ├── WMA.py │ ├── ZLEMA.py │ ├── ZigZag.py │ └── __init__.py ├── input.py ├── ma.py └── ohlcv.py └── test ├── TalippTest.py ├── test_ADX.py ├── test_ALMA.py ├── test_AO.py ├── test_ATR.py ├── test_AccuDist.py ├── test_Aroon.py ├── test_BB.py ├── test_BOP.py ├── test_CCI.py ├── test_CHOP.py ├── test_ChaikinOsc.py ├── test_ChandeKrollStop.py ├── test_CoppockCurve.py ├── test_DEMA.py ├── test_DPO.py ├── test_DonchianChannels.py ├── test_EMA.py ├── test_EMV.py ├── test_ForceIndex.py ├── test_HMA.py ├── test_IBS.py ├── test_KAMA.py ├── test_KST.py ├── test_KVO.py ├── test_KeltnerChannels.py ├── test_MACD.py ├── test_MassIndex.py ├── test_McGinleyDynamic.py ├── test_MeanDev.py ├── test_NATR.py ├── test_OBV.py ├── test_OHLCV.py ├── test_ParabolicSAR.py ├── test_ROC.py ├── test_RSI.py ├── test_RogersSatchel.py ├── test_SFX.py ├── test_SMA.py ├── test_SMMA.py ├── test_SOBV.py ├── test_STC.py ├── test_StdDev.py ├── test_Stoch.py ├── test_StochRSI.py ├── test_SuperTrend.py ├── test_T3.py ├── test_TEMA.py ├── test_TRIX.py ├── test_TSI.py ├── test_TTM.py ├── test_UO.py ├── test_VTX.py ├── test_VWAP.py ├── test_VWMA.py ├── test_WMA.py ├── test_ZLEMA.py ├── test_ZigZag.py ├── test_indicator_chaining.py ├── test_indicator_sampling.py ├── test_indicator_util.py └── test_input.py /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "pip" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | paths: 7 | - VERSION 8 | 9 | jobs: 10 | create-github-release: 11 | runs-on: "ubuntu-latest" 12 | 13 | steps: 14 | - uses: actions/checkout@v4 15 | - name: Create release 16 | env: 17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 18 | run: | 19 | VERSION=$(cat VERSION) 20 | gh release create "$VERSION" \ 21 | --generate-notes 22 | 23 | release-doc: 24 | needs: create-github-release 25 | 26 | runs-on: "ubuntu-latest" 27 | 28 | steps: 29 | - uses: actions/checkout@v4 30 | with: 31 | fetch-depth: 0 32 | - name: Configure Git Credentials 33 | run: | 34 | git config user.name github-actions[bot] 35 | git config user.email 41898282+github-actions[bot]@users.noreply.github.com 36 | - name: Set up Python 37 | uses: actions/setup-python@v2 38 | with: 39 | python-version: '3.8' 40 | - name: Install dependencies 41 | run: | 42 | python -m pip install --upgrade pip 43 | pip install -r requirements-mkdocs.txt 44 | pip install setuptools wheel twine 45 | - name: Build and publish 46 | run: | 47 | VERSION=$(cat VERSION) 48 | mike deploy --push --update-aliases "$VERSION" latest 49 | 50 | release-pypi: 51 | needs: release-doc 52 | 53 | runs-on: "ubuntu-latest" 54 | 55 | steps: 56 | - uses: actions/checkout@v4 57 | - name: Set up Python 58 | uses: actions/setup-python@v2 59 | with: 60 | python-version: '3.8' 61 | - name: Install dependencies 62 | run: | 63 | python -m pip install --upgrade pip 64 | pip install setuptools wheel twine 65 | - name: Build and publish 66 | env: 67 | TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} 68 | TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} 69 | run: | 70 | python setup.py sdist bdist_wheel 71 | twine upload dist/* 72 | -------------------------------------------------------------------------------- /.github/workflows/unit_testing.yml: -------------------------------------------------------------------------------- 1 | name: unit tests 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | build: 11 | strategy: 12 | matrix: 13 | os: ["ubuntu-latest", "windows-latest", "macos-latest"] 14 | python-version: ['3.8', '3.9', '3.10', '3.11', 'pypy-3.8'] 15 | 16 | runs-on: "${{ matrix.os }}" 17 | 18 | steps: 19 | - uses: actions/checkout@v4 20 | - name: Set up Python ${{ matrix.python-version }} 21 | uses: actions/setup-python@v2 22 | with: 23 | python-version: ${{ matrix.python-version }} 24 | - name: Install dependencies 25 | run: | 26 | python -m pip install --upgrade pip 27 | pip install flake8 pytest 28 | pip install -r requirements.txt 29 | pip install -e . 30 | - name: Install dependencies for backward compatibility 31 | run: pip install dataclasses 32 | if: ${{ matrix.python-version == 'pypy3' }} 33 | - name: Lint with flake8 34 | run: | 35 | # stop the build if there are Python syntax errors or undefined names 36 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 37 | - name: Run pytest 38 | run: | 39 | pytest 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Keys 2 | *.pem 3 | 4 | # Byte-compiled / optimized / DLL files 5 | __pycache__/ 6 | *.py[cod] 7 | *$py.class 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .idea/ 14 | .Python 15 | build/ 16 | develop-eggs/ 17 | dist/ 18 | downloads/ 19 | eggs/ 20 | .eggs/ 21 | lib/ 22 | lib64/ 23 | parts/ 24 | sdist/ 25 | var/ 26 | wheels/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | MANIFEST 31 | 32 | # PyInstaller 33 | # Usually these files are written by a python script from a template 34 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 35 | *.manifest 36 | *.spec 37 | 38 | # Installer logs 39 | pip-log.txt 40 | pip-delete-this-directory.txt 41 | 42 | # Unit test / coverage reports 43 | htmlcov/ 44 | .tox/ 45 | .coverage 46 | .coverage.* 47 | .cache 48 | nosetests.xml 49 | coverage.xml 50 | *.cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | .noseids 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | local_settings.py 62 | db.sqlite3 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # pyenv 81 | .python-version 82 | 83 | # celery beat schedule file 84 | celerybeat-schedule 85 | 86 | # SageMath parsed files 87 | *.sage.py 88 | 89 | # Environments 90 | .env 91 | .venv 92 | env/ 93 | venv/ 94 | ENV/ 95 | env.bak/ 96 | venv.bak/ 97 | 98 | # Spyder project settings 99 | .spyderproject 100 | .spyproject 101 | 102 | # Rope project settings 103 | .ropeproject 104 | 105 | # mkdocs documentation 106 | /site 107 | 108 | # mypy 109 | .mypy_cache/ 110 | 111 | # IDE/Editor 112 | .vscode/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 nardew 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include requirements.txt 2 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 2.5.0 2 | -------------------------------------------------------------------------------- /deploy_pypi.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rm -rf dist/* 4 | python3 setup.py sdist bdist_wheel 5 | twine upload dist/* -------------------------------------------------------------------------------- /docs/getting-started.md: -------------------------------------------------------------------------------- 1 | # Getting started 2 | 3 | ## Installation 4 | 5 | talipp can be installed from the following sources: 6 | 7 | ##### :simple-pypi:  PyPI 8 | 9 | ```bash 10 | pip install talipp 11 | ``` 12 | ##### :simple-github:  GitHub 13 | 14 | ```bash 15 | pip install git+https://github.com/nardew/talipp.git@main 16 | ``` 17 | 18 | ##### :simple-condaforge:  Conda 19 | 20 | ```bash 21 | conda install conda-forge::talipp 22 | ``` 23 | 24 | ## Essentials 25 | 26 | ### Import indicators 27 | 28 | Indicators can be imported as 29 | 30 | ```python 31 | from talipp.indicators import 32 | ``` 33 | 34 | For instance, to import [EMA][talipp.indicators.EMA.EMA] indicator, use 35 | 36 | ```python 37 | from talipp.indicators import EMA 38 | ``` 39 | 40 | List of all indicators can be found in the [Indicator catalogue](indicator-catalogue.md). 41 | 42 | ### Basic usage 43 | 44 | Indicators can be fed input values either during their initialization 45 | 46 | ```python 47 | from talipp.indicators import EMA 48 | 49 | ema = EMA(period=3, input_values=[1, 2, 3, 4, 5]) 50 | ``` 51 | 52 | or incrementally 53 | 54 | ```python 55 | from talipp.indicators import EMA 56 | 57 | ema = EMA(period=3) 58 | ema.add(1) 59 | ema.add(2) 60 | ... 61 | ``` 62 | 63 | To print indicator's values you can treat each indicator as a list, i.e. you can do 64 | 65 | ```python 66 | from talipp.indicators import EMA 67 | 68 | ema = EMA(period=3, input_values=[1, 2, 3, 4, 5]) 69 | 70 | print(ema[-1]) 71 | print(ema[-5:]) 72 | print(ema) 73 | ``` 74 | 75 | Detailed description of indicator manipulation can be found in the section [Indicator operations](indicator-operations.md). 76 | 77 | ### Input types 78 | 79 | Indicators can accept two types of input - simple type such as `float` or complex [OHLCV][talipp.ohlcv.OHLCV] type encapsulating structured data such as open price, high price, low price, close price, ... 80 | 81 | Each indicator specifies what type of input is required. For instance, [SMA][talipp.indicators.SMA.SMA] indicator accepts `float` while [Stoch][talipp.indicators.Stoch.Stoch] indicator accepts `OHLCV`. 82 | 83 | ```python 84 | from talipp.indicators import SMA, Stoch 85 | from talipp.ohlcv import OHLCV 86 | 87 | sma = SMA(period=3, input_values=[1, 2, 3]) 88 | stoch = Stoch(period=3, smoothing_period=2, input_values=[OHLCV(1, 2, 3, 4), OHLCV(5, 6, 7, 8)]) 89 | ``` 90 | 91 | Read more about input types in the [Input types](input-types.md) section. 92 | 93 | ## Examples 94 | 95 | The library comes with [examples](https://github.com/nardew/talipp/blob/main/examples/indicators.py) showcasing usage of each indicator on artificial input. 96 | 97 | If you have a binance account, then you can check [examples](https://github.com/nardew/talipp/blob/main/examples/binance_online.py) of indicators on realtime data. 98 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Home 2 | 3 | ![python](https://img.shields.io/pypi/pyversions/talipp?logo=python) 4 | ![pypi](https://img.shields.io/pypi/v/talipp?logo=pypi) 5 | ![GitHub Release Date](https://img.shields.io/github/release-date/nardew/talipp?logo=pypi) 6 | ![pypi](https://img.shields.io/pypi/l/talipp) 7 | 8 | 9 | **talipp** (a.k.a. **tali++**) is a Python library implementing [financial indicators](indicator-catalogue.md) for technical analysis. The distinctive feature of the library is its _incremental computation_ which fits well real-time applications or applications with iterative input in general. 10 | 11 | Supported incremental operations are: 12 | 13 | - **adding** a new input value 14 | - **updating** the last input value 15 | - **removing** input values 16 | 17 | ``` py title="example" 18 | from talipp.indicators import SMA 19 | 20 | # initialize standard moving average with period of 3 21 | sma = SMA(period = 3, input_values = [1, 2, 3, 4]) 22 | 23 | # print indicator 24 | print(f'SMA(3): {sma}') # [None, None, 2.0, 3.0] 25 | 26 | # append a new input value incrementally 27 | sma.add(5) 28 | print(f'SMA(3): {sma}') # [None, None, 2.0, 3.0, 4.0] 29 | 30 | # update the last value 31 | sma.update(8) 32 | print(f'SMA(3): {sma}') # [None, None, 2.0, 3.0, 5.0] 33 | 34 | # update the last value again 35 | sma.update(11) 36 | print(f'SMA(3): {sma}') # [None, None, 2.0, 3.0, 6.0] 37 | 38 | # remove the last value 39 | sma.remove() 40 | print(f'SMA(3): {sma}') # [None, None, 2.0, 3.0] 41 | ``` 42 | 43 | Incremental nature of the library means that any update of the input data is reflected in the indicators' values in O(1) in contrary to O(n) of standard libraries which need to recalculate *all* indicator values from scratch. 44 | 45 | To give you better perspective about the performance gain look at the below figure. It compares running time of incremental (talipp) and non-incremental (talib) libraries when calculating SMA(20) for inputs of various sizes where input values are fed one by one. 46 | 47 | ![SMA(20) comparison](images/sma20-comparison.svg "SMA(20) comparison") 48 | -------------------------------------------------------------------------------- /docs/indicator-chaining.md: -------------------------------------------------------------------------------- 1 | # Indicator chaining 2 | 3 | talipp offers a unique feature of chaining multiple indicators into a pipeline. When indicators are chained, each output of one indicator immediately becomes a new input of the one after forming a train of propagating values. As always, all this in constant time! 4 | 5 | The major benefit of chaining indicators is it allows user to define their custom indicators. To chain indicators, one links them together via `input_indicator` parameter during initialization as illustrated below. Notice how the second indicator produces new outputs even without any explicit calls of `add` method: 6 | 7 | ```python 8 | from talipp.indicators import SMA 9 | 10 | sma1 = SMA(2) 11 | sma2 = SMA(2, input_indicator = sma1) 12 | 13 | sma1.add(1) 14 | print(f"SMA1: {sma1}") # [None] 15 | print(f"SMA2: {sma2}") # [None] 16 | 17 | sma1.add(2) 18 | print(f"SMA1: {sma1}") # [None, 1.5] 19 | print(f"SMA2: {sma2}") # [None, None] 20 | 21 | sma1.add(3) 22 | print(f"SMA1: {sma1}") # [None, 1.5, 2.5] 23 | print(f"SMA2: {sma2}") # [None, None, 2] 24 | ``` 25 | 26 | One typical use-case of indicator chaining is to produce a smoothed version of an existing indicator: 27 | 28 | ```python 29 | from talipp.indicators import SMA, RSI 30 | 31 | rsi = RSI(14) 32 | smoothed_rsi = SMA(9, input_indicator = rsi) 33 | 34 | rsi.add([...]) 35 | print(smoothed_rsi) 36 | ``` 37 | 38 | There is no limit to the number of chained indicators, one can create a computation pipeline from as many indicators as needed. 39 | 40 | ## Input modifiers 41 | 42 | Chaining of indicators assumes that output and input types of chained indicators match. In case they do not, talipp provides an option to specify a conversion function which will be applied to the output value before it is fed to the next indicator. The function is specified in indicator's `__init__` method via `input_modifier` attribute. 43 | 44 | To illustrate usage of input modifiers, imagine we want to create a new indicator based on [Bollinger Bands][talipp.indicators.BB.BB] which will calculate [EMA][talipp.indicators.EMA.EMA] of the upper band. With standard libraries you would first calculate `Bolliger Bands`, then extract the upper band and finally feed it to `EMA`. With indicator chaining we can do better (besides it gives much more efficient solution). The only issue is that while `EMA` expects `floats` as the input, `Bollinger Bands` produce [BBVal][talipp.indicators.BB.BBVal]. Input modifiers for the rescue. 45 | 46 | ```python 47 | from talipp.indicators import BB, EMA 48 | 49 | bb = BB(5, 2) 50 | ema_bb = EMA(3, input_indicator=bb, input_modifier=lambda x: x.ub) 51 | ``` 52 | -------------------------------------------------------------------------------- /docs/indicator-operations.md: -------------------------------------------------------------------------------- 1 | # Indicator operations 2 | 3 | Each indicator provides operations to read, add, update and remove its values. 4 | 5 | ## Reading values 6 | 7 | Indicators implement [Sequence][collections.abc.Sequence] interface, meaning they can be treated as any other list when reading data. 8 | 9 | Following operations demonstrate how to read indicator's values: 10 | 11 | ```python 12 | from talipp.indicators import SMA 13 | 14 | sma = SMA(period=3, input_values=[1,2,3]) 15 | 16 | # print all values 17 | # outputs [None, None, 2] 18 | print(sma) 19 | 20 | # print last value 21 | # outputs 2 22 | print(sma[-1]) 23 | 24 | # print number of values 25 | # outputs 3 26 | print(len(sma)) 27 | ``` 28 | 29 | ## Adding values 30 | 31 | To incrementally add a new value use [add][talipp.indicators.Indicator.Indicator.add] method: 32 | 33 | ```python 34 | from talipp.indicators import SMA 35 | 36 | sma = SMA(period=3, input_values=[1,2,3]) 37 | 38 | # add a single value 39 | sma.add(4) 40 | 41 | # add a list of values 42 | sma.add([4, 5, 6]) 43 | ``` 44 | 45 | ## Updating values 46 | 47 | To update **the most recent** value use [update][talipp.indicators.Indicator.Indicator.update] method: 48 | 49 | ```python 50 | from talipp.indicators import SMA 51 | 52 | sma = SMA(period=3, input_values=[1,2,3]) 53 | 54 | # update the last input value 55 | sma.update(4) 56 | ``` 57 | 58 | !!! note 59 | 60 | Update of a value does not change number of indicator's values. Instead, it first removes the last input value and then it appends a new one. 61 | 62 | ## Removing values 63 | 64 | Indicators provide several ways how to remove data: 65 | 66 | 1. To remove the most recent input value, use [remove][talipp.indicators.Indicator.Indicator.remove] method: 67 | ```python 68 | from talipp.indicators import SMA 69 | 70 | sma = SMA(period=3, input_values=[1,2,3]) 71 | 72 | # outputs [None, None, 2] 73 | print(sma) 74 | 75 | # remove the last input value 76 | sma.remove() 77 | 78 | # outputs [None, None] 79 | print(sma) 80 | ``` 81 | 82 | 1. To remove all input values, use [remove_all][talipp.indicators.Indicator.Indicator.remove_all] method: 83 | ```python 84 | from talipp.indicators import SMA 85 | 86 | sma = SMA(period=3, input_values=[1,2,3]) 87 | 88 | # remove all input values 89 | sma.remove_all() 90 | 91 | # outputs [] 92 | print(sma) 93 | ``` 94 | 95 | 1. To remove **the oldest** values, use [purge_oldest][talipp.indicators.Indicator.Indicator.purge_oldest] method: 96 | ```python 97 | from talipp.indicators import SMA 98 | 99 | sma = SMA(period=3, input_values=[1,2,3]) 100 | 101 | # outputs [None, None, 2] 102 | print(sma) 103 | 104 | # purge the first value 105 | sma.purge_oldest(1) 106 | 107 | # outputs [None, 2] 108 | print(sma) 109 | ``` 110 | 111 | !!! note 112 | 113 | Purging old values is useful when memory consumption is a concern. If old indicator's values are not needed anymore, feel free to purge them. However, be careful not to purge any data if calculation of the current values still depends on them. 114 | -------------------------------------------------------------------------------- /docs/input-types.md: -------------------------------------------------------------------------------- 1 | # Input types 2 | 3 | Indicators work with two types of input data - simple `float` or complex [OHLCV][talipp.ohlcv.OHLCV] objects. While `float` is used in indicators requiring just a plain series of numbers, `OHLCV` object provides additional data (open, high, low, close price and optional volume and time) needed by certain class of indicators. 4 | 5 | Each indicator defines what kind of input it requires. Users can derive it either from the type of `input_values` parameter present in the indicator's `__init__` method or from the indicator's documentation. 6 | 7 | Below is an example of one indicator consuming `floats` and another one consuming `OHLCV` objects. 8 | 9 | ```python 10 | from talipp.indicators import SMA, Stoch 11 | from talipp.ohlcv import OHLCV 12 | 13 | sma = SMA(period=3, input_values=[1, 2, 3]) 14 | stoch = Stoch(period=3, smoothing_period=2, input_values=[OHLCV(1, 2, 3, 4), OHLCV(5, 6, 7, 8)]) 15 | ``` 16 | 17 | ## OHLCV factory 18 | 19 | To simplify conversion from user's format of input data to `OHLCV` objects, talipp provides [OHLCVFactory][talipp.ohlcv.OHLCVFactory] helper class. The factory offers three static helpers: 20 | 21 | ### [from_dict][talipp.ohlcv.OHLCVFactory.from_dict] 22 | 23 | This method accepts a dictionary with `open`, `high`, `low`, `close` and optionally `volume` and `time` keys where each key contains a list of values and generates a list of `OHLCV` objects out of them. 24 | 25 | Example: 26 | 27 | ```python 28 | from talipp.ohlcv import OHLCVFactory 29 | 30 | user_input = { 31 | 'open': [1, 2, 3], 32 | 'high': [4, 5, 6], 33 | 'low': [7, 8, 9], 34 | 'close': [10, 11, 12] 35 | } 36 | 37 | print(OHLCVFactory.from_dict(user_input)) 38 | ``` 39 | 40 | Output: 41 | 42 | ```commandline 43 | [OHLCV(1, 4, 7, 10), OHLCV(2, 5, 8, 11), OHLCV(3, 6, 9, 12)] 44 | ``` 45 | 46 | ### [from_matrix][talipp.ohlcv.OHLCVFactory.from_matrix] 47 | 48 | This method accepts a list of tuples where each tuple represents values to be used in `OHLCV` object. 49 | 50 | Example: 51 | 52 | ```python 53 | from talipp.ohlcv import OHLCVFactory 54 | 55 | user_input = [ 56 | (1, 2, 3, 4), 57 | (5, 6, 7, 8), 58 | (9, 10, 11, 12) 59 | ] 60 | 61 | print(OHLCVFactory.from_matrix(user_input)) 62 | ``` 63 | 64 | Output: 65 | 66 | ```commandline 67 | [OHLCV(1, 2, 3, 4), OHLCV(5, 6, 7, 8), OHLCV(9, 10, 11, 12)] 68 | ``` 69 | 70 | ### [from_matrix2][talipp.ohlcv.OHLCVFactory.from_matrix2] 71 | 72 | Similar to [from_matrix](#from_matrix), this method accepts a list of lists where the first list represents all `open` values, the second represents all `highs`, etc. 73 | 74 | ```python 75 | from talipp.ohlcv import OHLCVFactory 76 | 77 | user_input = [ 78 | [ 1, 2, 3], 79 | [ 4, 5, 6], 80 | [ 7, 8, 9], 81 | [10, 11, 12] 82 | ] 83 | 84 | print(OHLCVFactory.from_matrix2(user_input)) 85 | ``` 86 | 87 | Output: 88 | 89 | ```commandline 90 | [OHLCV(1, 4, 7, 10), OHLCV(2, 5, 8, 11), OHLCV(3, 6, 9, 12)] 91 | ``` 92 | -------------------------------------------------------------------------------- /docs/output-types.md: -------------------------------------------------------------------------------- 1 | # Output types 2 | 3 | Like indicators that process either simple or complex input values, the output values of indicators can also range from simple floats to complex objects. 4 | 5 | Complex output types are required if indicator needs to return multiple values per a single data point. For instance, while [SMA][talipp.indicators.SMA] will always return a single output value for each input value, [Bollinger Bands][talipp.indicators.BB.BB] has to return three values per each input value (lower, central and upper band), hence requiring a complex return type. 6 | 7 | Complex output type is always defined as a `dataclass` and is documented in each indicator module. 8 | 9 | For instance, output type of [Bollinger Bands][talipp.indicators.BB.BB] is [BBVal][talipp.indicators.BB.BBVal] and looks as follows: 10 | 11 | ```python 12 | @dataclass 13 | class BBVal: 14 | lb: float = None 15 | cb: float = None 16 | ub: float = None 17 | ``` 18 | 19 | That's why when printing [Bollinger Bands][talipp.indicators.BB.BB], the output will be 20 | 21 | ```commandline 22 | [BBVal(...), BBVal(...), BBVal(...), ...] 23 | ``` 24 | 25 | Other examples of complex output types are: 26 | 27 | * [MACD][talipp.indicators.MACD.MACD] -> [MACDVal][talipp.indicators.MACD.MACDVal] 28 | * [Parabolic SAR][talipp.indicators.ParabolicSAR.ParabolicSAR] -> [ParabolicSARVal][talipp.indicators.ParabolicSAR.ParabolicSARVal] 29 | * [Stoch][talipp.indicators.Stoch.Stoch] -> [StochVal][talipp.indicators.Stoch.StochVal] 30 | * ... 31 | 32 | When complex outputs serve as an input for other components in a data pipeline sometimes it may be more convenient to decompose them into lists per each attribute of the complex type. In other words, instead of working with 33 | 34 | ```python 35 | [StochVal(k=10, d=None), StochVal(k=20.0, d=15), StochVal(k=12, d=14)] 36 | ``` 37 | 38 | it may be more useful to have 39 | 40 | ```python 41 | { 42 | 'k': [ 10, 20, 12], 43 | 'd': [None, 15, 14] 44 | } 45 | ``` 46 | 47 | To transform the former output into the latter, talipp provides [composite_to_lists][talipp.indicator_util.composite_to_lists] utility function which can be applied to every indicator returning complex types. 48 | -------------------------------------------------------------------------------- /docs/overrides/main.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | 3 | {% block outdated %} 4 | You're not viewing the latest version. 5 | 6 | Click here to go to latest. 7 | 8 | {% endblock %} 9 | -------------------------------------------------------------------------------- /docs/serialization.md: -------------------------------------------------------------------------------- 1 | # Serialization 2 | 3 | This quick guide shows how to serialize full indicator's state including the input and output values and how to restore it later on. This can come handy e.g. if indicator calculated non-trivial number of items and we do not want to calculate them again next time. 4 | 5 | The solution is based on [jsonpickle](https://pypi.org/project/jsonpickle) library which can encode/decode objects into string form. 6 | 7 | ```python 8 | import jsonpickle 9 | from talipp.indicators import BB 10 | 11 | bb = BB(5, 1, list(range(0, 100, 2))) 12 | bb_serialized = jsonpickle.encode(bb, unpicklable = True) 13 | 14 | # write bb_serialized e.g. to a file... 15 | 16 | bb_deserialized = jsonpickle.decode(bb_serialized) 17 | 18 | # use the deserialized indicator as usual 19 | bb_deserialized.add(5) 20 | ``` 21 | -------------------------------------------------------------------------------- /docs/timeframe-sampling.md: -------------------------------------------------------------------------------- 1 | # Timeframe auto-sampling 2 | 3 | Timeframe auto-sampling is a special feature intended for indicators working with [OHLCV][talipp.ohlcv.OHLCV] input. By default, indicators add a new output value for each input one. With timeframe auto-sampling it is possible to "merge" several values received within selected timeframe and keep only the last one in given timeframe. This feature suits well e.g. real-time applications which receive new inputs tens or hundreds times a second but the indicators need to be built on sampled timeframe (secondly, minutely, ...). 4 | 5 | Supported timeframes are available in [SamplingPeriodType][talipp.input.SamplingPeriodType] enum and include values such as 6 | 7 | - [1 second][talipp.input.SamplingPeriodType.SEC_1] 8 | - [3 seconds][talipp.input.SamplingPeriodType.SEC_3] 9 | - [5 seconds][talipp.input.SamplingPeriodType.SEC_5] 10 | - [30 seconds][talipp.input.SamplingPeriodType.SEC_30] 11 | - [1 minute][talipp.input.SamplingPeriodType.MIN_1] 12 | - ... 13 | 14 | To enable auto-sampling, setup `input_sampling` attribute when initializing an indicator: 15 | 16 | ```python 17 | from datetime import datetime 18 | from talipp.indicators import OBV 19 | from talipp.input import SamplingPeriodType 20 | from talipp.ohlcv import OHLCV 21 | 22 | # choose auto-sampling by 15 seconds 23 | obv = OBV(input_sampling=SamplingPeriodType.SEC_15) 24 | 25 | dt = datetime(2024, 1, 1, 0, 0, 0) 26 | ohlcv = OHLCV(1, 1, 1, 1, 1, dt) 27 | 28 | # time 00:00:00 29 | obv.add(ohlcv) 30 | print(len(obv)) # 1 31 | 32 | # time 00:00:13 33 | ohlcv.time = dt.replace(second=13) 34 | obv.add(ohlcv) # still within the same timeframe => no new value added, the last one updated 35 | print(len(obv)) # 1 36 | 37 | # time 00:00:17 38 | ohlcv.time = dt.replace(second=17) 39 | obv.add(ohlcv) # next period entered => new value added 40 | print(len(obv)) # 2 41 | 42 | # time 00:00:25 43 | ohlcv.time = dt.replace(second=25) 44 | obv.add(ohlcv) # still within the same timeframe => no new value added, the last one updated 45 | print(len(obv)) # 2 46 | ``` 47 | 48 | !!! tip 49 | 50 | If you want to apply auto-sampling to an indicator which accepts `float` input, e.g. [MACD][talipp.indicators.MACD] indicator, then wrap each input value in a "dummy" [OHLCV][talipp.ohlcv.OHLCV] object, populate its `close` and `time` components and finally provide [input modifier](indicator-chaining.md#input-modifiers) to extract the value 51 | 52 | !!! example 53 | 54 | ```python 55 | from datetime import datetime 56 | from talipp.indicators import MACD 57 | from talipp.input import SamplingPeriodType 58 | from talipp.ohlcv import OHLCV 59 | 60 | input_floats = [1.0, 2.0, ...] 61 | dt = datetime(2024, 1, 1, 0, 0, 0) 62 | input_ohlcv = [OHLCV(None, None, None, value, None, dt) for value in input_floats] 63 | macd = MACD(input_values=input_ohlcv, input_modifier=lambda x: x.close, input_sampling=SamplingPeriodType.SEC_15) 64 | ``` 65 | -------------------------------------------------------------------------------- /examples/draw_graph.py: -------------------------------------------------------------------------------- 1 | import csv 2 | 3 | import matplotlib.pyplot as plt 4 | from matplotlib.ticker import FuncFormatter 5 | 6 | 7 | def thousands_separator(x): 8 | return f'{int(x):,}' 9 | 10 | 11 | def draw_graph(csv_file_path): 12 | x_values = [] 13 | y_values = [] 14 | y2_values = [] 15 | 16 | # Open the CSV file and read the values 17 | with open(csv_file_path, newline='') as csvfile: 18 | reader = csv.reader(csvfile, delimiter=";") 19 | for row in reader: 20 | # Assume the first value is x and the second value is y 21 | x_values.append(int(row[1].replace(",", ""))) 22 | y_values.append(float(row[2])) 23 | y2_values.append(float(row[4])) 24 | 25 | # Plot the values 26 | plt.figure(figsize=[10,5]) # You can adjust the figure size as needed 27 | #plt.plot(x_values, y_values) # You can change the marker style 28 | plt.plot(x_values, y_values, color='orange') 29 | plt.plot(x_values, y2_values, color='royalblue') # You can change the marker style 30 | plt.title('SMA(20) performance comparison', fontweight='bold', fontname='Helvetica', fontsize=16, color="black") # Add a title to the graph 31 | plt.xlabel('Input size', color="dimgray") # Label the x-axis 32 | plt.ylabel('Time [ms]', color="dimgray") # Label the y-axis 33 | #plt.grid(True) # Add grid lines for better readability 34 | plt.grid(True, which='both', axis='both', linestyle='-', color='lightgray') 35 | formatter = FuncFormatter(thousands_separator) 36 | plt.gca().xaxis.set_major_formatter(formatter) 37 | x_ticks = [x for x in x_values if x % 10000 == 0] 38 | if x_values[0] not in x_ticks: 39 | x_ticks.insert(0, x_values[0]) 40 | if x_values[-1] not in x_ticks: 41 | x_ticks.append(x_values[-1]) 42 | plt.xticks(ticks=x_ticks, fontname='Helvetica', color="dimgray") 43 | plt.yticks(color="dimgray") 44 | 45 | end_x = x_values[-1] 46 | end_y = y_values[-1] 47 | plt.text(end_x - 0.005 * (max(x_values) - min(x_values)), 48 | end_y + 1 * (max(y_values) - min(y_values)), 'talipp', fontsize=12, fontweight='bold', ha='right', color='orange', fontname='Helvetica') 49 | 50 | end_y2 = y2_values[-1] 51 | plt.text(end_x - 0.03 * (max(x_values) - min(x_values)), 52 | end_y2 - 0.01 * (max(y2_values) - min(y2_values)), 'non-incremental library (talib)', fontsize=12, fontweight='bold', ha='right', 53 | color='royalblue', fontname='Helvetica') 54 | 55 | #plt.show() 56 | plt.savefig("sma20-comparison.svg", format='svg', bbox_inches='tight') 57 | 58 | if __name__ == "__main__": 59 | draw_graph('in.csv') 60 | -------------------------------------------------------------------------------- /examples/indicators.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | from talipp.indicators import AccuDist, ADX, ALMA, AO, Aroon, ATR, BB, BOP, CCI, ChaikinOsc, ChandeKrollStop, CHOP, \ 4 | CoppockCurve, DEMA, DonchianChannels, DPO, EMA, EMV, ForceIndex, HMA, IBS, Ichimoku, KAMA, KeltnerChannels, KST, KVO, \ 5 | MACD, MassIndex, MeanDev, NATR, OBV, ROC, RogersSatchell, RSI, ParabolicSAR, SFX, SMA, SMMA, SOBV, STC, StdDev, Stoch, StochRSI, \ 6 | SuperTrend, T3, TEMA, TRIX, TSI, TTM, UO, VTX, VWAP, VWMA, WMA, ZigZag, ZLEMA 7 | from talipp.ohlcv import OHLCVFactory 8 | 9 | if __name__ == "__main__": 10 | 11 | close = random.sample(range(1, 10000), 1000) 12 | ohlcv = OHLCVFactory.from_matrix2([ 13 | random.sample(range(1, 10000), 1000), 14 | random.sample(range(1, 10000), 1000), 15 | random.sample(range(1, 10000), 1000), 16 | random.sample(range(1, 10000), 1000), 17 | random.sample(range(1, 10000), 1000)] 18 | ) 19 | print(f"Last OHLCV: {ohlcv[-1]}") 20 | 21 | print(f'AccuDist: {AccuDist(ohlcv)[-1]}') 22 | print(f'ADX: {ADX(14, 14, ohlcv)[-1]}') 23 | print(f'ALMA: {ALMA(9, 0.85, 6, close)[-1]}') 24 | print(f'AO: {AO(5, 34, ohlcv)[-1]}') 25 | print(f'Aroon: {Aroon(14, ohlcv)[-1]}') 26 | print(f'ATR: {ATR(14, ohlcv)[-1]}') 27 | print(f'BB: {BB(20, 2, close)[-1]}') 28 | print(f'BOP: {BOP(ohlcv)[-1]}') 29 | print(f'CCI: {CCI(20, ohlcv)[-1]}') 30 | print(f'ChaikinOsc: {ChaikinOsc(3, 10, ohlcv)[-1]}') 31 | print(f'ChandeKrollStop: {ChandeKrollStop(10, 2, 9, ohlcv)[-1]}') 32 | print(f'CHOP: {CHOP(14, ohlcv)[-1]}') 33 | print(f'CoppockCurve: {CoppockCurve(11, 14, 10, close)[-1]}') 34 | print(f'DEMA: {DEMA(20, close)[-1]}') 35 | print(f'DonchianChannels: {DonchianChannels(20, ohlcv)[-1]}') 36 | print(f'DPO: {DPO(20, close)[-1]}') 37 | print(f'EMA: {EMA(20, close)[-1]}') 38 | print(f'EMV: {EMV(14, 10000, ohlcv)[-1]}') 39 | print(f'ForceIndex: {ForceIndex(13, ohlcv)[-1]}') 40 | print(f'HMA: {HMA(9, close)[-1]}') 41 | print(f'IBS: {IBS(ohlcv)[-1]}') 42 | print(f'Ichimoku: {Ichimoku(26, 9, 52, 52, 26, ohlcv)[-1]}') 43 | print(f'KAMA: {KAMA(14, 2, 30, close)[-1]}') 44 | print(f'KeltnerChannels: {KeltnerChannels(20, 26, 1, 1, ohlcv)[-1]}') 45 | print(f'KST: {KST(10, 10, 15, 10, 20, 10, 30, 15, 9, close)[-1]}') 46 | print(f'KVO: {KVO(34, 55, ohlcv)[-1]}') 47 | print(f'MACD: {MACD(12, 26, 9, close)[-1]}') 48 | print(f'MassIndex: {MassIndex(9, 9, 10, ohlcv)[-1]}') 49 | print(f'MeanDev: {MeanDev(10, close)[-1]}') 50 | print(f'NATR: {NATR(14, ohlcv)[-1]}') 51 | print(f'OBV: {OBV(ohlcv)[-1]}') 52 | print(f'ROC: {ROC(9, close)[-1]}') 53 | print(f'RogersSatchell: {RogersSatchell(9, ohlcv)[-1]}') 54 | print(f'RSI: {RSI(14, close)[-1]}') 55 | print(f"SAR: {ParabolicSAR(0.02, 0.02, 0.2, ohlcv)[-20:]}") 56 | print(f'SFX: {SFX(12, 12, 3, ohlcv)[-1]}') 57 | print(f'SMA: {SMA(20, close)[-1]}') 58 | print(f'SMMA: {SMMA(7, close)[-1]}') 59 | print(f'SOBV: {SOBV(7, ohlcv)[-1]}') 60 | print(f'STC: {STC(23, 50, 10, 3, close)[-1]}') 61 | print(f'StdDev: {StdDev(7, close)[-1]}') 62 | print(f'Stoch: {Stoch(14, 3, ohlcv)[-1]}') 63 | print(f'StochRSI: {StochRSI(14, 14, 3, 3, close)[-1]}') 64 | print(f'SuperTrend: {SuperTrend(10, 3, ohlcv)[-20:]}') 65 | print(f'T3: {T3(20, 0.7, close)[-1]}') 66 | print(f'TEMA: {TEMA(20, close)[-1]}') 67 | print(f'TRIX: {TRIX(18, close)[-1]}') 68 | print(f'TSI: {TSI(13, 25, close)[-1]}') 69 | print(f'TTM: {TTM(20, input_values = ohlcv)[-20:]}') 70 | print(f'UO: {UO(7, 14, 28, ohlcv)[-1]}') 71 | print(f'VTX: {VTX(14, ohlcv)[-1]}') 72 | print(f'VWAP: {VWAP(ohlcv)[-1]}') 73 | print(f'VWMA: {VWMA(20, ohlcv)[-1]}') 74 | print(f'WMA: {WMA(9, close)[-1]}') 75 | print(f'ZigZag: {ZigZag(0.1, 10, ohlcv)[-5:]}') 76 | print(f'ZLEMA: {ZLEMA(9, close)[-1]}') 77 | -------------------------------------------------------------------------------- /examples/performance.py: -------------------------------------------------------------------------------- 1 | import time 2 | from typing import List 3 | 4 | from talipp.indicators import SMA 5 | 6 | 7 | class Timer(object): 8 | def __init__(self, name: str = "") -> None: 9 | self.name = name 10 | 11 | self.start_tmstmp_ms = None 12 | 13 | def __enter__(self) -> None: 14 | self.start_tmstmp_ms = time.time_ns() 15 | 16 | def __exit__(self, type, value, traceback) -> None: 17 | print(f'Timer {self.name} finished. Took {round((time.time_ns() - self.start_tmstmp_ms)/1000000, 3)} ms.') 18 | 19 | 20 | def gen_values(num: int) -> List[int]: 21 | return [i for i in range(0, num)] 22 | 23 | 24 | def measure(values_n: int, indicator, *args): 25 | print(f"Calculate {indicator.__name__}{args} from {values_n:,} values") 26 | values = gen_values(values_n) 27 | with Timer(): 28 | indicator(*args, values) 29 | 30 | 31 | def test_sma(): 32 | measure(1000, SMA, 10) 33 | measure(100000, SMA, 10) 34 | measure(1000000, SMA, 10) 35 | 36 | measure(1000, SMA, 200) 37 | measure(100000, SMA, 200) 38 | measure(1000000, SMA, 200) 39 | 40 | 41 | if __name__ == "__main__": 42 | test_sma() 43 | -------------------------------------------------------------------------------- /examples/readme_example.py: -------------------------------------------------------------------------------- 1 | from talipp.indicator_util import composite_to_lists 2 | from talipp.indicators import EMA, SMA, Stoch 3 | from talipp.ohlcv import OHLCVFactory 4 | 5 | # EMA indicator ([float] -> [float]) 6 | ema = EMA(period = 3, input_values = [1, 3, 5, 7, 9, 2, 4, 6, 8, 10]) 7 | 8 | # treat indicators as any other list 9 | print(f'EMA(3): {ema}') # [3.0, 5.0, 7.0, 4.5, 4.25, 5.125, 6.5625, 8.28125] 10 | print(f'Last EMA value: {ema[-1]}') # 8.28125 11 | 12 | # append a new input value in the incrementally 13 | ema.add(11) 14 | print(f'EMA after adding a new value: {ema}') # [3.0, 5.0, 7.0, 4.5, 4.25, 5.125, 6.5625, 8.28125, 9.640625] 15 | 16 | # change the last added value 17 | ema.update(15) 18 | print(f'EMA after updating the last value: {ema}') # [3.0, 5.0, 7.0, 4.5, 4.25, 5.125, 6.5625, 8.28125, 11.640625] 19 | 20 | # change the last added value again 21 | ema.update(18) 22 | print(f'EMA after updating the last value: {ema}') # [3.0, 5.0, 7.0, 4.5, 4.25, 5.125, 6.5625, 8.28125, 13.140625] 23 | 24 | # remove the last added value 25 | ema.remove() 26 | print(f'EMA after removing the last value: {ema}') # [3.0, 5.0, 7.0, 4.5, 4.25, 5.125, 6.5625, 8.28125] 27 | 28 | # purge the oldest input value 29 | ema.purge_oldest(1) 30 | print(f'EMA after purging the oldest value: {ema}') # [5.0, 7.0, 4.5, 4.25, 5.125, 6.5625, 8.28125] 31 | 32 | # STOCH indicator ([OHLCV] -> [composite]) 33 | stoch = Stoch(5, 3, OHLCVFactory.from_dict({ 34 | 'high': [5, 10, 15, 20, 25, 30, 35], 35 | 'low': [1, 4, 7, 10, 13, 16, 19], 36 | 'close': [3, 9, 8, 19, 18, 17, 19] 37 | })) 38 | 39 | # print result as a list of composite values for 'k' and 'd' output parameters 40 | print(f'Stoch(5, 3) composite result: {stoch}') # [StochVal(k=70.83333333333333, d=None), StochVal(k=50.0, d=None), StochVal(k=42.857142857142854, d=54.563492063492056)] 41 | 42 | # print result as lists per output parameters 43 | print(f'Stoch(5, 3) decomposed result: {composite_to_lists(stoch)}') # {'k': [70.83333333333333, 50.0, 42.857142857142854], 'd': [None, None, 54.563492063492056]} 44 | 45 | # Indicator chaining 46 | sma1 = SMA(3) 47 | sma2 = SMA(3, input_indicator = sma1) 48 | sma3 = SMA(3, input_indicator = sma2) 49 | 50 | print(f"Chain three moving averages:") 51 | sma1.add([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 52 | print(f"SMA1: {sma1}") # [2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0] 53 | print(f"SMA2: {sma2}") # [3.0, 4.0, 5.0, 6.0, 7.0, 8.0] 54 | print(f"SMA3: {sma3}") # [4.0, 5.0, 6.0, 7.0] 55 | 56 | print(f"Purge oldest 3 values:") 57 | sma1.purge_oldest(3) 58 | print(f"SMA1: {sma1}") # [5.0, 6.0, 7.0, 8.0, 9.0] 59 | print(f"SMA2: {sma2}") # [6.0, 7.0, 8.0] 60 | print(f"SMA3: {sma3}") # [7.0] 61 | -------------------------------------------------------------------------------- /examples/serialization.py: -------------------------------------------------------------------------------- 1 | import jsonpickle 2 | from talipp.indicators import BB 3 | 4 | if __name__ == "__main__": 5 | bb = BB(5, 1, list(range(0, 100, 2))) 6 | bb_pickled = jsonpickle.encode(bb, unpicklable = True) 7 | bb_unpickled = jsonpickle.decode(bb_pickled) 8 | 9 | print(f"Original BB: {bb[-1]}") 10 | print(f"Unpickled BB: {bb_unpickled[-1]}") 11 | 12 | print('\nUpdating indicators...\n') 13 | 14 | bb.add(100) 15 | bb_unpickled.add(100) 16 | 17 | print(f"Updated BB: {bb[-1]}") 18 | print(f"Updated unpickled BB: {bb_unpickled[-1]}") 19 | -------------------------------------------------------------------------------- /requirements-mkdocs.txt: -------------------------------------------------------------------------------- 1 | black 2 | markdown-callouts 3 | mike 4 | mkdocs-gen-files 5 | mkdocs-git-revision-date-localized-plugin 6 | mkdocs-link-marker 7 | mkdocs-literate-nav 8 | mkdocs-material 9 | mkdocs-section-index 10 | mkdocstrings[python] 11 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nardew/talipp/70dc9a26889c9c9329e44321e1362c4db43dbcc3/requirements.txt -------------------------------------------------------------------------------- /scripts/gen_ref_pages.py: -------------------------------------------------------------------------------- 1 | """Generate the code reference pages and navigation.""" 2 | 3 | from pathlib import Path 4 | 5 | import mkdocs_gen_files 6 | 7 | nav = mkdocs_gen_files.Nav() 8 | mod_symbol = '' 9 | 10 | root = Path(__file__).parent.parent 11 | src = root / "talipp" 12 | 13 | for path in sorted(src.rglob("*.py")): 14 | module_path = path.relative_to(root).with_suffix("") 15 | doc_path = path.relative_to(root).with_suffix(".md") 16 | full_doc_path = Path("reference", doc_path) 17 | 18 | parts = tuple(module_path.parts) 19 | 20 | if parts[-1] == "__init__": 21 | parts = parts[:-1] 22 | doc_path = doc_path.with_name("index.md") 23 | full_doc_path = full_doc_path.with_name("index.md") 24 | elif parts[-1] == "__main__": 25 | continue 26 | 27 | nav_parts = [f"{mod_symbol} {part}" for part in parts] 28 | nav[tuple(nav_parts)] = doc_path.as_posix() 29 | 30 | with mkdocs_gen_files.open(full_doc_path, "w") as fd: 31 | ident = ".".join(parts) 32 | fd.write(f"::: {ident}") 33 | 34 | mkdocs_gen_files.set_edit_path(full_doc_path, path.relative_to(root)) 35 | 36 | with mkdocs_gen_files.open("reference/SUMMARY.md", "w") as nav_file: 37 | nav_file.writelines(nav.build_literate_nav()) 38 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | with open("README.md", "r") as fh: 4 | long_description = fh.read() 5 | 6 | with open("requirements.txt", "r") as fh: 7 | requirements = fh.readlines() 8 | requirements = [line.strip() for line in requirements] 9 | 10 | with open("VERSION", "r") as fh: 11 | version = fh.read() 12 | 13 | setuptools.setup( 14 | name="talipp", 15 | version=version, 16 | author="nardew", 17 | author_email="talipp.pyth@gmail.com", 18 | description="talipp - Incremental Technical Analysis Library", 19 | long_description=long_description, 20 | long_description_content_type="text/markdown", 21 | url="https://github.com/nardew/talipp", 22 | packages=setuptools.find_packages(), 23 | classifiers=[ 24 | "Development Status :: 5 - Production/Stable", 25 | "Intended Audience :: Developers", 26 | "Intended Audience :: Financial and Insurance Industry", 27 | "Intended Audience :: Science/Research", 28 | "Programming Language :: Python :: 3", 29 | "Programming Language :: Python :: 3.8", 30 | "Programming Language :: Python :: 3.9", 31 | "Programming Language :: Python :: 3.10", 32 | "Programming Language :: Python :: 3.11", 33 | "License :: OSI Approved :: MIT License", 34 | "Operating System :: OS Independent", 35 | "Topic :: Software Development :: Libraries", 36 | "Topic :: Software Development :: Libraries :: Python Modules", 37 | "Typing :: Typed", 38 | ], 39 | install_requires=requirements, 40 | python_requires='>=3.8.0', 41 | ) 42 | -------------------------------------------------------------------------------- /talipp/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nardew/talipp/70dc9a26889c9c9329e44321e1362c4db43dbcc3/talipp/__init__.py -------------------------------------------------------------------------------- /talipp/exceptions.py: -------------------------------------------------------------------------------- 1 | """Exception definitions.""" 2 | 3 | 4 | class TalippException(Exception): 5 | """Base talipp exception class.""" 6 | pass 7 | -------------------------------------------------------------------------------- /talipp/indicators/ALMA.py: -------------------------------------------------------------------------------- 1 | from math import exp 2 | from typing import List, Any 3 | 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | 7 | 8 | class ALMA(Indicator): 9 | """Arnaud Legoux Moving Average. 10 | 11 | Input type: `float` 12 | 13 | Output type: `float` 14 | 15 | Args: 16 | period: Moving average period. 17 | offset: Weights offset. 18 | sigma: Weights sigma factor. 19 | input_values: List of input values. 20 | input_indicator: Input indicator. 21 | input_modifier: Input modifier. 22 | input_sampling: Input sampling type. 23 | """ 24 | 25 | def __init__(self, period: int, 26 | offset: float, 27 | sigma: float, 28 | input_values: List[float] = None, 29 | input_indicator: Indicator = None, 30 | input_modifier: InputModifierType = None, 31 | input_sampling: SamplingPeriodType = None): 32 | super().__init__(input_modifier=input_modifier, 33 | input_sampling=input_sampling) 34 | 35 | self.period = period 36 | self.offset = offset 37 | self.sigma = sigma 38 | 39 | # calculate weights and normalisation factor (w_sum) 40 | self.w = [] 41 | self.w_sum = 0.0 42 | s = self.period / float(self.sigma) 43 | m = (self.period - 1) * self.offset 44 | for i in range(0, self.period): 45 | self.w.append(exp(-1 * (i - m) * (i - m) / (2 * s * s))) 46 | self.w_sum += self.w[-1] 47 | 48 | self.initialize(input_values, input_indicator) 49 | 50 | def _calculate_new_value(self) -> Any: 51 | if len(self.input_values) < self.period: 52 | return None 53 | else: 54 | alma = 0.0 55 | for i in range(0, self.period): 56 | alma += self.input_values[-(self.period - i)] * self.w[i] 57 | 58 | return alma / self.w_sum 59 | -------------------------------------------------------------------------------- /talipp/indicators/AO.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | from talipp.ma import MAType, MAFactory 7 | from talipp.ohlcv import OHLCV 8 | 9 | 10 | class AO(Indicator): 11 | """Awesome Oscillator. 12 | 13 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 14 | 15 | Output type: `float` 16 | 17 | Args: 18 | fast_period: Fast moving average period. 19 | slow_period: Slow moving average period. 20 | input_values: List of input values. 21 | input_indicator: Input indicator. 22 | input_modifier: Input modifier. 23 | ma_type: Moving average type. 24 | input_sampling: Input sampling type. 25 | """ 26 | 27 | def __init__(self, fast_period: int, 28 | slow_period: int, 29 | input_values: List[OHLCV] = None, 30 | input_indicator: Indicator = None, 31 | input_modifier: InputModifierType = None, 32 | ma_type: MAType = MAType.SMA, 33 | input_sampling: SamplingPeriodType = None): 34 | super().__init__(input_modifier=input_modifier, 35 | input_sampling=input_sampling) 36 | 37 | self.fast_period = fast_period 38 | self.slow_period = slow_period 39 | 40 | self.ma_fast = MAFactory.get_ma(ma_type, fast_period) 41 | self.ma_slow = MAFactory.get_ma(ma_type, slow_period) 42 | 43 | self.add_managed_sequence(self.ma_fast) 44 | self.add_managed_sequence(self.ma_slow) 45 | 46 | self.initialize(input_values, input_indicator) 47 | 48 | def _calculate_new_value(self) -> Any: 49 | median = (self.input_values[-1].high + self.input_values[-1].low) / 2.0 50 | 51 | self.ma_fast.add(median) 52 | self.ma_slow.add(median) 53 | 54 | if not has_valid_values(self.ma_fast) or not has_valid_values(self.ma_slow): 55 | return None 56 | else: 57 | return self.ma_fast[-1] - self.ma_slow[-1] 58 | -------------------------------------------------------------------------------- /talipp/indicators/ATR.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | from talipp.ohlcv import OHLCV 7 | 8 | 9 | class ATR(Indicator): 10 | """Average True Range 11 | 12 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 13 | 14 | Output type: `float` 15 | 16 | Args: 17 | period: Period. 18 | input_values: List of input values. 19 | input_indicator: Input indicator. 20 | input_modifier: Input modifier. 21 | input_sampling: Input sampling type. 22 | """ 23 | 24 | def __init__(self, period: int, 25 | input_values: List[OHLCV] = None, 26 | input_indicator: Indicator = None, 27 | input_modifier: InputModifierType = None, 28 | input_sampling: SamplingPeriodType = None): 29 | super(ATR, self).__init__(input_modifier=input_modifier, 30 | input_sampling=input_sampling) 31 | 32 | self.period = period 33 | self.tr = [] 34 | 35 | self.add_managed_sequence(self.tr) 36 | 37 | self.initialize(input_values, input_indicator) 38 | 39 | def _calculate_new_value(self) -> Any: 40 | high = self.input_values[-1].high 41 | low = self.input_values[-1].low 42 | 43 | if has_valid_values(self.input_values, 1, exact=True): 44 | self.tr.append(high - low) 45 | else: 46 | close2 = self.input_values[-2].close 47 | self.tr.append(max( 48 | high - low, 49 | abs(high - close2), 50 | abs(low - close2), 51 | )) 52 | 53 | if len(self.input_values) < self.period: 54 | return None 55 | elif len(self.input_values) == self.period: 56 | return sum(self.tr) / self.period 57 | else: 58 | return (self.output_values[-1] * (self.period - 1) + self.tr[-1]) / self.period 59 | -------------------------------------------------------------------------------- /talipp/indicators/AccuDist.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | from talipp.ohlcv import OHLCV 7 | 8 | 9 | class AccuDist(Indicator): 10 | """Accumulation and Distribution Line. 11 | 12 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 13 | 14 | Output type: `float` 15 | 16 | Args: 17 | input_values: List of input values. 18 | input_indicator: Input indicator. 19 | input_modifier: Input modifier. 20 | input_sampling: Input sampling type. 21 | """ 22 | 23 | def __init__(self, input_values: List[OHLCV] = None, 24 | input_indicator: Indicator = None, 25 | input_modifier: InputModifierType = None, 26 | input_sampling: SamplingPeriodType = None): 27 | super().__init__( 28 | input_modifier=input_modifier, 29 | input_sampling=input_sampling) 30 | 31 | self.initialize(input_values, input_indicator) 32 | 33 | def _calculate_new_value(self) -> Any: 34 | value = self.input_values[-1] 35 | 36 | if value.high != value.low: 37 | mfm = ((value.close - value.low) - (value.high - value.close)) / float(value.high - value.low) 38 | mfv = mfm * value.volume 39 | else: 40 | # in case high and low are equal (and hence division by zero above), return None 41 | return None 42 | 43 | if not has_valid_values(self.output_values): 44 | return mfv 45 | else: 46 | return self.output_values[-1] + mfv 47 | -------------------------------------------------------------------------------- /talipp/indicators/Aroon.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List, Any 3 | 4 | from talipp.indicator_util import has_valid_values 5 | from talipp.indicators.Indicator import Indicator, InputModifierType 6 | from talipp.input import SamplingPeriodType 7 | from talipp.ohlcv import OHLCV 8 | 9 | 10 | @dataclass 11 | class AroonVal: 12 | """`Aroon` output type. 13 | 14 | Args: 15 | up: Aroon up. 16 | down: Aroon down. 17 | """ 18 | 19 | up: float = None 20 | down: float = None 21 | 22 | 23 | class Aroon(Indicator): 24 | """Aroon Up/Down 25 | 26 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 27 | 28 | Output type: [AroonVal][talipp.indicators.Aroon.AroonVal] 29 | 30 | Args: 31 | period: Aroon period. 32 | input_values: List of input values. 33 | input_indicator: Input indicator. 34 | input_modifier: Input modifier. 35 | input_sampling: Input sampling type. 36 | """ 37 | 38 | def __init__(self, period: int, 39 | input_values: List[OHLCV] = None, 40 | input_indicator: Indicator = None, 41 | input_modifier: InputModifierType = None, 42 | input_sampling: SamplingPeriodType = None): 43 | super().__init__(input_modifier=input_modifier, 44 | output_value_type=AroonVal, 45 | input_sampling=input_sampling) 46 | 47 | self.period = period 48 | 49 | self.initialize(input_values, input_indicator) 50 | 51 | def _calculate_new_value(self) -> Any: 52 | if not has_valid_values(self.input_values, self.period+1): 53 | return None 54 | 55 | # search in reversed list in order to get the right-most index 56 | days_high = self.period - max(reversed(range(self.period + 1)), 57 | key = lambda x: self.input_values[-self.period - 1:][x].high) 58 | days_low = self.period - min(reversed(range(self.period + 1)), 59 | key = lambda x: self.input_values[-self.period - 1:][x].low) 60 | 61 | return AroonVal(100.0 * (self.period - days_high) / self.period, 62 | 100.0 * (self.period - days_low) / self.period) 63 | -------------------------------------------------------------------------------- /talipp/indicators/BB.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List, Any 3 | 4 | from talipp.indicator_util import has_valid_values 5 | from talipp.indicators.Indicator import Indicator, InputModifierType 6 | from talipp.indicators.StdDev import StdDev 7 | from talipp.input import SamplingPeriodType 8 | from talipp.ma import MAType, MAFactory 9 | 10 | 11 | @dataclass 12 | class BBVal: 13 | """`BB` output type. 14 | 15 | Args: 16 | lb: Lower band. 17 | cb: Central band. 18 | ub: Upper band. 19 | """ 20 | 21 | lb: float = None 22 | cb: float = None 23 | ub: float = None 24 | 25 | 26 | class BB(Indicator): 27 | """Bollinger Bands. 28 | 29 | Input type: `float` 30 | 31 | Output type: [BBVal][talipp.indicators.BB.BBVal] 32 | 33 | Args: 34 | period: Period. 35 | std_dev_mult: Standard deviation multiplier. 36 | input_values: List of input values. 37 | input_indicator: Input indicator. 38 | input_modifier: Input modifier. 39 | input_sampling: Input sampling type. 40 | """ 41 | 42 | def __init__(self, period: int, 43 | std_dev_mult: float, 44 | input_values: List[float] = None, 45 | input_indicator: Indicator = None, 46 | input_modifier: InputModifierType = None, 47 | ma_type: MAType = MAType.SMA, 48 | input_sampling: SamplingPeriodType = None): 49 | super().__init__(input_modifier=input_modifier, 50 | output_value_type=BBVal, 51 | input_sampling=input_sampling) 52 | 53 | self.period = period 54 | self.std_dev_mult = std_dev_mult 55 | 56 | self.central_band = MAFactory.get_ma(ma_type, period) 57 | self.std_dev = StdDev(self.period) 58 | 59 | self.add_sub_indicator(self.central_band) 60 | self.add_sub_indicator(self.std_dev) 61 | 62 | self.initialize(input_values, input_indicator) 63 | 64 | def _calculate_new_value(self) -> Any: 65 | if not has_valid_values(self.input_values, self.period): 66 | return None 67 | 68 | return BBVal( 69 | self.central_band[-1] - self.std_dev_mult * self.std_dev[-1], 70 | self.central_band[-1], 71 | self.central_band[-1] + self.std_dev_mult * self.std_dev[-1] 72 | ) 73 | -------------------------------------------------------------------------------- /talipp/indicators/BOP.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicators.Indicator import Indicator, InputModifierType 4 | from talipp.input import SamplingPeriodType 5 | from talipp.ohlcv import OHLCV 6 | 7 | 8 | class BOP(Indicator): 9 | """Balance Of Power. 10 | 11 | Input type: `float` 12 | 13 | Output type: `float` 14 | 15 | Args: 16 | input_values: List of input values. 17 | input_indicator: Input indicator. 18 | input_modifier: Input modifier. 19 | input_sampling: Input sampling type. 20 | """ 21 | 22 | def __init__(self, input_values: List[OHLCV] = None, 23 | input_indicator: Indicator = None, 24 | input_modifier: InputModifierType = None, 25 | input_sampling: SamplingPeriodType = None): 26 | super().__init__(input_modifier=input_modifier, 27 | input_sampling=input_sampling) 28 | 29 | self.initialize(input_values, input_indicator) 30 | 31 | def _calculate_new_value(self) -> Any: 32 | value = self.input_values[-1] 33 | if value.high != value.low: 34 | return (value.close - value.open) / float(value.high - value.low) 35 | else: 36 | return None 37 | -------------------------------------------------------------------------------- /talipp/indicators/CCI.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.indicators.MeanDev import MeanDev 6 | from talipp.input import SamplingPeriodType 7 | from talipp.ohlcv import OHLCV 8 | 9 | 10 | class CCI(Indicator): 11 | """Commodity Channel Index. 12 | 13 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 14 | 15 | Output type: `float` 16 | 17 | Args: 18 | period: Period. 19 | input_values: List of input values. 20 | input_indicator: Input indicator. 21 | input_modifier: Input modifier. 22 | input_sampling: Input sampling type. 23 | """ 24 | 25 | def __init__(self, period: int, 26 | input_values: List[OHLCV] = None, 27 | input_indicator: Indicator = None, 28 | input_modifier: InputModifierType = None, 29 | input_sampling: SamplingPeriodType = None): 30 | super().__init__(input_modifier=input_modifier, 31 | input_sampling=input_sampling) 32 | 33 | self.mean_dev = MeanDev(period) 34 | self.add_managed_sequence(self.mean_dev) 35 | 36 | self.initialize(input_values, input_indicator) 37 | 38 | def _calculate_new_value(self) -> Any: 39 | value = self.input_values[-1] 40 | typical_price = (value.high + value.low + value.close) / 3.0 41 | 42 | self.mean_dev.add(typical_price) 43 | 44 | if not has_valid_values(self.mean_dev, 1): 45 | return None 46 | 47 | # take SMA(typical_price) directly from MeanDev since it is already calculating it in the background 48 | return (typical_price - self.mean_dev.ma[-1]) / (0.015 * self.mean_dev[-1]) 49 | -------------------------------------------------------------------------------- /talipp/indicators/CHOP.py: -------------------------------------------------------------------------------- 1 | from math import log10 2 | from typing import List, Any 3 | 4 | from talipp.indicator_util import has_valid_values 5 | from talipp.indicators.ATR import ATR 6 | from talipp.indicators.Indicator import Indicator, InputModifierType 7 | from talipp.input import SamplingPeriodType 8 | from talipp.ohlcv import OHLCV 9 | 10 | 11 | class CHOP(Indicator): 12 | """Choppiness Index. 13 | 14 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 15 | 16 | Output type: `float` 17 | 18 | Args: 19 | period: Period. 20 | input_values: List of input values. 21 | input_indicator: Input indicator. 22 | input_modifier: Input modifier. 23 | input_sampling: Input sampling type. 24 | """ 25 | 26 | def __init__(self, period: int, 27 | input_values: List[OHLCV] = None, 28 | input_indicator: Indicator = None, 29 | input_modifier: InputModifierType = None, 30 | input_sampling: SamplingPeriodType = None): 31 | super().__init__(input_modifier=input_modifier, 32 | input_sampling=input_sampling) 33 | 34 | self.period = period 35 | 36 | self.atr = ATR(1) 37 | self.add_sub_indicator(self.atr) 38 | 39 | self.initialize(input_values, input_indicator) 40 | 41 | def _calculate_new_value(self) -> Any: 42 | if not has_valid_values(self.atr, self.period) or not has_valid_values(self.input_values, self.period): 43 | return None 44 | 45 | max_high = max(self.input_values[-self.period:], key = lambda x: x.high).high 46 | min_low = min(self.input_values[-self.period:], key = lambda x: x.low).low 47 | 48 | if max_high != min_low: 49 | return 100.0 * log10(sum(self.atr[-self.period:]) / (max_high - min_low) ) / log10(self.period) 50 | else: 51 | return None 52 | -------------------------------------------------------------------------------- /talipp/indicators/ChaikinOsc.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.AccuDist import AccuDist 5 | from talipp.indicators.Indicator import Indicator, InputModifierType 6 | from talipp.input import SamplingPeriodType 7 | from talipp.ma import MAType, MAFactory 8 | from talipp.ohlcv import OHLCV 9 | 10 | 11 | class ChaikinOsc(Indicator): 12 | """Chaikin Oscillator. 13 | 14 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 15 | 16 | Output type: `float` 17 | 18 | Args: 19 | fast_period: Fast moving average period. 20 | slow_period: Slow moving average period. 21 | input_values: List of input values. 22 | input_indicator: Input indicator. 23 | input_modifier: Input modifier. 24 | input_sampling: Input sampling type. 25 | """ 26 | 27 | def __init__(self, fast_period: int, 28 | slow_period: int, 29 | input_values: List[OHLCV] = None, 30 | input_indicator: Indicator = None, 31 | input_modifier: InputModifierType = None, 32 | ma_type: MAType = MAType.EMA, 33 | input_sampling: SamplingPeriodType = None): 34 | super().__init__(input_modifier=input_modifier, 35 | input_sampling=input_sampling) 36 | 37 | self.fast_period = fast_period 38 | self.slow_period = slow_period 39 | 40 | self.accu_dist = AccuDist() 41 | self.add_sub_indicator(self.accu_dist) 42 | 43 | self.ma_fast = MAFactory.get_ma(ma_type, fast_period, input_modifier=input_modifier) 44 | self.add_managed_sequence(self.ma_fast) 45 | 46 | self.ma_slow = MAFactory.get_ma(ma_type, slow_period, input_modifier=input_modifier) 47 | self.add_managed_sequence(self.ma_slow) 48 | 49 | self.initialize(input_values, input_indicator) 50 | 51 | def _calculate_new_value(self) -> Any: 52 | if not has_valid_values(self.accu_dist): 53 | return None 54 | 55 | self.ma_fast.add(self.accu_dist[-1]) 56 | self.ma_slow.add(self.accu_dist[-1]) 57 | 58 | if not has_valid_values(self.ma_fast) or not has_valid_values(self.ma_slow): 59 | return None 60 | 61 | return self.ma_fast[-1] - self.ma_slow[-1] 62 | -------------------------------------------------------------------------------- /talipp/indicators/ChandeKrollStop.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List, Any 3 | 4 | from talipp.indicator_util import has_valid_values 5 | from talipp.indicators import ATR 6 | from talipp.indicators.Indicator import Indicator, InputModifierType 7 | from talipp.input import SamplingPeriodType 8 | from talipp.ohlcv import OHLCV 9 | 10 | 11 | @dataclass 12 | class ChandeKrollStopVal: 13 | """`ChandeKrollStop` output type. 14 | 15 | Args: 16 | short_stop: Stop price for shorts. 17 | long_stop: Stop price for longs. 18 | """ 19 | 20 | short_stop: float = None 21 | long_stop: float = None 22 | 23 | 24 | class ChandeKrollStop(Indicator): 25 | """Chande Kroll Stop. 26 | 27 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 28 | 29 | Output type: [ChandeKrollStopVal][talipp.indicators.ChandeKrollStop.ChandeKrollStopVal] 30 | 31 | Args: 32 | atr_period: ATR period. 33 | atr_mult: ATR multiplier. 34 | input_values: List of input values. 35 | input_indicator: Input indicator. 36 | input_modifier: Input modifier. 37 | input_sampling: Input sampling type. 38 | """ 39 | 40 | def __init__(self, atr_period: int, 41 | atr_mult: float, 42 | period: int, 43 | input_values: List[OHLCV] = None, 44 | input_indicator: Indicator = None, 45 | input_modifier: InputModifierType = None, 46 | input_sampling: SamplingPeriodType = None): 47 | super().__init__(input_modifier=input_modifier, 48 | output_value_type=ChandeKrollStopVal, 49 | input_sampling=input_sampling) 50 | 51 | self.atr_period = atr_period 52 | self.atr_mult = atr_mult 53 | self.period = period 54 | 55 | self.atr = ATR(atr_period) 56 | self.add_sub_indicator(self.atr) 57 | 58 | self.high_stop_list = [] 59 | self.low_stop_list = [] 60 | self.add_managed_sequence(self.high_stop_list) 61 | self.add_managed_sequence(self.low_stop_list) 62 | 63 | self.initialize(input_values, input_indicator) 64 | 65 | def _calculate_new_value(self) -> Any: 66 | if not has_valid_values(self.input_values, self.atr_period): 67 | return None 68 | 69 | if not has_valid_values(self.atr, 1): 70 | return None 71 | 72 | self.high_stop_list.append(max(self.input_values[-self.atr_period:], key = lambda x: x.high).high - self.atr[-1] * self.atr_mult) 73 | self.low_stop_list.append(min(self.input_values[-self.atr_period:], key = lambda x: x.low).low + self.atr[-1] * self.atr_mult) 74 | 75 | if not has_valid_values(self.high_stop_list, self.period): 76 | return None 77 | 78 | return ChandeKrollStopVal(max(self.high_stop_list[-self.period:]), 79 | min(self.low_stop_list[-self.period:])) 80 | -------------------------------------------------------------------------------- /talipp/indicators/CoppockCurve.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.indicators.ROC import ROC 6 | from talipp.indicators.WMA import WMA 7 | from talipp.input import SamplingPeriodType 8 | 9 | 10 | class CoppockCurve(Indicator): 11 | """CoppockCurve. 12 | 13 | Input type: `float` 14 | 15 | Output type: `float` 16 | 17 | Args: 18 | fast_roc_period: Fast [ROC][talipp.indicators.ROC] period. 19 | slow_roc_period: Slow [ROC][talipp.indicators.ROC] period. 20 | wma_period: [WMA][talipp.indicators.WMA] period. 21 | input_values: List of input values. 22 | input_indicator: Input indicator. 23 | input_modifier: Input modifier. 24 | input_sampling: Input sampling type. 25 | """ 26 | 27 | def __init__(self, fast_roc_period: int, 28 | slow_roc_period: int, 29 | wma_period: int, 30 | input_values: List[float] = None, 31 | input_indicator: Indicator = None, 32 | input_modifier: InputModifierType = None, 33 | input_sampling: SamplingPeriodType = None): 34 | super().__init__(input_modifier=input_modifier, 35 | input_sampling=input_sampling) 36 | 37 | self.fast_roc = ROC(fast_roc_period) 38 | self.add_sub_indicator(self.fast_roc) 39 | 40 | self.slow_roc = ROC(slow_roc_period) 41 | self.add_sub_indicator(self.slow_roc) 42 | 43 | self.wma = WMA(wma_period) 44 | self.add_managed_sequence(self.wma) 45 | 46 | self.initialize(input_values, input_indicator) 47 | 48 | def _calculate_new_value(self) -> Any: 49 | if not has_valid_values(self.fast_roc, 1) or not has_valid_values(self.slow_roc, 1): 50 | return None 51 | 52 | self.wma.add(self.slow_roc[-1] + self.fast_roc[-1]) 53 | 54 | if not has_valid_values(self.wma, 1): 55 | return None 56 | 57 | return self.wma[-1] 58 | -------------------------------------------------------------------------------- /talipp/indicators/DEMA.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.EMA import EMA 5 | from talipp.indicators.Indicator import Indicator, InputModifierType 6 | from talipp.input import SamplingPeriodType 7 | 8 | 9 | class DEMA(Indicator): 10 | """Double Exponential Moving Average. 11 | 12 | Input type: `float` 13 | 14 | Output type: `float` 15 | 16 | Args: 17 | period: Period. 18 | input_values: List of input values. 19 | input_indicator: Input indicator. 20 | input_modifier: Input modifier. 21 | input_sampling: Input sampling type. 22 | """ 23 | 24 | def __init__(self, period: int, 25 | input_values: List[float] = None, 26 | input_indicator: Indicator = None, 27 | input_modifier: InputModifierType = None, 28 | input_sampling: SamplingPeriodType = None): 29 | super().__init__(input_modifier=input_modifier, 30 | input_sampling=input_sampling) 31 | 32 | self.period = period 33 | 34 | self.ema = EMA(period) 35 | self.add_sub_indicator(self.ema) 36 | 37 | self.ema_ema = EMA(period) 38 | self.add_managed_sequence(self.ema_ema) 39 | 40 | self.initialize(input_values, input_indicator) 41 | 42 | def _calculate_new_value(self) -> Any: 43 | if not has_valid_values(self.ema, 1): 44 | return None 45 | 46 | self.ema_ema.add(self.ema[-1]) 47 | 48 | if not has_valid_values(self.ema_ema, 1): 49 | return None 50 | 51 | return 2.0 * self.ema[-1] - self.ema_ema[-1] 52 | -------------------------------------------------------------------------------- /talipp/indicators/DPO.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | from talipp.ma import MAType, MAFactory 7 | 8 | 9 | class DPO(Indicator): 10 | """Detrended Price Oscillator. 11 | 12 | Input type: float 13 | 14 | Output type: `float` 15 | 16 | Args: 17 | period: Period. 18 | input_values: List of input values. 19 | input_indicator: Input indicator. 20 | input_modifier: Input modifier. 21 | ma_type: Moving average type. 22 | input_sampling: Input sampling type. 23 | """ 24 | 25 | def __init__(self, period: int, 26 | input_values: List[float] = None, 27 | input_indicator: Indicator = None, 28 | input_modifier: InputModifierType = None, 29 | ma_type: MAType = MAType.SMA, 30 | input_sampling: SamplingPeriodType = None): 31 | super().__init__(input_modifier=input_modifier, 32 | input_sampling=input_sampling) 33 | 34 | self.period = period 35 | 36 | self.ma = MAFactory.get_ma(ma_type, period) 37 | self.add_sub_indicator(self.ma) 38 | 39 | self.initialize(input_values, input_indicator) 40 | 41 | def _calculate_new_value(self) -> Any: 42 | if not has_valid_values(self.input_values, int(self.period / 2) + 2) or not has_valid_values(self.ma, 1): 43 | return None 44 | 45 | return self.input_values[-(int(self.period / 2) + 1) - 1] - float(self.ma[-1]) 46 | -------------------------------------------------------------------------------- /talipp/indicators/DonchianChannels.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List, Any 3 | 4 | from talipp.indicator_util import has_valid_values 5 | from talipp.indicators.Indicator import Indicator, InputModifierType 6 | from talipp.input import SamplingPeriodType 7 | from talipp.ohlcv import OHLCV 8 | 9 | 10 | @dataclass 11 | class DonchianChannelsVal: 12 | """`DonchianChannels` output type. 13 | 14 | Args: 15 | lb: Lower band. 16 | cb: Central band. 17 | ub: Upper band. 18 | """ 19 | 20 | lb: float = None 21 | cb: float = None 22 | ub: float = None 23 | 24 | 25 | class DonchianChannels(Indicator): 26 | """Donchian Channels. 27 | 28 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 29 | 30 | Output type: [DonchianChannelsVal][talipp.indicators.DonchianChannels.DonchianChannelsVal] 31 | 32 | Args: 33 | period: Period. 34 | input_values: List of input values. 35 | input_indicator: Input indicator. 36 | input_modifier: Input modifier. 37 | input_sampling: Input sampling type. 38 | """ 39 | def __init__(self, period: int, 40 | input_values: List[OHLCV] = None, 41 | input_indicator: Indicator = None, 42 | input_modifier: InputModifierType = None, 43 | input_sampling: SamplingPeriodType = None): 44 | super().__init__(input_modifier=input_modifier, 45 | output_value_type=DonchianChannelsVal, 46 | input_sampling=input_sampling) 47 | 48 | self.period = period 49 | 50 | self.initialize(input_values, input_indicator) 51 | 52 | def _calculate_new_value(self) -> Any: 53 | if not has_valid_values(self.input_values, self.period): 54 | return None 55 | 56 | max_high = max(self.input_values[-self.period:], key = lambda x: x.high).high 57 | min_low = min(self.input_values[-self.period:], key = lambda x: x.low).low 58 | 59 | return DonchianChannelsVal(min_low, 60 | (max_high + min_low) / 2.0, 61 | max_high) 62 | -------------------------------------------------------------------------------- /talipp/indicators/EMA.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | 7 | 8 | class EMA(Indicator): 9 | """Exponential Moving Average. 10 | 11 | Input type: `float` 12 | 13 | Output type: `float` 14 | 15 | Args: 16 | period: Period. 17 | input_values: List of input values. 18 | input_indicator: Input indicator. 19 | input_modifier: Input modifier. 20 | input_sampling: Input sampling type. 21 | """ 22 | 23 | def __init__(self, period: int, 24 | input_values: List[float] = None, 25 | input_indicator: Indicator = None, 26 | input_modifier: InputModifierType = None, 27 | input_sampling: SamplingPeriodType = None): 28 | super().__init__(input_modifier=input_modifier, 29 | input_sampling=input_sampling) 30 | 31 | self.period = period 32 | 33 | self.initialize(input_values, input_indicator) 34 | 35 | def _calculate_new_value(self) -> Any: 36 | if not has_valid_values(self.input_values, self.period): 37 | return None 38 | elif has_valid_values(self.input_values, self.period, exact=True): 39 | return sum(self.input_values[-self.period:]) / self.period 40 | else: 41 | mult = 2.0 / (self.period + 1.0) 42 | return float(mult * self.input_values[-1] + (1.0 - mult) * self.output_values[-1]) 43 | -------------------------------------------------------------------------------- /talipp/indicators/EMV.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | from talipp.ma import MAType, MAFactory 7 | from talipp.ohlcv import OHLCV 8 | 9 | 10 | class EMV(Indicator): 11 | """Ease of Movement. 12 | 13 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 14 | 15 | Output type: `float` 16 | 17 | Args: 18 | period: Period. 19 | volume_div: Volume divider. 20 | input_values: List of input values. 21 | input_indicator: Input indicator. 22 | input_modifier: Input modifier. 23 | input_sampling: Input sampling type. 24 | """ 25 | 26 | def __init__(self, period: int, 27 | volume_div: int, 28 | input_values: List[OHLCV] = None, 29 | input_indicator: Indicator = None, 30 | input_modifier: InputModifierType = None, 31 | ma_type: MAType = MAType.SMA, 32 | input_sampling: SamplingPeriodType = None): 33 | super().__init__(input_modifier=input_modifier, 34 | input_sampling=input_sampling) 35 | 36 | self.period = period 37 | self.volume_div = volume_div 38 | 39 | self.emv_sma = MAFactory.get_ma(ma_type, period) 40 | self.add_managed_sequence(self.emv_sma) 41 | 42 | self.initialize(input_values, input_indicator) 43 | 44 | def _calculate_new_value(self) -> Any: 45 | if not has_valid_values(self.input_values, 2): 46 | return None 47 | 48 | value = self.input_values[-1] 49 | value2 = self.input_values[-2] 50 | if value.high != value.low: 51 | distance = (value.high + value.low) / 2.0 - (value2.high + value2.low) / 2.0 52 | box_ratio = (value.volume / float(self.volume_div)) / (value.high - value.low) 53 | emv = distance / box_ratio 54 | else: 55 | emv = 0.0 56 | 57 | self.emv_sma.add(emv) 58 | 59 | if not has_valid_values(self.emv_sma, 1): 60 | return None 61 | else: 62 | return self.emv_sma[-1] 63 | -------------------------------------------------------------------------------- /talipp/indicators/FibonacciRetracement.py: -------------------------------------------------------------------------------- 1 | class FibonacciRetracement: 2 | """Fibonacci retracement levels""" 3 | 4 | R0_236 = 0.236 5 | """23.6% level""" 6 | R0_382 = 0.382 7 | """38.2% level""" 8 | R0_5 = 0.5 9 | """50.0% level""" 10 | R0_618 = 0.618 11 | """61.8% level""" 12 | R0_786 = 0.786 13 | """78.6% level""" 14 | R1 = 1.0 15 | """100.0% level""" 16 | R1_618 = 1.618 17 | """161.8% level""" 18 | R2_618 = 2.618 19 | """261.8% level""" 20 | R3_618 = 3.618 21 | """361.8% level""" 22 | 23 | @staticmethod 24 | def get_retracement_value(fibonacci_coefficient: float, value: float) -> float: 25 | """Calculate output value based on the provided input value and Fibonacci coefficient. 26 | 27 | Args: 28 | fibonacci_coefficient: Fibonacci coefficient. 29 | value: Input value. 30 | 31 | Returns: 32 | Value for given Fibonacci coefficient 33 | """ 34 | return value + value * fibonacci_coefficient 35 | -------------------------------------------------------------------------------- /talipp/indicators/ForceIndex.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | from talipp.ma import MAFactory, MAType 7 | from talipp.ohlcv import OHLCV 8 | 9 | 10 | class ForceIndex(Indicator): 11 | """Force Index. 12 | 13 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 14 | 15 | Output type: `float` 16 | 17 | Args: 18 | period: Period. 19 | input_values: List of input values. 20 | input_indicator: Input indicator. 21 | input_modifier: Input modifier. 22 | ma_type: Moving average type. 23 | input_sampling: Input sampling type. 24 | """ 25 | 26 | def __init__(self, period: int, 27 | input_values: List[OHLCV] = None, 28 | input_indicator: Indicator = None, 29 | input_modifier: InputModifierType = None, 30 | ma_type: MAType = MAType.EMA, 31 | input_sampling: SamplingPeriodType = None): 32 | super().__init__(input_modifier=input_modifier, 33 | input_sampling=input_sampling) 34 | 35 | self.ma = MAFactory.get_ma(ma_type, period) 36 | self.add_managed_sequence(self.ma) 37 | 38 | self.initialize(input_values, input_indicator) 39 | 40 | def _calculate_new_value(self) -> Any: 41 | if not has_valid_values(self.input_values, 2): 42 | return None 43 | 44 | self.ma.add((self.input_values[-1].close - self.input_values[-2].close) * self.input_values[-1].volume) 45 | 46 | if not has_valid_values(self.ma, 1): 47 | return None 48 | 49 | return self.ma[-1] 50 | -------------------------------------------------------------------------------- /talipp/indicators/HMA.py: -------------------------------------------------------------------------------- 1 | from math import sqrt 2 | from typing import List, Any 3 | 4 | from talipp.indicator_util import has_valid_values 5 | from talipp.indicators.Indicator import Indicator, InputModifierType 6 | from talipp.indicators.WMA import WMA 7 | from talipp.input import SamplingPeriodType 8 | 9 | 10 | class HMA(Indicator): 11 | """Hull Moving Average. 12 | 13 | Input type: `float` 14 | 15 | Output type: `float` 16 | 17 | Args: 18 | period: Period. 19 | input_values: List of input values. 20 | input_indicator: Input indicator. 21 | input_modifier: Input modifier. 22 | input_sampling: Input sampling type. 23 | """ 24 | 25 | def __init__(self, period: int, 26 | input_values: List[float] = None, 27 | input_indicator: Indicator = None, 28 | input_modifier: InputModifierType = None, 29 | input_sampling: SamplingPeriodType = None): 30 | super().__init__(input_modifier=input_modifier, 31 | input_sampling=input_sampling) 32 | 33 | self.period = period 34 | 35 | self.wma = WMA(period) 36 | self.wma2 = WMA(int(period / 2)) 37 | self.hma = WMA(int(sqrt(period))) 38 | 39 | self.add_sub_indicator(self.wma) 40 | self.add_sub_indicator(self.wma2) 41 | self.add_managed_sequence(self.hma) 42 | 43 | self.initialize(input_values, input_indicator) 44 | 45 | def _calculate_new_value(self) -> Any: 46 | if not has_valid_values(self.wma, int(sqrt(self.period))): 47 | return None 48 | 49 | self.hma.add(2.0 * self.wma2[-1] - self.wma[-1]) 50 | 51 | if not has_valid_values(self.hma, 1): 52 | return None 53 | 54 | return self.hma[-1] 55 | -------------------------------------------------------------------------------- /talipp/indicators/IBS.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | from talipp.ohlcv import OHLCV 7 | 8 | 9 | class IBS(Indicator): 10 | """Internal Bar Strength. 11 | 12 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 13 | 14 | Output type: `float` 15 | 16 | Args: 17 | input_values: List of input values. 18 | input_indicator: Input indicator. 19 | input_modifier: Input modifier. 20 | input_sampling: Input sampling type. 21 | """ 22 | 23 | def __init__(self, 24 | input_values: List[OHLCV] = None, 25 | input_indicator: Indicator = None, 26 | input_modifier: InputModifierType = None, 27 | input_sampling: SamplingPeriodType = None): 28 | super().__init__(input_modifier=input_modifier, 29 | input_sampling=input_sampling) 30 | 31 | self.initialize(input_values, input_indicator) 32 | 33 | def _calculate_new_value(self) -> Any: 34 | if not has_valid_values(self.input_values): 35 | return None 36 | 37 | candle: OHLCV = self.input_values[-1] 38 | return None if candle.high == candle.low else (candle.close - candle.low) / (candle.high - candle.low) 39 | -------------------------------------------------------------------------------- /talipp/indicators/KAMA.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | 7 | 8 | class KAMA(Indicator): 9 | """Kaufman's Adaptive Moving Average. 10 | 11 | Input type: `float` 12 | 13 | Output type: `float` 14 | 15 | Args: 16 | period: Volatility period. 17 | fast_ema_constant_period: Fast [EMA][talipp.indicators.EMA] smoothing factor. 18 | slow_ema_constant_period: Slow [EMA][talipp.indicators.EMA] smoothing factor. 19 | input_values: List of input values. 20 | input_indicator: Input indicator. 21 | input_modifier: Input modifier. 22 | input_sampling: Input sampling type. 23 | """ 24 | 25 | def __init__(self, period: int, 26 | fast_ema_constant_period: int, 27 | slow_ema_constant_period: int, 28 | input_values: List[float] = None, 29 | input_indicator: Indicator = None, 30 | input_modifier: InputModifierType = None, 31 | input_sampling: SamplingPeriodType = None): 32 | super().__init__(input_modifier=input_modifier, 33 | input_sampling=input_sampling) 34 | 35 | self.period = period 36 | 37 | self.fast_smoothing_constant = 2.0 / (fast_ema_constant_period + 1) 38 | self.slow_smoothing_constant = 2.0 / (slow_ema_constant_period + 1) 39 | 40 | self.volatility = [] 41 | self.add_managed_sequence(self.volatility) 42 | 43 | self.initialize(input_values, input_indicator) 44 | 45 | def _calculate_new_value(self) -> Any: 46 | if not has_valid_values(self.input_values, 2): 47 | return None 48 | 49 | self.volatility.append(abs(self.input_values[-1] - self.input_values[-2])) 50 | 51 | if not has_valid_values(self.volatility, self.period): 52 | return None 53 | 54 | volatility = sum(self.volatility[-self.period:]) 55 | change = abs(self.input_values[-1] - self.input_values[-self.period - 1]) 56 | 57 | if volatility != 0: 58 | efficiency_ratio = float(change) / volatility 59 | else: 60 | efficiency_ratio = 0 61 | 62 | smoothing_constant = (efficiency_ratio * (self.fast_smoothing_constant - self.slow_smoothing_constant) + self.slow_smoothing_constant)**2 63 | 64 | if not has_valid_values(self.output_values, 1): 65 | prev_kama = self.input_values[-2] 66 | else: 67 | prev_kama = self.output_values[-1] 68 | 69 | return prev_kama + smoothing_constant * (self.input_values[-1] - prev_kama) 70 | -------------------------------------------------------------------------------- /talipp/indicators/KVO.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | from talipp.ma import MAType, MAFactory 7 | from talipp.ohlcv import OHLCV 8 | 9 | 10 | class KVO(Indicator): 11 | """Klinger Volume Oscillator. 12 | 13 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 14 | 15 | Output type: `float` 16 | 17 | Args: 18 | fast_period: Fast moving average period. 19 | slow_period: Slow moving average period. 20 | input_values: List of input values. 21 | input_indicator: Input indicator. 22 | input_modifier: Input modifier. 23 | ma_type: Moving average type. 24 | input_sampling: Input sampling type. 25 | """ 26 | 27 | def __init__(self, fast_period: int, 28 | slow_period: int, 29 | input_values: List[OHLCV] = None, 30 | input_indicator: Indicator = None, 31 | input_modifier: InputModifierType = None, 32 | ma_type: MAType = MAType.EMA, 33 | input_sampling: SamplingPeriodType = None): 34 | super().__init__(input_modifier=input_modifier, 35 | input_sampling=input_sampling) 36 | 37 | self.fast_ma = MAFactory.get_ma(ma_type, fast_period) 38 | self.add_managed_sequence(self.fast_ma) 39 | 40 | self.slow_ma = MAFactory.get_ma(ma_type, slow_period) 41 | self.add_managed_sequence(self.slow_ma) 42 | 43 | self.trend = [] 44 | self.add_managed_sequence(self.trend) 45 | 46 | self.cumulative_measurement = [] 47 | self.add_managed_sequence(self.cumulative_measurement) 48 | 49 | self.initialize(input_values, input_indicator) 50 | 51 | def _calculate_new_value(self) -> Any: 52 | if not has_valid_values(self.input_values, 2): 53 | return None 54 | 55 | value = self.input_values[-1] 56 | value2 = self.input_values[-2] 57 | 58 | if not has_valid_values(self.trend, 1): 59 | self.trend.append(0.0) 60 | else: 61 | if (value.high + value.low + value.close) > (value2.high + value2.low + value2.close): 62 | self.trend.append(1.0) 63 | else: 64 | self.trend.append(-1.0) 65 | 66 | if not has_valid_values(self.trend, 2): 67 | return None 68 | 69 | dm = value.high - value.low 70 | dm2 = value2.high - value2.low 71 | 72 | if not has_valid_values(self.cumulative_measurement, 1): 73 | prev_cm = dm 74 | else: 75 | prev_cm = self.cumulative_measurement[-1] 76 | 77 | if self.trend[-1] == self.trend[-2]: 78 | self.cumulative_measurement.append(prev_cm + dm) 79 | else: 80 | self.cumulative_measurement.append(dm2 + dm) 81 | 82 | if self.cumulative_measurement[-1] == 0: 83 | volume_force = 0.0 84 | else: 85 | volume_force = value.volume * abs(2 * (dm / self.cumulative_measurement[-1] - 1)) * self.trend[-1] * 100 86 | 87 | self.fast_ma.add(volume_force) 88 | self.slow_ma.add(volume_force) 89 | 90 | if not has_valid_values(self.fast_ma, 1) or not has_valid_values(self.slow_ma, 1): 91 | return None 92 | 93 | return self.fast_ma[-1] - self.slow_ma[-1] 94 | -------------------------------------------------------------------------------- /talipp/indicators/KeltnerChannels.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List, Any 3 | 4 | from talipp.indicator_util import has_valid_values 5 | from talipp.indicators.ATR import ATR 6 | from talipp.indicators.Indicator import Indicator, InputModifierType 7 | from talipp.input import SamplingPeriodType 8 | from talipp.ma import MAType, MAFactory 9 | from talipp.ohlcv import OHLCV, ValueExtractor 10 | 11 | 12 | @dataclass 13 | class KeltnerChannelsVal: 14 | """`KeltnerChannels` output type. 15 | 16 | Args: 17 | lb: Lower band. 18 | cb: Central band. 19 | ub: Upper band. 20 | """ 21 | 22 | lb: float = None 23 | cb: float = None 24 | ub: float = None 25 | 26 | 27 | class KeltnerChannels(Indicator): 28 | """Keltner Channels. 29 | 30 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 31 | 32 | Output type: [KeltnerChannelsVal][talipp.indicators.KeltnerChannels.KeltnerChannelsVal] 33 | 34 | Args: 35 | ma_period: Moving average period. 36 | atr_period: [ATR][talipp.indicators.ATR] period. 37 | atr_mult_up: Upper band multiplier. 38 | atr_mult_down: Lower band multiplier. 39 | input_values: List of input values. 40 | input_indicator: Input indicator. 41 | input_modifier: Input modifier. 42 | ma_type: Moving average type. 43 | input_sampling: Input sampling type. 44 | """ 45 | 46 | def __init__(self, ma_period: int, 47 | atr_period: int, 48 | atr_mult_up: float, 49 | atr_mult_down: float, 50 | input_values: List[OHLCV] = None, 51 | input_indicator: Indicator = None, 52 | input_modifier: InputModifierType = None, 53 | ma_type: MAType = MAType.EMA, 54 | input_sampling: SamplingPeriodType = None): 55 | super().__init__(input_modifier=input_modifier, 56 | output_value_type=KeltnerChannelsVal, 57 | input_sampling=input_sampling) 58 | 59 | self.atr_mult_up = atr_mult_up 60 | self.atr_mult_down = atr_mult_down 61 | 62 | self.atr = ATR(atr_period) 63 | self.cb = MAFactory.get_ma(ma_type, ma_period, input_modifier=ValueExtractor.extract_close) 64 | 65 | self.add_sub_indicator(self.cb) 66 | self.add_sub_indicator(self.atr) 67 | 68 | self.initialize(input_values, input_indicator) 69 | 70 | def _calculate_new_value(self) -> Any: 71 | if not has_valid_values(self.cb, 1) or not has_valid_values(self.atr, 1): 72 | return None 73 | 74 | return KeltnerChannelsVal(self.cb[-1] - self.atr_mult_down * self.atr[-1], 75 | self.cb[-1], 76 | self.cb[-1] + self.atr_mult_up * self.atr[-1]) 77 | -------------------------------------------------------------------------------- /talipp/indicators/MACD.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List, Any 3 | 4 | from talipp.indicator_util import has_valid_values 5 | from talipp.indicators.Indicator import Indicator, InputModifierType 6 | from talipp.input import SamplingPeriodType 7 | from talipp.ma import MAType, MAFactory 8 | 9 | 10 | @dataclass 11 | class MACDVal: 12 | """`MACD` output type. 13 | 14 | Args: 15 | macd: `MACD` value. 16 | signal: Signal line. 17 | histogram: Histogram. 18 | """ 19 | 20 | macd: float = None 21 | signal: float = None 22 | histogram: float = None 23 | 24 | 25 | class MACD(Indicator): 26 | """Moving Average Convergence Divergence. 27 | 28 | Input type: `float` 29 | 30 | Output type: [MACDVal][talipp.indicators.MACD.MACDVal] 31 | 32 | Args: 33 | fast_period: Fast moving average period. 34 | slow_period: Slow moving average period. 35 | signal_period: Signal line moving average period. 36 | input_values: List of input values. 37 | input_indicator: Input indicator. 38 | input_modifier: Input modifier. 39 | ma_type: Moving average type. 40 | input_sampling: Input sampling type. 41 | """ 42 | 43 | def __init__(self, fast_period: int, 44 | slow_period: int, 45 | signal_period: int, 46 | input_values: List[float] = None, 47 | input_indicator: Indicator = None, 48 | input_modifier: InputModifierType = None, 49 | ma_type: MAType = MAType.EMA, 50 | input_sampling: SamplingPeriodType = None): 51 | super().__init__(input_modifier=input_modifier, 52 | output_value_type=MACDVal, 53 | input_sampling=input_sampling) 54 | 55 | self.ma_fast = MAFactory.get_ma(ma_type, fast_period) 56 | self.ma_slow = MAFactory.get_ma(ma_type, slow_period) 57 | self.signal_line = MAFactory.get_ma(ma_type, signal_period) 58 | 59 | self.add_sub_indicator(self.ma_fast) 60 | self.add_sub_indicator(self.ma_slow) 61 | self.add_managed_sequence(self.signal_line) 62 | 63 | self.initialize(input_values, input_indicator) 64 | 65 | def _calculate_new_value(self) -> Any: 66 | if not has_valid_values(self.ma_fast, 1) or not has_valid_values(self.ma_slow, 1): 67 | return None 68 | 69 | macd = self.ma_fast[-1] - self.ma_slow[-1] 70 | self.signal_line.add(macd) 71 | 72 | if has_valid_values(self.signal_line, 1): 73 | signal = self.signal_line[-1] 74 | else: 75 | signal = None 76 | 77 | histogram = None 78 | if macd is not None and signal is not None: 79 | histogram = macd - signal 80 | 81 | return MACDVal(macd, signal, histogram) 82 | -------------------------------------------------------------------------------- /talipp/indicators/MassIndex.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | from talipp.ma import MAType, MAFactory 7 | from talipp.ohlcv import OHLCV 8 | 9 | 10 | class MassIndex(Indicator): 11 | """Mass Index. 12 | 13 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 14 | 15 | Output type: `float` 16 | 17 | Args: 18 | ma_period: Moving average period. 19 | ma_ma_period: Moving average period of moving average. 20 | ma_ratio_period: Moving averages ration period. 21 | input_values: List of input values. 22 | input_indicator: Input indicator. 23 | input_modifier: Input modifier. 24 | ma_type: Moving average type. 25 | input_sampling: Input sampling type. 26 | """ 27 | 28 | def __init__(self, ma_period: int, 29 | ma_ma_period: int, 30 | ma_ratio_period: int, 31 | input_values: List[OHLCV] = None, 32 | input_indicator: Indicator = None, 33 | input_modifier: InputModifierType = None, 34 | ma_type: MAType = MAType.EMA, 35 | input_sampling: SamplingPeriodType = None): 36 | super().__init__(input_modifier=input_modifier, 37 | input_sampling=input_sampling) 38 | 39 | self.ma_ratio_period = ma_ratio_period 40 | 41 | self.ma = MAFactory.get_ma(ma_type, ma_period) 42 | self.ma_ma = MAFactory.get_ma(ma_type, ma_ma_period) 43 | self.ma_ratio = [] 44 | 45 | self.add_managed_sequence(self.ma) 46 | self.add_managed_sequence(self.ma_ma) 47 | self.add_managed_sequence(self.ma_ratio) 48 | 49 | self.initialize(input_values, input_indicator) 50 | 51 | def _calculate_new_value(self) -> Any: 52 | value = self.input_values[-1] 53 | self.ma.add(value.high - value.low) 54 | 55 | if not has_valid_values(self.ma, 1): 56 | return None 57 | 58 | self.ma_ma.add(self.ma[-1]) 59 | 60 | if not has_valid_values(self.ma_ma, 1): 61 | return None 62 | 63 | self.ma_ratio.append(self.ma[-1] / float(self.ma_ma[-1])) 64 | 65 | if not has_valid_values(self.ma_ratio, self.ma_ratio_period): 66 | return None 67 | 68 | return sum(self.ma_ratio[-self.ma_ratio_period:]) 69 | -------------------------------------------------------------------------------- /talipp/indicators/McGinleyDynamic.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | 7 | 8 | class McGinleyDynamic(Indicator): 9 | """McGinley Dynamic. 10 | 11 | Input type: `float` 12 | 13 | Output type: `float` 14 | 15 | Args: 16 | period: Period. 17 | input_values: List of input values. 18 | input_indicator: Input indicator. 19 | input_modifier: Input modifier. 20 | input_sampling: Input sampling type. 21 | """ 22 | 23 | def __init__(self, period: int, 24 | input_values: List[float] = None, 25 | input_indicator: Indicator = None, 26 | input_modifier: InputModifierType = None, 27 | input_sampling: SamplingPeriodType = None): 28 | super().__init__(input_modifier=input_modifier, 29 | input_sampling=input_sampling) 30 | 31 | self.period = period 32 | 33 | self.initialize(input_values, input_indicator) 34 | 35 | def _calculate_new_value(self) -> Any: 36 | if not has_valid_values(self.input_values, self.period): 37 | return None 38 | elif has_valid_values(self.input_values, self.period, exact=True): 39 | return sum(self.input_values) / float(self.period) 40 | else: 41 | return self.output_values[-1] + (self.input_values[-1] - self.output_values[-1]) / float(self.period * pow(self.input_values[-1] / float(self.output_values[-1]), 4)) 42 | -------------------------------------------------------------------------------- /talipp/indicators/MeanDev.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | from talipp.ma import MAType, MAFactory 7 | 8 | 9 | class MeanDev(Indicator): 10 | """Mean Deviation. 11 | 12 | Input type: `float` 13 | 14 | Output type: `float` 15 | 16 | Args: 17 | period: Moving average period. 18 | input_values: List of input values. 19 | input_indicator: Input indicator. 20 | input_modifier: Input modifier. 21 | ma_type: Moving average type. 22 | input_sampling: Input sampling type. 23 | """ 24 | 25 | def __init__(self, period: int, 26 | input_values: List[float] = None, 27 | input_indicator: Indicator = None, 28 | input_modifier: InputModifierType = None, 29 | ma_type: MAType = MAType.SMA, 30 | input_sampling: SamplingPeriodType = None): 31 | super().__init__(input_modifier=input_modifier, 32 | input_sampling=input_sampling) 33 | 34 | self.period = period 35 | 36 | self.ma = MAFactory.get_ma(ma_type, period) 37 | self.add_sub_indicator(self.ma) 38 | 39 | self.initialize(input_values, input_indicator) 40 | 41 | def _calculate_new_value(self) -> Any: 42 | if not has_valid_values(self.ma, 1): 43 | return None 44 | 45 | return sum(map(lambda x: abs(x - self.ma[-1]), self.input_values[-self.period:])) / float(self.period) 46 | -------------------------------------------------------------------------------- /talipp/indicators/NATR.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators import ATR 5 | from talipp.indicators.Indicator import Indicator, InputModifierType 6 | from talipp.input import SamplingPeriodType 7 | from talipp.ohlcv import OHLCV 8 | 9 | 10 | class NATR(Indicator): 11 | """Normalized Average True Range 12 | 13 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 14 | 15 | Output type: `float` 16 | 17 | Args: 18 | period: Period. 19 | input_values: List of input values. 20 | input_indicator: Input indicator. 21 | input_modifier: Input modifier. 22 | input_sampling: Input sampling type. 23 | """ 24 | 25 | def __init__(self, period: int, 26 | input_values: List[OHLCV] = None, 27 | input_indicator: Indicator = None, 28 | input_modifier: InputModifierType = None, 29 | input_sampling: SamplingPeriodType = None): 30 | super(NATR, self).__init__(input_modifier=input_modifier, 31 | input_sampling=input_sampling) 32 | 33 | self.period = period 34 | self.atr = ATR(period) 35 | 36 | self.add_sub_indicator(self.atr) 37 | 38 | self.initialize(input_values, input_indicator) 39 | 40 | def _calculate_new_value(self) -> Any: 41 | if not has_valid_values(self.atr, 1): 42 | return None 43 | 44 | if self.input_values[-1].close == 0: 45 | return None 46 | 47 | return 100.0 * self.atr[-1] / self.input_values[-1].close 48 | -------------------------------------------------------------------------------- /talipp/indicators/OBV.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | from talipp.ohlcv import OHLCV 7 | 8 | 9 | class OBV(Indicator): 10 | """On Balance Volume. 11 | 12 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 13 | 14 | Output type: `float` 15 | 16 | Args: 17 | input_values: List of input values. 18 | input_indicator: Input indicator. 19 | input_modifier: Input modifier. 20 | input_sampling: Input sampling type. 21 | """ 22 | 23 | def __init__(self, input_values: List[OHLCV] = None, 24 | input_indicator: Indicator = None, 25 | input_modifier: InputModifierType = None, 26 | input_sampling: SamplingPeriodType = None): 27 | super().__init__(input_modifier=input_modifier, 28 | input_sampling=input_sampling) 29 | 30 | self.initialize(input_values, input_indicator) 31 | 32 | def _calculate_new_value(self) -> Any: 33 | if not has_valid_values(self.input_values, 1): 34 | return None 35 | elif has_valid_values(self.input_values, 1, exact=True): 36 | return self.input_values[0].volume 37 | else: 38 | value = self.input_values[-1] 39 | prev_value = self.input_values[-2] 40 | 41 | if value.close == prev_value.close: 42 | return self.output_values[-1] 43 | elif value.close > prev_value.close: 44 | return self.output_values[-1] + value.volume 45 | else: 46 | return self.output_values[-1] - value.volume 47 | -------------------------------------------------------------------------------- /talipp/indicators/ROC.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | 7 | 8 | class ROC(Indicator): 9 | """Rate Of Change. 10 | 11 | Input type: `float` 12 | 13 | Output type: `float` 14 | 15 | Args: 16 | period: Look-back period. 17 | input_values: List of input values. 18 | input_indicator: Input indicator. 19 | input_modifier: Input modifier. 20 | input_sampling: Input sampling type. 21 | """ 22 | 23 | def __init__(self, period: int, 24 | input_values: List[float] = None, 25 | input_indicator: Indicator = None, 26 | input_modifier: InputModifierType = None, 27 | input_sampling: SamplingPeriodType = None): 28 | super().__init__(input_modifier=input_modifier, 29 | input_sampling=input_sampling) 30 | 31 | self.period = period 32 | 33 | self.initialize(input_values, input_indicator) 34 | 35 | def _calculate_new_value(self) -> Any: 36 | if not has_valid_values(self.input_values, self.period+1): 37 | return None 38 | else: 39 | return 100.0 * (self.input_values[-1] - self.input_values[-self.period - 1]) / self.input_values[-self.period - 1] 40 | -------------------------------------------------------------------------------- /talipp/indicators/RSI.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | 7 | 8 | class RSI(Indicator): 9 | """Relative Strength Index. 10 | 11 | Input type: `float` 12 | 13 | Output type: `float` 14 | 15 | Args: 16 | period: Period. 17 | input_values: List of input values. 18 | input_indicator: Input indicator. 19 | input_modifier: Input modifier. 20 | input_sampling: Input sampling type. 21 | """ 22 | def __init__(self, period: int, 23 | input_values: List[float] = None, 24 | input_indicator: Indicator = None, 25 | input_modifier: InputModifierType = None, 26 | input_sampling: SamplingPeriodType = None): 27 | super().__init__(input_modifier=input_modifier, 28 | input_sampling=input_sampling) 29 | 30 | self.period = period 31 | 32 | self.avg_gain = [] 33 | self.avg_loss = [] 34 | 35 | self.add_managed_sequence(self.avg_gain) 36 | self.add_managed_sequence(self.avg_loss) 37 | 38 | self.initialize(input_values, input_indicator) 39 | 40 | def _calculate_new_value(self) -> Any: 41 | if not has_valid_values(self.input_values, self.period+1): 42 | return None 43 | elif has_valid_values(self.input_values, self.period+1, exact=True): 44 | # calculate initial changes in price 45 | init_changes = [self.input_values[i] - self.input_values[i - 1] for i in range(1, self.period)] 46 | 47 | # initialize average gain and loss 48 | self.avg_gain.append(float(sum(init_changes[i] for i in range(len(init_changes)) if init_changes[i] > 0)) / (self.period - 1)) 49 | self.avg_loss.append(float(sum(-1 * init_changes[i] for i in range(len(init_changes)) if init_changes[i] < 0)) / (self.period - 1)) 50 | 51 | change = self.input_values[-1] - self.input_values[-2] 52 | 53 | gain = change if change > 0 else 0.0 54 | loss = -1 * change if change < 0 else 0.0 55 | 56 | self.avg_gain.append(float(self.avg_gain[-1] * (self.period - 1) + gain) / self.period) 57 | self.avg_loss.append(float(self.avg_loss[-1] * (self.period - 1) + loss) / self.period) 58 | 59 | if self.avg_loss[-1] == 0: 60 | rsi = 100.0 61 | else: 62 | rs = self.avg_gain[-1] / self.avg_loss[-1] 63 | rsi = 100.0 - (100.0 / (1.0 + rs)) 64 | 65 | return rsi 66 | -------------------------------------------------------------------------------- /talipp/indicators/RogersSatchell.py: -------------------------------------------------------------------------------- 1 | from math import sqrt, log 2 | from typing import List, Any 3 | 4 | from talipp.indicator_util import has_valid_values 5 | from talipp.indicators.Indicator import Indicator, InputModifierType 6 | from talipp.input import SamplingPeriodType 7 | from talipp.ohlcv import OHLCV 8 | 9 | 10 | class RogersSatchell(Indicator): 11 | """Rogers-Satchell volatility indicator. 12 | 13 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 14 | 15 | Output type: `float` 16 | 17 | Args: 18 | period: Period. 19 | input_values: List of input values. 20 | input_indicator: Input indicator. 21 | input_modifier: Input modifier. 22 | input_sampling: Input sampling type. 23 | """ 24 | 25 | def __init__(self, period: int, 26 | input_values: List[OHLCV] = None, 27 | input_indicator: Indicator = None, 28 | input_modifier: InputModifierType = None, 29 | input_sampling: SamplingPeriodType = None): 30 | super().__init__(input_modifier=input_modifier, 31 | input_sampling=input_sampling) 32 | 33 | self.period = period 34 | 35 | self.initialize(input_values, input_indicator) 36 | 37 | def _calculate_new_value(self) -> Any: 38 | if not has_valid_values(self.input_values, self.period): 39 | return None 40 | 41 | s = 0.0 42 | for ohlcv in self.input_values[-self.period:]: 43 | s += log(float(ohlcv.high) / ohlcv.close) * log(float(ohlcv.high) / ohlcv.open) + log(float(ohlcv.low) / ohlcv.close) * log(float(ohlcv.low) / ohlcv.open) 44 | 45 | return sqrt(s / self.period) if s > 0 else None 46 | -------------------------------------------------------------------------------- /talipp/indicators/SFX.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List, Any 3 | 4 | from talipp.indicator_util import has_valid_values 5 | from talipp.indicators.ATR import ATR 6 | from talipp.indicators.Indicator import Indicator, InputModifierType 7 | from talipp.indicators.StdDev import StdDev 8 | from talipp.input import SamplingPeriodType 9 | from talipp.ma import MAType, MAFactory 10 | from talipp.ohlcv import OHLCV, ValueExtractor 11 | 12 | 13 | @dataclass 14 | class SFXVal: 15 | """`SFX` output type. 16 | 17 | Args: 18 | atr: `ATR` value. 19 | std_dev: Standard deviation. 20 | ma_std_dev: Standard deviation moving average. 21 | """ 22 | 23 | atr: float = None 24 | std_dev: float = None 25 | ma_std_dev: float = None 26 | 27 | 28 | class SFX(Indicator): 29 | """SFX. 30 | 31 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 32 | 33 | Output type: [SFXVal][talipp.indicators.SFX.SFXVal] 34 | 35 | Args: 36 | atr_period: [ATR][talipp.indicators.ATR] period. 37 | std_dev_period: [Standard deviation][talipp.indicators.StdDev] period. 38 | std_dev_period: Standard deviation moving average period. 39 | input_values: List of input values. 40 | input_indicator: Input indicator. 41 | input_modifier: Input modifier. 42 | ma_type: Moving average type. 43 | input_sampling: Input sampling type. 44 | """ 45 | 46 | def __init__(self, atr_period: int, 47 | std_dev_period: int, 48 | std_dev_smoothing_period: int, 49 | input_values: List[OHLCV] = None, 50 | input_indicator: Indicator = None, 51 | input_modifier: InputModifierType = None, 52 | ma_type: MAType = MAType.SMA, 53 | input_sampling: SamplingPeriodType = None): 54 | super().__init__(input_modifier=input_modifier, 55 | output_value_type=SFXVal, 56 | input_sampling=input_sampling) 57 | 58 | self.atr = ATR(atr_period) 59 | self.std_dev = StdDev(std_dev_period, input_modifier=ValueExtractor.extract_close) 60 | self.ma_std_dev = MAFactory.get_ma(ma_type, std_dev_smoothing_period, input_indicator=self.std_dev) 61 | 62 | self.add_sub_indicator(self.atr) 63 | self.add_sub_indicator(self.std_dev) 64 | 65 | self.initialize(input_values, input_indicator) 66 | 67 | def _calculate_new_value(self) -> Any: 68 | if has_valid_values(self.atr, 1): 69 | atr = self.atr[-1] 70 | else: 71 | atr = None 72 | 73 | if has_valid_values(self.std_dev, 1): 74 | std_dev = self.std_dev[-1] 75 | else: 76 | std_dev = None 77 | 78 | if has_valid_values(self.ma_std_dev, 1): 79 | ma_std_dev = self.ma_std_dev[-1] 80 | else: 81 | ma_std_dev = None 82 | 83 | return SFXVal(atr, std_dev, ma_std_dev) 84 | -------------------------------------------------------------------------------- /talipp/indicators/SMA.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | 7 | 8 | class SMA(Indicator): 9 | """Simple Moving Average. 10 | 11 | Input type: `float` 12 | 13 | Output type: `float` 14 | 15 | Args: 16 | period: Period. 17 | input_values: List of input values. 18 | input_indicator: Input indicator. 19 | input_modifier: Input modifier. 20 | input_sampling: Input sampling type. 21 | """ 22 | 23 | def __init__(self, period: int, 24 | input_values: List[float] = None, 25 | input_indicator: Indicator = None, 26 | input_modifier: InputModifierType = None, 27 | input_sampling: SamplingPeriodType = None): 28 | super().__init__(input_modifier=input_modifier, 29 | input_sampling=input_sampling) 30 | 31 | self.period = period 32 | 33 | self.initialize(input_values, input_indicator) 34 | 35 | def _calculate_new_value(self) -> Any: 36 | if has_valid_values(self.input_values, self.period + 1): 37 | return self.output_values[-1] - \ 38 | (self.input_values[-self.period - 1] - self.input_values[-1]) / float(self.period) 39 | elif has_valid_values(self.input_values, self.period, exact=True): 40 | return float(sum(self.input_values[-self.period:])) / self.period 41 | else: # len(self.input_values) < self.period 42 | return None 43 | -------------------------------------------------------------------------------- /talipp/indicators/SMMA.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | 7 | 8 | class SMMA(Indicator): 9 | """Smoothed Moving Average 10 | 11 | Input type: `float` 12 | 13 | Output type: `float` 14 | 15 | Args: 16 | period: Period. 17 | input_values: List of input values. 18 | input_indicator: Input indicator. 19 | input_modifier: Input modifier. 20 | input_sampling: Input sampling type. 21 | """ 22 | def __init__(self, period: int, 23 | input_values: List[float] = None, 24 | input_indicator: Indicator = None, 25 | input_modifier: InputModifierType = None, 26 | input_sampling: SamplingPeriodType = None): 27 | super().__init__(input_modifier=input_modifier, 28 | input_sampling=input_sampling) 29 | 30 | self.period = period 31 | 32 | self.initialize(input_values, input_indicator) 33 | 34 | def _calculate_new_value(self) -> Any: 35 | if not has_valid_values(self.input_values, self.period): 36 | return None 37 | elif has_valid_values(self.input_values, self.period, exact=True): 38 | return float(sum(self.input_values)) / self.period 39 | else: 40 | return (self.output_values[-1] * (self.period - 1) + self.input_values[-1]) / self.period 41 | -------------------------------------------------------------------------------- /talipp/indicators/SOBV.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.indicators.OBV import OBV 6 | from talipp.input import SamplingPeriodType 7 | from talipp.ohlcv import OHLCV 8 | 9 | 10 | class SOBV(Indicator): 11 | """Smoothed On Balance Volume. 12 | 13 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 14 | 15 | Output type: `float` 16 | 17 | Args: 18 | period: Moving average period. 19 | input_values: List of input values. 20 | input_indicator: Input indicator. 21 | input_modifier: Input modifier. 22 | input_sampling: Input sampling type. 23 | """ 24 | 25 | def __init__(self, period: int, 26 | input_values: List[OHLCV] = None, 27 | input_indicator: Indicator = None, 28 | input_modifier: InputModifierType = None, 29 | input_sampling: SamplingPeriodType = None): 30 | super().__init__(input_modifier=input_modifier, 31 | input_sampling=input_sampling) 32 | 33 | self.period = period 34 | 35 | self.obv = OBV() 36 | self.add_sub_indicator(self.obv) 37 | 38 | self.initialize(input_values, input_indicator) 39 | 40 | def _calculate_new_value(self) -> Any: 41 | if not has_valid_values(self.obv, self.period): 42 | return None 43 | 44 | return sum(self.obv[-self.period:]) / float(self.period) 45 | -------------------------------------------------------------------------------- /talipp/indicators/STC.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.indicators.MACD import MACD, MACDVal 6 | from talipp.indicators.Stoch import Stoch, StochVal 7 | from talipp.input import SamplingPeriodType 8 | from talipp.ma import MAType 9 | from talipp.ohlcv import OHLCV 10 | 11 | 12 | class STC(Indicator): 13 | """Schaff Trend Cycle. 14 | 15 | Input type: `float` 16 | 17 | Output type: `float` 18 | 19 | Args: 20 | fast_macd_period: Fast [MACD][talipp.indicators.MACD] period. 21 | slow_macd_period: Slow [MACD][talipp.indicators.MACD] period. 22 | stoch_period: [Stoch][talipp.indicators.Stoch] period. 23 | stoch_smoothing_period: [Stoch][talipp.indicators.Stoch] smooting period. 24 | input_values: List of input values. 25 | input_indicator: Input indicator. 26 | input_modifier: Input modifier. 27 | stoch_ma_type: [Stoch][talipp.indicators.Stoch] moving average type. 28 | input_sampling: Input sampling type. 29 | """ 30 | 31 | def __init__(self, fast_macd_period: int, 32 | slow_macd_period: int, 33 | stoch_period: int, 34 | stoch_smoothing_period:int, 35 | input_values: List[float] = None, 36 | input_indicator: Indicator = None, 37 | input_modifier: InputModifierType = None, 38 | stoch_ma_type: MAType = MAType.SMA, 39 | input_sampling: SamplingPeriodType = None): 40 | super().__init__(input_modifier=input_modifier, 41 | input_sampling=input_sampling) 42 | 43 | # use slow_macd_period for signal line as signal line is not relevant here 44 | self.macd = MACD(fast_macd_period, slow_macd_period, slow_macd_period) 45 | self.stoch_macd = Stoch(stoch_period, stoch_smoothing_period, input_indicator=self.macd, input_modifier=STC.macd_to_ohlcv, ma_type=stoch_ma_type) 46 | self.stoch_d = Stoch(stoch_period, stoch_smoothing_period, input_indicator=self.stoch_macd, input_modifier=STC.stoch_d_to_ohlcv, ma_type=stoch_ma_type) 47 | 48 | self.add_sub_indicator(self.macd) 49 | 50 | self.initialize(input_values, input_indicator) 51 | 52 | def _calculate_new_value(self) -> Any: 53 | if has_valid_values(self.stoch_d, 1) and self.stoch_d[-1].d is not None: 54 | return max(min(self.stoch_d[-1].d, 100), 0) 55 | else: 56 | return None 57 | 58 | @staticmethod 59 | def macd_to_ohlcv(macd_val: MACDVal) -> OHLCV: 60 | return OHLCV(macd_val.macd, macd_val.macd, macd_val.macd, macd_val.macd) 61 | 62 | @staticmethod 63 | def stoch_d_to_ohlcv(stoch_val: StochVal) -> OHLCV: 64 | return OHLCV(stoch_val.d, stoch_val.d, stoch_val.d, stoch_val.d) 65 | -------------------------------------------------------------------------------- /talipp/indicators/StdDev.py: -------------------------------------------------------------------------------- 1 | from math import sqrt 2 | from typing import List, Any 3 | 4 | from talipp.indicator_util import has_valid_values 5 | from talipp.indicators.Indicator import Indicator, InputModifierType 6 | from talipp.input import SamplingPeriodType 7 | 8 | 9 | class StdDev(Indicator): 10 | """Standard Deviation. 11 | 12 | Input type: `float` 13 | 14 | Output type: `float` 15 | 16 | Args: 17 | period: Period. 18 | input_values: List of input values. 19 | input_indicator: Input indicator. 20 | input_modifier: Input modifier. 21 | input_sampling: Input sampling type. 22 | """ 23 | 24 | def __init__(self, period: int, 25 | input_values: List[float] = None, 26 | input_indicator: Indicator = None, 27 | input_modifier: InputModifierType = None, 28 | input_sampling: SamplingPeriodType = None): 29 | super().__init__(input_modifier=input_modifier, 30 | input_sampling=input_sampling) 31 | 32 | self.period = period 33 | 34 | self.initialize(input_values, input_indicator) 35 | 36 | def _calculate_new_value(self) -> Any: 37 | if not has_valid_values(self.input_values, self.period): 38 | return None 39 | 40 | mean = sum(self.input_values[-self.period:]) / self.period 41 | return sqrt(sum([(item - mean)**2 for item in self.input_values[-self.period:]]) / self.period) 42 | -------------------------------------------------------------------------------- /talipp/indicators/Stoch.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List, Any 3 | 4 | from talipp.indicator_util import has_valid_values 5 | from talipp.indicators.Indicator import Indicator, InputModifierType 6 | from talipp.input import SamplingPeriodType 7 | from talipp.ma import MAFactory, MAType 8 | from talipp.ohlcv import OHLCV 9 | 10 | 11 | @dataclass 12 | class StochVal: 13 | """`Stoch` output type. 14 | 15 | Args: 16 | k: `k` value. 17 | d: `d` value. 18 | """ 19 | 20 | k: float = None 21 | d: float = None 22 | 23 | 24 | class Stoch(Indicator): 25 | """Stochastic. 26 | 27 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 28 | 29 | Output type: [StochVal][talipp.indicators.Stoch.StochVal] 30 | 31 | Args: 32 | period: Period. 33 | smoothing_period: Moving average period. 34 | input_values: List of input values. 35 | input_indicator: Input indicator. 36 | input_modifier: Input modifier. 37 | ma_type: Moving average type. 38 | input_sampling: Input sampling type. 39 | """ 40 | 41 | def __init__(self, period: int, 42 | smoothing_period: int, 43 | input_values: List[OHLCV] = None, 44 | input_indicator: Indicator = None, 45 | input_modifier: InputModifierType = None, 46 | ma_type: MAType = MAType.SMA, 47 | input_sampling: SamplingPeriodType = None): 48 | super().__init__(input_modifier=input_modifier, 49 | output_value_type=StochVal, 50 | input_sampling=input_sampling) 51 | 52 | self.period = period 53 | 54 | self.values_d = MAFactory.get_ma(ma_type, smoothing_period) 55 | self.add_managed_sequence(self.values_d) 56 | 57 | self.initialize(input_values, input_indicator) 58 | 59 | def _calculate_new_value(self) -> Any: 60 | if not has_valid_values(self.input_values, self.period): 61 | return None 62 | 63 | input_period = self.input_values[-1 * self.period:] 64 | 65 | highs = [value.high for value in input_period if value.high is not None] 66 | lows = [value.low for value in input_period if value.low is not None] 67 | 68 | max_high = max(highs) 69 | min_low = min(lows) 70 | 71 | if max_high == min_low: 72 | k = 100.0 73 | else: 74 | k = 100.0 * (self.input_values[-1].close - min_low) / (max_high - min_low) 75 | 76 | self.values_d.add(k) 77 | 78 | if has_valid_values(self.values_d, 1): 79 | d = self.values_d[-1] 80 | else: 81 | d = None 82 | 83 | return StochVal(k, d) 84 | -------------------------------------------------------------------------------- /talipp/indicators/StochRSI.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List, Any 3 | 4 | from talipp.indicator_util import has_valid_values 5 | from talipp.indicators.Indicator import Indicator, InputModifierType 6 | from talipp.indicators.RSI import RSI 7 | from talipp.input import SamplingPeriodType 8 | from talipp.ma import MAType, MAFactory 9 | 10 | 11 | @dataclass 12 | class StochRSIVal: 13 | """`StochRSI` output type. 14 | 15 | Args: 16 | k: `k` value. 17 | d: `d` value. 18 | """ 19 | 20 | k: float = None 21 | d: float = None 22 | 23 | 24 | class StochRSI(Indicator): 25 | """Stochastic RSI. 26 | 27 | Input type: `float` 28 | 29 | Output type: [StochRSIVal][talipp.indicators.StochRSI.StochRSIVal] 30 | 31 | Args: 32 | rsi_period: [RSI][talipp.indicators.RSI] period. 33 | stoch_period: [Stoch][talipp.indicators.Stoch] period. 34 | k_smoothing_period: Stoch's `k` moving average period. 35 | d_smoothing_period: Stoch's `d` moving average period. 36 | input_values: List of input values. 37 | input_indicator: Input indicator. 38 | input_modifier: Input modifier. 39 | ma_type: Moving average type. 40 | input_sampling: Input sampling type. 41 | """ 42 | 43 | def __init__(self, rsi_period: int, 44 | stoch_period: int, 45 | k_smoothing_period: int, 46 | d_smoothing_period: int, 47 | input_values: List[float] = None, 48 | input_indicator: Indicator = None, 49 | input_modifier: InputModifierType = None, 50 | ma_type: MAType = MAType.SMA, 51 | input_sampling: SamplingPeriodType = None): 52 | super().__init__(input_modifier=input_modifier, 53 | output_value_type=StochRSIVal, 54 | input_sampling=input_sampling) 55 | 56 | self.stoch_period = stoch_period 57 | 58 | self.rsi = RSI(rsi_period) 59 | self.add_sub_indicator(self.rsi) 60 | 61 | self.smoothed_k = MAFactory.get_ma(ma_type, k_smoothing_period) 62 | self.add_managed_sequence(self.smoothed_k) 63 | 64 | self.values_d = MAFactory.get_ma(ma_type, d_smoothing_period) 65 | self.add_managed_sequence(self.values_d) 66 | 67 | self.initialize(input_values, input_indicator) 68 | 69 | def _calculate_new_value(self) -> Any: 70 | if not has_valid_values(self.rsi, self.stoch_period): 71 | return None 72 | 73 | recent_rsi = self.rsi[-self.stoch_period:] 74 | 75 | max_high = max(recent_rsi) 76 | min_low = min(recent_rsi) 77 | 78 | if max_high == min_low: 79 | k = 100.0 80 | else: 81 | k = 100.0 * (self.rsi[-1] - min_low) / (max_high - min_low) 82 | 83 | self.smoothed_k.add(k) 84 | self.values_d.add(self.smoothed_k[-1]) 85 | 86 | return StochRSIVal(self.smoothed_k[-1], self.values_d[-1]) 87 | -------------------------------------------------------------------------------- /talipp/indicators/T3.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.EMA import EMA 5 | from talipp.indicators.Indicator import Indicator, InputModifierType 6 | from talipp.input import SamplingPeriodType 7 | 8 | 9 | class T3(Indicator): 10 | """T3 Moving Average. 11 | 12 | Input type: `float` 13 | 14 | Output type: `float` 15 | 16 | Args: 17 | period: Period. 18 | factor: Multiplicative factor. 19 | input_values: List of input values. 20 | input_indicator: Input indicator. 21 | input_modifier: Input modifier. 22 | input_sampling: Input sampling type. 23 | """ 24 | 25 | def __init__(self, period: int, 26 | factor: float = 0.7, 27 | input_values: List[float] = None, 28 | input_indicator: Indicator = None, 29 | input_modifier: InputModifierType = None, 30 | input_sampling: SamplingPeriodType = None): 31 | super().__init__(input_modifier=input_modifier, 32 | input_sampling=input_sampling) 33 | 34 | self.period = period 35 | 36 | self.ema1 = EMA(period) 37 | self.ema2 = EMA(period, input_indicator=self.ema1) 38 | self.ema3 = EMA(period, input_indicator=self.ema2) 39 | self.ema4 = EMA(period, input_indicator=self.ema3) 40 | self.ema5 = EMA(period, input_indicator=self.ema4) 41 | self.ema6 = EMA(period, input_indicator=self.ema5) 42 | 43 | self.add_sub_indicator(self.ema1) 44 | 45 | self.c1 = -(factor**3) 46 | self.c2 = 3 * factor**2 + 3 * factor**3 47 | self.c3 = -6 * factor**2 - 3 * factor - 3 * factor**3 48 | self.c4 = 1 + 3 * factor + factor**3 + 3 * factor**2 49 | 50 | self.initialize(input_values, input_indicator) 51 | 52 | def _calculate_new_value(self) -> Any: 53 | if not has_valid_values(self.ema6, 1): 54 | return None 55 | 56 | return (self.c1 * self.ema6[-1] + 57 | self.c2 * self.ema5[-1] + 58 | self.c3 * self.ema4[-1] + 59 | self.c4 * self.ema3[-1]) 60 | -------------------------------------------------------------------------------- /talipp/indicators/TEMA.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.EMA import EMA 5 | from talipp.indicators.Indicator import Indicator, InputModifierType 6 | from talipp.input import SamplingPeriodType 7 | 8 | 9 | class TEMA(Indicator): 10 | """Triple Exponential Moving Average. 11 | 12 | Input type: `float` 13 | 14 | Output type: `float` 15 | 16 | Args: 17 | period: Period. 18 | input_values: List of input values. 19 | input_indicator: Input indicator. 20 | input_modifier: Input modifier. 21 | input_sampling: Input sampling type. 22 | """ 23 | 24 | def __init__(self, period: int, 25 | input_values: List[float] = None, 26 | input_indicator: Indicator = None, 27 | input_modifier: InputModifierType = None, 28 | input_sampling: SamplingPeriodType = None): 29 | super().__init__(input_modifier=input_modifier, 30 | input_sampling=input_sampling) 31 | 32 | self.period = period 33 | 34 | self.ema = EMA(period) 35 | self.ema_ema = EMA(period, input_indicator=self.ema) 36 | self.ema_ema_ema = EMA(period, input_indicator=self.ema_ema) 37 | 38 | self.add_sub_indicator(self.ema) 39 | 40 | self.initialize(input_values, input_indicator) 41 | 42 | def _calculate_new_value(self) -> Any: 43 | if not has_valid_values(self.ema_ema_ema, 1): 44 | return None 45 | 46 | return 3.0 * self.ema[-1] - 3.0 * self.ema_ema[-1] + self.ema_ema_ema[-1] 47 | -------------------------------------------------------------------------------- /talipp/indicators/TRIX.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.EMA import EMA 5 | from talipp.indicators.Indicator import Indicator, InputModifierType 6 | from talipp.input import SamplingPeriodType 7 | 8 | 9 | class TRIX(Indicator): 10 | """TRIX. 11 | 12 | Input type: `float` 13 | 14 | Output type: `float` 15 | 16 | Args: 17 | period: Period. 18 | input_values: List of input values. 19 | input_indicator: Input indicator. 20 | input_modifier: Input modifier. 21 | input_sampling: Input sampling type. 22 | """ 23 | 24 | def __init__(self, period: int, 25 | input_values: List[float] = None, 26 | input_indicator: Indicator = None, 27 | input_modifier: InputModifierType = None, 28 | input_sampling: SamplingPeriodType = None): 29 | super().__init__(input_modifier=input_modifier, 30 | input_sampling=input_sampling) 31 | 32 | self.period = period 33 | 34 | self.ema1 = EMA(period) 35 | self.ema2 = EMA(period, input_indicator = self.ema1) 36 | self.ema3 = EMA(period, input_indicator = self.ema2) 37 | 38 | self.add_sub_indicator(self.ema1) 39 | 40 | self.initialize(input_values, input_indicator) 41 | 42 | def _calculate_new_value(self) -> Any: 43 | if not has_valid_values(self.ema3, 2): 44 | return None 45 | 46 | return 10000.0 * (self.ema3[-1] - self.ema3[-2]) / self.ema3[-2] 47 | -------------------------------------------------------------------------------- /talipp/indicators/TSI.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | from talipp.ma import MAType, MAFactory 7 | 8 | 9 | class TSI(Indicator): 10 | """True Strength Index. 11 | 12 | Input type: `float` 13 | 14 | Output type: `float` 15 | 16 | Args: 17 | fast_period: Fast moving average period. 18 | slow_period: Slow moving average period. 19 | input_values: List of input values. 20 | input_indicator: Input indicator. 21 | input_modifier: Input modifier. 22 | ma_type: Moving average type. 23 | input_sampling: Input sampling type. 24 | """ 25 | 26 | def __init__(self, fast_period: int, 27 | slow_period: int, 28 | input_values: List[float] = None, 29 | input_indicator: Indicator = None, 30 | input_modifier: InputModifierType = None, 31 | ma_type: MAType = MAType.EMA, 32 | input_sampling: SamplingPeriodType = None): 33 | super().__init__(input_modifier=input_modifier, 34 | input_sampling=input_sampling) 35 | 36 | self.slow_ma = MAFactory.get_ma(ma_type, slow_period) 37 | self.add_managed_sequence(self.slow_ma) 38 | self.fast_ma = MAFactory.get_ma(ma_type, fast_period, input_indicator = self.slow_ma) 39 | 40 | self.abs_slow_ma = MAFactory.get_ma(ma_type, slow_period) 41 | self.add_managed_sequence(self.abs_slow_ma) 42 | self.abs_fast_ma = MAFactory.get_ma(ma_type, fast_period, input_indicator = self.abs_slow_ma) 43 | 44 | self.initialize(input_values, input_indicator) 45 | 46 | def _calculate_new_value(self) -> Any: 47 | if not has_valid_values(self.input_values, 2): 48 | return None 49 | 50 | self.slow_ma.add(self.input_values[-1] - self.input_values[-2]) 51 | self.abs_slow_ma.add(abs(self.input_values[-1] - self.input_values[-2])) 52 | 53 | if not has_valid_values(self.fast_ma, 1): 54 | return None 55 | 56 | if self.abs_fast_ma[-1] != 0: 57 | return 100.0 * (self.fast_ma[-1] / self.abs_fast_ma[-1]) 58 | else: 59 | if has_valid_values(self.output_values, 1): 60 | return self.output_values[-1] 61 | else: 62 | return None 63 | -------------------------------------------------------------------------------- /talipp/indicators/UO.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | from talipp.ohlcv import OHLCV 7 | 8 | 9 | class UO(Indicator): 10 | """Ultimate Oscillator. 11 | 12 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 13 | 14 | Output type: `float` 15 | 16 | Args: 17 | fast_period: Fast period. 18 | mid_period: Mid period. 19 | slow_period: Slow period. 20 | input_values: List of input values. 21 | input_indicator: Input indicator. 22 | input_modifier: Input modifier. 23 | input_sampling: Input sampling type. 24 | """ 25 | 26 | def __init__(self, fast_period: int, 27 | mid_period: int, 28 | slow_period: int, 29 | input_values: List[OHLCV] = None, 30 | input_indicator: Indicator = None, 31 | input_modifier: InputModifierType = None, 32 | input_sampling: SamplingPeriodType = None): 33 | super().__init__(input_modifier=input_modifier, 34 | input_sampling=input_sampling) 35 | 36 | self.fast_period = fast_period 37 | self.mid_period = mid_period 38 | self.slow_period = slow_period 39 | 40 | self.buy_press = [] 41 | self.true_range = [] 42 | 43 | self.add_managed_sequence(self.buy_press) 44 | self.add_managed_sequence(self.true_range) 45 | 46 | self.initialize(input_values, input_indicator) 47 | 48 | def _calculate_new_value(self) -> Any: 49 | if not has_valid_values(self.input_values, 2): 50 | return None 51 | 52 | value = self.input_values[-1] 53 | prev_value = self.input_values[-2] 54 | 55 | self.buy_press.append(value.close - min(value.low, prev_value.close)) 56 | self.true_range.append(max(value.high, prev_value.close) - min(value.low, prev_value.close)) 57 | 58 | if not has_valid_values(self.buy_press, self.slow_period): 59 | return None 60 | 61 | fast_sum = sum(self.true_range[-self.fast_period:]) 62 | mid_sum = sum(self.true_range[-self.mid_period:]) 63 | slow_sum = sum(self.true_range[-self.slow_period:]) 64 | 65 | if fast_sum == 0 or mid_sum == 0 or slow_sum == 0: 66 | return None 67 | 68 | avg_fast = sum(self.buy_press[-self.fast_period:]) / float(fast_sum) 69 | avg_mid = sum(self.buy_press[-self.mid_period:]) / float(mid_sum) 70 | avg_slow = sum(self.buy_press[-self.slow_period:]) / float(slow_sum) 71 | 72 | return 100.0 * (4.0 * avg_fast + 2.0 * avg_mid + avg_slow) / 7.0 73 | -------------------------------------------------------------------------------- /talipp/indicators/VTX.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from typing import List, Any 3 | 4 | from talipp.indicator_util import has_valid_values 5 | from talipp.indicators.ATR import ATR 6 | from talipp.indicators.Indicator import Indicator, InputModifierType 7 | from talipp.input import SamplingPeriodType 8 | from talipp.ohlcv import OHLCV 9 | 10 | 11 | @dataclass 12 | class VTXVal: 13 | """`VTX` output type. 14 | 15 | Args: 16 | plus_vtx: Positive movement. 17 | minus_vtx: Negative movement. 18 | """ 19 | 20 | plus_vtx: float = None 21 | minus_vtx: float = None 22 | 23 | 24 | class VTX(Indicator): 25 | """Vortex Indicator. 26 | 27 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 28 | 29 | Output type: [VTXVal][talipp.indicators.VTX.VTXVal] 30 | 31 | Args: 32 | period: Period. 33 | input_values: List of input values. 34 | input_indicator: Input indicator. 35 | input_modifier: Input modifier. 36 | input_sampling: Input sampling type. 37 | """ 38 | 39 | def __init__(self, period: int, 40 | input_values: List[OHLCV] = None, 41 | input_indicator: Indicator = None, 42 | input_modifier: InputModifierType = None, 43 | input_sampling: SamplingPeriodType = None): 44 | super().__init__(input_modifier=input_modifier, 45 | output_value_type=VTXVal, 46 | input_sampling=input_sampling) 47 | 48 | self.period = period 49 | 50 | self.plus_vm = [] 51 | self.add_managed_sequence(self.plus_vm) 52 | 53 | self.minus_vm = [] 54 | self.add_managed_sequence(self.minus_vm) 55 | 56 | self.atr = ATR(1) 57 | self.add_sub_indicator(self.atr) 58 | 59 | self.initialize(input_values, input_indicator) 60 | 61 | def _calculate_new_value(self) -> Any: 62 | if not has_valid_values(self.input_values, 2): 63 | return None 64 | 65 | value = self.input_values[-1] 66 | value2 = self.input_values[-2] 67 | 68 | self.plus_vm.append(abs(value.high - value2.low)) 69 | self.minus_vm.append(abs(value.low - value2.high)) 70 | 71 | if not has_valid_values(self.atr, self.period) or not has_valid_values(self.plus_vm, self.period) or \ 72 | not has_valid_values(self.minus_vm, self.period): 73 | return None 74 | 75 | atr_sum = float(sum(self.atr[-self.period:])) 76 | return VTXVal(sum(self.plus_vm[-self.period:]) / atr_sum, sum(self.minus_vm[-self.period:]) / atr_sum) 77 | -------------------------------------------------------------------------------- /talipp/indicators/VWAP.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicators.Indicator import Indicator, InputModifierType 4 | from talipp.input import SamplingPeriodType 5 | from talipp.ohlcv import OHLCV 6 | 7 | 8 | class VWAP(Indicator): 9 | """Volume Weighted Average Price. 10 | 11 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 12 | 13 | Output type: `float` 14 | 15 | Args: 16 | input_values: List of input values. 17 | input_indicator: Input indicator. 18 | input_modifier: Input modifier. 19 | input_sampling: Input sampling type. 20 | """ 21 | 22 | def __init__(self, input_values: List[OHLCV] = None, 23 | input_indicator: Indicator = None, 24 | input_modifier: InputModifierType = None, 25 | input_sampling: SamplingPeriodType = None): 26 | super().__init__(input_modifier=input_modifier, 27 | input_sampling=input_sampling) 28 | 29 | self.sum_price_vol = [] 30 | self.sum_vol = [] 31 | 32 | self.add_managed_sequence(self.sum_price_vol) 33 | self.add_managed_sequence(self.sum_vol) 34 | 35 | self.initialize(input_values, input_indicator) 36 | 37 | def _calculate_new_value(self) -> Any: 38 | # initialize sums 39 | if len(self.sum_price_vol) == 0: 40 | self.sum_price_vol.append(0.0) 41 | self.sum_vol.append(0.0) 42 | 43 | value = self.input_values[-1] 44 | typical_price = (value.high + value.low + value.close) / 3.0 45 | 46 | self.sum_price_vol.append(self.sum_price_vol[-1] + value.volume * typical_price) 47 | self.sum_vol.append(self.sum_vol[-1] + value.volume) 48 | 49 | if self.sum_vol[-1] != 0: 50 | return self.sum_price_vol[-1] / self.sum_vol[-1] 51 | else: 52 | return None 53 | -------------------------------------------------------------------------------- /talipp/indicators/VWMA.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | from talipp.ohlcv import OHLCV 7 | 8 | 9 | class VWMA(Indicator): 10 | """Volume Weighted Moving Average. 11 | 12 | Input type: [OHLCV][talipp.ohlcv.OHLCV] 13 | 14 | Output type: `float` 15 | 16 | Args: 17 | period: Period. 18 | input_values: List of input values. 19 | input_indicator: Input indicator. 20 | input_modifier: Input modifier. 21 | input_sampling: Input sampling type. 22 | """ 23 | 24 | def __init__(self, period: int, 25 | input_values: List[OHLCV] = None, 26 | input_indicator: Indicator = None, 27 | input_modifier: InputModifierType = None, 28 | input_sampling: SamplingPeriodType = None): 29 | super().__init__(input_modifier=input_modifier, 30 | input_sampling=input_sampling) 31 | 32 | self.period = period 33 | 34 | self.initialize(input_values, input_indicator) 35 | 36 | def _calculate_new_value(self) -> Any: 37 | if not has_valid_values(self.input_values, self.period): 38 | return None 39 | else: 40 | s = 0.0 41 | v = 0.0 42 | for value in self.input_values[-self.period:]: 43 | s += value.close * value.volume 44 | v += value.volume 45 | 46 | return s / v 47 | -------------------------------------------------------------------------------- /talipp/indicators/WMA.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.Indicator import Indicator, InputModifierType 5 | from talipp.input import SamplingPeriodType 6 | 7 | 8 | class WMA(Indicator): 9 | """Weighted Moving Average. 10 | 11 | Input type: `float` 12 | 13 | Output type: `float` 14 | 15 | Args: 16 | period: Period. 17 | input_values: List of input values. 18 | input_indicator: Input indicator. 19 | input_modifier: Input modifier. 20 | input_sampling: Input sampling type. 21 | """ 22 | 23 | def __init__(self, period: int, 24 | input_values: List[float] = None, 25 | input_indicator: Indicator = None, 26 | input_modifier: InputModifierType = None, 27 | input_sampling: SamplingPeriodType = None): 28 | super().__init__(input_modifier=input_modifier, 29 | input_sampling=input_sampling) 30 | 31 | self.period = period 32 | 33 | self.denom_sum = period * (period + 1) / 2.0 34 | 35 | self.initialize(input_values, input_indicator) 36 | 37 | def _calculate_new_value(self) -> Any: 38 | if not has_valid_values(self.input_values, self.period): 39 | return None 40 | 41 | s = 0.0 42 | for i in range(self.period, 0, -1): 43 | index = len(self.input_values) - self.period + i - 1 # decreases from end of array with increasing i 44 | s += self.input_values[index] * i 45 | 46 | return s / self.denom_sum 47 | -------------------------------------------------------------------------------- /talipp/indicators/ZLEMA.py: -------------------------------------------------------------------------------- 1 | from typing import List, Any 2 | 3 | from talipp.indicator_util import has_valid_values 4 | from talipp.indicators.EMA import EMA 5 | from talipp.indicators.Indicator import Indicator, InputModifierType 6 | from talipp.input import SamplingPeriodType 7 | 8 | 9 | class ZLEMA(Indicator): 10 | """Zero Lag Exponential Moving Average. 11 | 12 | Input type: `float` 13 | 14 | Output type: `float` 15 | 16 | Args: 17 | period: Period. 18 | input_values: List of input values. 19 | input_indicator: Input indicator. 20 | input_modifier: Input modifier. 21 | input_sampling: Input sampling type. 22 | """ 23 | 24 | def __init__(self, period: int, 25 | input_values: List[float] = None, 26 | input_indicator: Indicator = None, 27 | input_modifier: InputModifierType = None, 28 | input_sampling: SamplingPeriodType = None): 29 | super().__init__(input_modifier=input_modifier, 30 | input_sampling=input_sampling) 31 | 32 | self.lag = round((period - 1) / 2.0) 33 | 34 | self.ema = EMA(period) 35 | self.add_managed_sequence(self.ema) 36 | 37 | self.initialize(input_values, input_indicator) 38 | 39 | def _calculate_new_value(self) -> Any: 40 | if not has_valid_values(self.input_values, self.lag+1): 41 | return None 42 | 43 | self.ema.add(self.input_values[-1] + (self.input_values[-1] - self.input_values[-self.lag-1])) 44 | 45 | if not has_valid_values(self.ema): 46 | return None 47 | 48 | return self.ema[-1] 49 | -------------------------------------------------------------------------------- /talipp/indicators/__init__.py: -------------------------------------------------------------------------------- 1 | from .AccuDist import AccuDist as AccuDist 2 | from .ADX import ADX as ADX 3 | from .ALMA import ALMA as ALMA 4 | from .AO import AO as AO 5 | from .Aroon import Aroon as Aroon 6 | from .ATR import ATR as ATR 7 | from .BB import BB as BB 8 | from .BOP import BOP as BOP 9 | from .CCI import CCI as CCI 10 | from .ChaikinOsc import ChaikinOsc as ChaikinOsc 11 | from .ChandeKrollStop import ChandeKrollStop as ChandeKrollStop 12 | from .CHOP import CHOP as CHOP 13 | from .CoppockCurve import CoppockCurve as CoppockCurve 14 | from .DEMA import DEMA as DEMA 15 | from .DonchianChannels import DonchianChannels as DonchianChannels 16 | from .DPO import DPO as DPO 17 | from .EMA import EMA as EMA 18 | from .EMV import EMV as EMV 19 | from .FibonacciRetracement import FibonacciRetracement as FibonacciRetracement 20 | from .ForceIndex import ForceIndex as ForceIndex 21 | from .HMA import HMA as HMA 22 | from .IBS import IBS as IBS 23 | from .Ichimoku import Ichimoku as Ichimoku 24 | from .KAMA import KAMA as KAMA 25 | from .KeltnerChannels import KeltnerChannels as KeltnerChannels 26 | from .KST import KST as KST 27 | from .KVO import KVO as KVO 28 | from .MACD import MACD as MACD 29 | from .MassIndex import MassIndex as MassIndex 30 | from .McGinleyDynamic import McGinleyDynamic as McGinleyDynamic 31 | from .MeanDev import MeanDev as MeanDev 32 | from .NATR import NATR as NATR 33 | from .OBV import OBV as OBV 34 | from .PivotsHL import PivotsHL as PivotsHL 35 | from .ROC import ROC as ROC 36 | from .RogersSatchell import RogersSatchell as RogersSatchell 37 | from .RSI import RSI as RSI 38 | from .ParabolicSAR import ParabolicSAR as ParabolicSAR 39 | from .SFX import SFX as SFX 40 | from .SMA import SMA as SMA 41 | from .SMMA import SMMA as SMMA 42 | from .SOBV import SOBV as SOBV 43 | from .STC import STC as STC 44 | from .StdDev import StdDev as StdDev 45 | from .Stoch import Stoch as Stoch 46 | from .StochRSI import StochRSI as StochRSI 47 | from .SuperTrend import SuperTrend as SuperTrend 48 | from .T3 import T3 as T3 49 | from .TEMA import TEMA as TEMA 50 | from .TRIX import TRIX as TRIX 51 | from .TSI import TSI as TSI 52 | from .TTM import TTM as TTM 53 | from .UO import UO as UO 54 | from .VTX import VTX as VTX 55 | from .VWAP import VWAP as VWAP 56 | from .VWMA import VWMA as VWMA 57 | from .WMA import WMA as WMA 58 | from .ZigZag import ZigZag as ZigZag 59 | from .ZLEMA import ZLEMA as ZLEMA 60 | 61 | __all__ = ( 62 | "AccuDist", 63 | "ADX", 64 | "ALMA", 65 | "AO", 66 | "Aroon", 67 | "ATR", 68 | "BB", 69 | "BOP", 70 | "CCI", 71 | "ChaikinOsc", 72 | "ChandeKrollStop", 73 | "CHOP", 74 | "CoppockCurve", 75 | "DEMA", 76 | "DonchianChannels", 77 | "DPO", 78 | "EMA", 79 | "EMV", 80 | "FibonacciRetracement", 81 | "ForceIndex", 82 | "HMA", 83 | "IBS", 84 | "Ichimoku", 85 | "KAMA", 86 | "KeltnerChannels", 87 | "KST", 88 | "KVO", 89 | "MACD", 90 | "MassIndex", 91 | "McGinleyDynamic", 92 | "MeanDev", 93 | "NATR", 94 | "OBV", 95 | "ParabolicSAR", 96 | "PivotsHL", 97 | "ROC", 98 | "RogersSatchell", 99 | "RSI", 100 | "SFX", 101 | "SMA", 102 | "SMMA", 103 | "SOBV", 104 | "STC", 105 | "StdDev", 106 | "Stoch", 107 | "StochRSI", 108 | "SuperTrend", 109 | "T3", 110 | "TEMA", 111 | "TRIX", 112 | "TSI", 113 | "TTM", 114 | "UO", 115 | "VTX", 116 | "VWAP", 117 | "VWMA", 118 | "WMA", 119 | "ZigZag", 120 | "ZLEMA" 121 | ) 122 | -------------------------------------------------------------------------------- /test/test_ADX.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import ADX 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class TestADX(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = ADX(14, 14, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3].adx, 15.734865, places = 5) 18 | self.assertAlmostEqual(ind[-3].plus_di, 33.236743, places = 5) 19 | self.assertAlmostEqual(ind[-3].minus_di, 17.415377, places = 5) 20 | 21 | self.assertAlmostEqual(ind[-2].adx, 16.761395, places = 5) 22 | self.assertAlmostEqual(ind[-2].plus_di, 31.116720, places = 5) 23 | self.assertAlmostEqual(ind[-2].minus_di, 16.716048, places = 5) 24 | 25 | self.assertAlmostEqual(ind[-1].adx, 16.698475, places = 5) 26 | self.assertAlmostEqual(ind[-1].plus_di, 28.670782, places = 5) 27 | self.assertAlmostEqual(ind[-1].minus_di, 20.812570, places = 5) 28 | 29 | def test_update(self): 30 | self.assertIndicatorUpdate(ADX(14, 14, self.input_values)) 31 | 32 | def test_delete(self): 33 | self.assertIndicatorDelete(ADX(14, 14, self.input_values)) 34 | 35 | def test_purge_oldest(self): 36 | self.assertIndicatorPurgeOldest(ADX(14, 14, self.input_values)) 37 | 38 | 39 | if __name__ == '__main__': 40 | unittest.main() 41 | -------------------------------------------------------------------------------- /test/test_ALMA.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import ALMA 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class TestALMA(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.CLOSE_TMPL) 11 | 12 | def test_init(self): 13 | ind = ALMA(9, 0.85, 6, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 10.053326, places = 5) 18 | self.assertAlmostEqual(ind[-2], 10.267585, places = 5) 19 | self.assertAlmostEqual(ind[-1], 10.264363, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(ALMA(9, 0.85, 6, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(ALMA(9, 0.85, 6, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(ALMA(9, 0.85, 6, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_AO.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import AO 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class TestAO(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = AO(5, 7, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 0.117142, places = 5) 18 | self.assertAlmostEqual(ind[-2], 0.257142, places = 5) 19 | self.assertAlmostEqual(ind[-1], 0.373285, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(AO(5, 7, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(AO(5, 7, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(AO(5, 7, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_ATR.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import ATR 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class TestATR(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = ATR(5, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 0.676426, places = 5) 18 | self.assertAlmostEqual(ind[-2], 0.665141, places = 5) 19 | self.assertAlmostEqual(ind[-1], 0.686113, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(ATR(5, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(ATR(5, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(ATR(5, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_AccuDist.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import AccuDist 4 | from talipp.ohlcv import OHLCV 5 | 6 | from TalippTest import TalippTest 7 | 8 | 9 | class TestAccuDist(TalippTest): 10 | def setUp(self) -> None: 11 | self.input_values = list(TalippTest.OHLCV_TMPL) 12 | 13 | def test_init(self): 14 | ind = AccuDist(self.input_values) 15 | 16 | print(ind) 17 | self.assertAlmostEqual(ind[-3], -689.203568, places = 5) 18 | self.assertAlmostEqual(ind[-2], -725.031632, places = 5) 19 | self.assertAlmostEqual(ind[-1], -726.092152, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(AccuDist(self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(AccuDist(self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(AccuDist(self.input_values)) 29 | 30 | def test_low_high_equal(self): 31 | ind = AccuDist(self.input_values) 32 | ind.add(OHLCV(1, 1, 1, 1, 1)) 33 | 34 | # no assert since the check verifies no exception was raised 35 | 36 | 37 | if __name__ == '__main__': 38 | unittest.main() 39 | -------------------------------------------------------------------------------- /test/test_Aroon.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import Aroon 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = Aroon(10, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3].up, 100, places = 5) 18 | self.assertAlmostEqual(ind[-3].down, 70, places = 5) 19 | 20 | self.assertAlmostEqual(ind[-2].up, 90, places = 5) 21 | self.assertAlmostEqual(ind[-2].down, 60, places = 5) 22 | 23 | self.assertAlmostEqual(ind[-1].up, 80, places = 5) 24 | self.assertAlmostEqual(ind[-1].down, 50, places = 5) 25 | 26 | def test_update(self): 27 | self.assertIndicatorUpdate(Aroon(10, self.input_values)) 28 | 29 | def test_delete(self): 30 | self.assertIndicatorDelete(Aroon(10, self.input_values)) 31 | 32 | def test_purge_oldest(self): 33 | self.assertIndicatorPurgeOldest(Aroon(10, self.input_values)) 34 | 35 | 36 | if __name__ == '__main__': 37 | unittest.main() 38 | -------------------------------------------------------------------------------- /test/test_BB.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import BB 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class TestBB(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.CLOSE_TMPL) 11 | 12 | def test_init(self): 13 | ind = BB(5, 2, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3].lb, 8.186646, places = 5) 18 | self.assertAlmostEqual(ind[-3].cb, 9.748000, places = 5) 19 | self.assertAlmostEqual(ind[-3].ub, 11.309353, places = 5) 20 | 21 | self.assertAlmostEqual(ind[-2].lb, 9.161539, places = 5) 22 | self.assertAlmostEqual(ind[-2].cb, 10.096000, places = 5) 23 | self.assertAlmostEqual(ind[-2].ub, 11.030460, places = 5) 24 | 25 | self.assertAlmostEqual(ind[-1].lb, 9.863185, places = 5) 26 | self.assertAlmostEqual(ind[-1].cb, 10.254000, places = 5) 27 | self.assertAlmostEqual(ind[-1].ub, 10.644814, places = 5) 28 | 29 | def test_update(self): 30 | self.assertIndicatorUpdate(BB(5, 2, self.input_values)) 31 | 32 | def test_delete(self): 33 | self.assertIndicatorDelete(BB(5, 2, self.input_values)) 34 | 35 | def test_purge_oldest(self): 36 | self.assertIndicatorPurgeOldest(BB(5, 2, self.input_values)) 37 | 38 | 39 | if __name__ == '__main__': 40 | unittest.main() 41 | -------------------------------------------------------------------------------- /test/test_BOP.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import BOP 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = BOP(self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 0.447761, places = 5) 18 | self.assertAlmostEqual(ind[-2], -0.870967, places = 5) 19 | self.assertAlmostEqual(ind[-1], -0.363636, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(BOP(self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(BOP(self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(BOP(self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_CCI.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import CCI 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = CCI(20, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 179.169127, places = 5) 18 | self.assertAlmostEqual(ind[-2], 141.667617, places = 5) 19 | self.assertAlmostEqual(ind[-1], 89.601438, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(CCI(20, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(CCI(20, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(CCI(20, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_CHOP.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import CHOP 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = CHOP(14, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 49.835100, places = 5) 18 | self.assertAlmostEqual(ind[-2], 50.001477, places = 5) 19 | self.assertAlmostEqual(ind[-1], 49.289273, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(CHOP(14, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(CHOP(14, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(CHOP(14, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_ChaikinOsc.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import ChaikinOsc 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = ChaikinOsc(5, 7, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 31.280810, places = 5) 18 | self.assertAlmostEqual(ind[-2], 28.688536, places = 5) 19 | self.assertAlmostEqual(ind[-1], 24.913310, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(ChaikinOsc(5, 7, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(ChaikinOsc(5, 7, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(ChaikinOsc(5, 7, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_ChandeKrollStop.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import ChandeKrollStop 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class TestBB(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = ChandeKrollStop(5, 2, 3, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3].short_stop, 9.507146, places = 5) 18 | self.assertAlmostEqual(ind[-3].long_stop, 9.772853, places = 5) 19 | 20 | self.assertAlmostEqual(ind[-2].short_stop, 9.529717, places = 5) 21 | self.assertAlmostEqual(ind[-2].long_stop, 9.750282, places = 5) 22 | 23 | self.assertAlmostEqual(ind[-1].short_stop, 9.529717, places = 5) 24 | self.assertAlmostEqual(ind[-1].long_stop, 9.750282, places = 5) 25 | 26 | def test_update(self): 27 | self.assertIndicatorUpdate(ChandeKrollStop(5, 2, 3, self.input_values)) 28 | 29 | def test_delete(self): 30 | self.assertIndicatorDelete(ChandeKrollStop(5, 2, 3, self.input_values)) 31 | 32 | def test_purge_oldest(self): 33 | self.assertIndicatorPurgeOldest(ChandeKrollStop(5, 2, 3, self.input_values)) 34 | 35 | 36 | if __name__ == '__main__': 37 | unittest.main() 38 | -------------------------------------------------------------------------------- /test/test_CoppockCurve.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import CoppockCurve 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.CLOSE_TMPL) 11 | 12 | def test_init(self): 13 | ind = CoppockCurve(11, 14, 10, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 27.309482, places = 5) 18 | self.assertAlmostEqual(ind[-2], 26.109333, places = 5) 19 | self.assertAlmostEqual(ind[-1], 22.941006, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(CoppockCurve(11, 14, 10, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(CoppockCurve(11, 14, 10, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(CoppockCurve(11, 14, 10, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_DEMA.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import DEMA 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class TestDEMA(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.CLOSE_TMPL) 11 | 12 | def test_init(self): 13 | ind = DEMA(20, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 9.683254, places = 5) 18 | self.assertAlmostEqual(ind[-2], 9.813792, places = 5) 19 | self.assertAlmostEqual(ind[-1], 9.882701, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(DEMA(20, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(DEMA(20, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(DEMA(20, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_DPO.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import DPO 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.CLOSE_TMPL) 11 | 12 | def test_init(self): 13 | ind = DPO(20, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 0.344499, places = 5) 18 | self.assertAlmostEqual(ind[-2], 0.116999, places = 5) 19 | self.assertAlmostEqual(ind[-1], 0.011499, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(DPO(20, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(DPO(20, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(DPO(20, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_DonchianChannels.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import DonchianChannels 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = DonchianChannels(5, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3].lb, 8.420000, places = 5) 18 | self.assertAlmostEqual(ind[-3].cb, 9.640000, places = 5) 19 | self.assertAlmostEqual(ind[-3].ub, 10.860000, places = 5) 20 | 21 | self.assertAlmostEqual(ind[-2].lb, 8.420000, places = 5) 22 | self.assertAlmostEqual(ind[-2].cb, 9.640000, places = 5) 23 | self.assertAlmostEqual(ind[-2].ub, 10.860000, places = 5) 24 | 25 | self.assertAlmostEqual(ind[-1].lb, 9.260000, places = 5) 26 | self.assertAlmostEqual(ind[-1].cb, 10.059999, places = 5) 27 | self.assertAlmostEqual(ind[-1].ub, 10.860000, places = 5) 28 | 29 | def test_update(self): 30 | self.assertIndicatorUpdate(DonchianChannels(5, self.input_values)) 31 | 32 | def test_delete(self): 33 | self.assertIndicatorDelete(DonchianChannels(5, self.input_values)) 34 | 35 | def test_purge_oldest(self): 36 | self.assertIndicatorPurgeOldest(DonchianChannels(5, self.input_values)) 37 | 38 | 39 | if __name__ == '__main__': 40 | unittest.main() 41 | -------------------------------------------------------------------------------- /test/test_EMA.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import EMA 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.CLOSE_TMPL) 11 | 12 | def test_init(self): 13 | ind = EMA(20, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 9.319374, places = 5) 18 | self.assertAlmostEqual(ind[-2], 9.406100, places = 5) 19 | self.assertAlmostEqual(ind[-1], 9.462662, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(EMA(20, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(EMA(20, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(EMA(20, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_EMV.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import EMV 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = EMV(14, 10000, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 5.656780, places = 5) 18 | self.assertAlmostEqual(ind[-2], 5.129971, places = 5) 19 | self.assertAlmostEqual(ind[-1], -0.192883, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(EMV(14, 10000, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(EMV(14, 10000, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(EMV(14, 10000, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_ForceIndex.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import ForceIndex 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = ForceIndex(20, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 24.015092, places = 5) 18 | self.assertAlmostEqual(ind[-2], 20.072283, places = 5) 19 | self.assertAlmostEqual(ind[-1], 16.371894, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(ForceIndex(20, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(ForceIndex(20, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(ForceIndex(20, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_HMA.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import HMA 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.CLOSE_TMPL) 11 | 12 | def test_init(self): 13 | ind = HMA(20, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 9.718018, places = 5) 18 | self.assertAlmostEqual(ind[-2], 9.940188, places = 5) 19 | self.assertAlmostEqual(ind[-1], 10.104067, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(HMA(3, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(HMA(3, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(HMA(3, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_IBS.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import IBS 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = IBS(self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 0.597014, places = 5) 18 | self.assertAlmostEqual(ind[-2], 0.129032, places = 5) 19 | self.assertAlmostEqual(ind[-1], 0.493506, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(IBS(self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(IBS(self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(IBS(self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_KAMA.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import KAMA 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.CLOSE_TMPL) 11 | 12 | def test_init(self): 13 | ind = KAMA(14, 2, 30, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 8.884374, places = 5) 18 | self.assertAlmostEqual(ind[-2], 8.932091, places = 5) 19 | self.assertAlmostEqual(ind[-1], 8.941810, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(KAMA(14, 2, 30, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(KAMA(14, 2, 30, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(KAMA(14, 2, 30, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_KST.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import KST 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.CLOSE_TMPL) 11 | 12 | def test_init(self): 13 | ind = KST(5, 5, 10, 5, 15, 5, 25, 10, 9, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3].kst, 136.602283, places = 5) 18 | self.assertAlmostEqual(ind[-3].signal, 103.707431, places = 5) 19 | 20 | self.assertAlmostEqual(ind[-2].kst, 158.252762, places = 5) 21 | self.assertAlmostEqual(ind[-2].signal, 113.964023, places = 5) 22 | 23 | self.assertAlmostEqual(ind[-1].kst, 155.407034, places = 5) 24 | self.assertAlmostEqual(ind[-1].signal, 122.246497, places = 5) 25 | 26 | def test_update(self): 27 | self.assertIndicatorUpdate(KST(10, 10, 15, 10, 20, 10, 30, 15, 9, self.input_values)) 28 | 29 | def test_delete(self): 30 | self.assertIndicatorDelete(KST(10, 10, 15, 10, 20, 10, 30, 15, 9, self.input_values)) 31 | 32 | def test_purge_oldest(self): 33 | self.assertIndicatorPurgeOldest(KST(10, 10, 15, 10, 20, 10, 30, 15, 9, self.input_values)) 34 | 35 | 36 | if __name__ == '__main__': 37 | unittest.main() 38 | -------------------------------------------------------------------------------- /test/test_KVO.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import KVO 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = KVO(5, 10, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 4540.325257, places = 5) 18 | self.assertAlmostEqual(ind[-2], 535.632479, places = 5) 19 | self.assertAlmostEqual(ind[-1], -2470.776132, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(KVO(5, 10, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(KVO(5, 10, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(KVO(5, 10, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_KeltnerChannels.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import KeltnerChannels 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = KeltnerChannels(10, 10, 2, 3, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3].lb, 7.606912, places = 5) 18 | self.assertAlmostEqual(ind[-3].cb, 9.643885, places = 5) 19 | self.assertAlmostEqual(ind[-3].ub, 11.001867, places = 5) 20 | 21 | self.assertAlmostEqual(ind[-2].lb, 7.731176, places = 5) 22 | self.assertAlmostEqual(ind[-2].cb, 9.750451, places = 5) 23 | self.assertAlmostEqual(ind[-2].ub, 11.096635, places = 5) 24 | 25 | self.assertAlmostEqual(ind[-1].lb, 7.747476, places = 5) 26 | self.assertAlmostEqual(ind[-1].cb, 9.795824, places = 5) 27 | self.assertAlmostEqual(ind[-1].ub, 11.161389, places = 5) 28 | 29 | def test_update(self): 30 | self.assertIndicatorUpdate(KeltnerChannels(10, 10, 2, 3, self.input_values)) 31 | 32 | def test_delete(self): 33 | self.assertIndicatorDelete(KeltnerChannels(10, 10, 2, 3, self.input_values)) 34 | 35 | def test_purge_oldest(self): 36 | self.assertIndicatorPurgeOldest(KeltnerChannels(10, 10, 2, 3, self.input_values)) 37 | 38 | 39 | if __name__ == '__main__': 40 | unittest.main() 41 | -------------------------------------------------------------------------------- /test/test_MACD.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import MACD 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.CLOSE_TMPL) 11 | 12 | def test_init(self): 13 | ind = MACD(12, 26, 9, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3].macd, 0.293541, places = 5) 18 | self.assertAlmostEqual(ind[-3].signal, 0.098639, places = 5) 19 | self.assertAlmostEqual(ind[-3].histogram, 0.194901, places = 5) 20 | 21 | self.assertAlmostEqual(ind[-2].macd, 0.326186, places = 5) 22 | self.assertAlmostEqual(ind[-2].signal, 0.144149, places = 5) 23 | self.assertAlmostEqual(ind[-2].histogram, 0.182037, places = 5) 24 | 25 | self.assertAlmostEqual(ind[-1].macd, 0.329698, places = 5) 26 | self.assertAlmostEqual(ind[-1].signal, 0.181259, places = 5) 27 | self.assertAlmostEqual(ind[-1].histogram, 0.148439, places = 5) 28 | 29 | def test_update(self): 30 | self.assertIndicatorUpdate(MACD(12, 26, 9, self.input_values)) 31 | 32 | def test_delete(self): 33 | self.assertIndicatorDelete(MACD(12, 26, 9, self.input_values)) 34 | 35 | def test_purge_oldest(self): 36 | self.assertIndicatorPurgeOldest(MACD(12, 26, 9, self.input_values)) 37 | 38 | 39 | if __name__ == '__main__': 40 | unittest.main() 41 | -------------------------------------------------------------------------------- /test/test_MassIndex.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import MassIndex 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = MassIndex(9, 9, 10, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 9.498975, places = 5) 18 | self.assertAlmostEqual(ind[-2], 9.537927, places = 5) 19 | self.assertAlmostEqual(ind[-1], 9.648128, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(MassIndex(9, 9, 10, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(MassIndex(9, 9, 10, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(MassIndex(9, 9, 10, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_McGinleyDynamic.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import McGinleyDynamic 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.CLOSE_TMPL) 11 | 12 | def test_init(self): 13 | ind = McGinleyDynamic(14, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 8.839868, places = 5) 18 | self.assertAlmostEqual(ind[-2], 8.895229, places = 5) 19 | self.assertAlmostEqual(ind[-1], 8.944634, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(McGinleyDynamic(14, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(McGinleyDynamic(14, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(McGinleyDynamic(14, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_MeanDev.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import MeanDev 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.CLOSE_TMPL) 11 | 12 | def test_init(self): 13 | ind = MeanDev(20, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 0.608949, places = 5) 18 | self.assertAlmostEqual(ind[-2], 0.595400, places = 5) 19 | self.assertAlmostEqual(ind[-1], 0.535500, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(MeanDev(20, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(MeanDev(20, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(MeanDev(20, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_NATR.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import NATR 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class TestATR(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = NATR(5, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 6.387410, places = 5) 18 | self.assertAlmostEqual(ind[-2], 6.501871, places = 5) 19 | self.assertAlmostEqual(ind[-1], 6.861131, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(NATR(5, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(NATR(5, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(NATR(5, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_OBV.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import OBV 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = OBV(self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 665.899999, places = 5) 18 | self.assertAlmostEqual(ind[-2], 617.609999, places = 5) 19 | self.assertAlmostEqual(ind[-1], 535.949999, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(OBV(self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(OBV(self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(OBV(self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_ParabolicSAR.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import ParabolicSAR 4 | from talipp.indicators.ParabolicSAR import SARTrend 5 | 6 | from TalippTest import TalippTest 7 | 8 | 9 | class TestBB(TalippTest): 10 | def setUp(self) -> None: 11 | self.input_values = list(TalippTest.OHLCV_TMPL) 12 | 13 | def test_init(self): 14 | ind = ParabolicSAR(0.02, 0.02, 0.2, self.input_values) 15 | 16 | print(ind) 17 | 18 | self.assertAlmostEqual(ind[-3].value, 8.075630, places = 5) 19 | self.assertAlmostEqual(ind[-3].trend, SARTrend.UP, places = 5) 20 | self.assertAlmostEqual(ind[-3].ep, 10.860000, places = 5) 21 | self.assertAlmostEqual(ind[-3].accel_factor, 0.060000, places = 5) 22 | 23 | self.assertAlmostEqual(ind[-2].value, 8.242693, places = 5) 24 | self.assertAlmostEqual(ind[-2].trend, SARTrend.UP, places = 5) 25 | self.assertAlmostEqual(ind[-2].ep, 10.860000, places = 5) 26 | self.assertAlmostEqual(ind[-2].accel_factor, 0.060000, places = 5) 27 | 28 | self.assertAlmostEqual(ind[-1].value, 8.399731, places = 5) 29 | self.assertAlmostEqual(ind[-1].trend, SARTrend.UP, places = 5) 30 | self.assertAlmostEqual(ind[-1].ep, 10.860000, places = 5) 31 | self.assertAlmostEqual(ind[-1].accel_factor, 0.060000, places = 5) 32 | 33 | def test_update(self): 34 | self.assertIndicatorUpdate(ParabolicSAR(0.02, 0.02, 0.2, self.input_values)) 35 | 36 | def test_delete(self): 37 | self.assertIndicatorDelete(ParabolicSAR(0.02, 0.02, 0.2, self.input_values)) 38 | 39 | def test_purge_oldest(self): 40 | self.assertIndicatorPurgeOldest(ParabolicSAR(0.02, 0.02, 0.2, self.input_values)) 41 | 42 | 43 | if __name__ == '__main__': 44 | unittest.main() 45 | -------------------------------------------------------------------------------- /test/test_ROC.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import ROC 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class TestEMA(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.CLOSE_TMPL) 11 | 12 | def test_init(self): 13 | ind = ROC(20, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 30.740740, places = 5) 18 | self.assertAlmostEqual(ind[-2], 26.608910, places = 5) 19 | self.assertAlmostEqual(ind[-1], 33.511348, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(ROC(3, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(ROC(3, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(ROC(3, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_RSI.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import RSI 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.CLOSE_TMPL) 11 | 12 | def test_init(self): 13 | ind = RSI(20, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 57.880437, places = 5) 18 | self.assertAlmostEqual(ind[-2], 55.153392, places = 5) 19 | self.assertAlmostEqual(ind[-1], 53.459494, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(RSI(10, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(RSI(10, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(RSI(10, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_RogersSatchel.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import RogersSatchell 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = RogersSatchell(9, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 0.036353, places = 5) 18 | self.assertAlmostEqual(ind[-2], 0.035992, places = 5) 19 | self.assertAlmostEqual(ind[-1], 0.040324, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(RogersSatchell(9, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(RogersSatchell(9, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(RogersSatchell(9, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_SFX.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import SFX 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = SFX(12, 12, 3, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3].atr, 0.689106, places = 5) 18 | self.assertAlmostEqual(ind[-3].std_dev, 0.572132, places = 5) 19 | self.assertAlmostEqual(ind[-3].ma_std_dev, 0.476715, places = 5) 20 | 21 | self.assertAlmostEqual(ind[-2].atr, 0.683347, places = 5) 22 | self.assertAlmostEqual(ind[-2].std_dev, 0.610239, places = 5) 23 | self.assertAlmostEqual(ind[-2].ma_std_dev, 0.551638, places = 5) 24 | 25 | self.assertAlmostEqual(ind[-1].atr, 0.690568, places = 5) 26 | self.assertAlmostEqual(ind[-1].std_dev, 0.619332, places = 5) 27 | self.assertAlmostEqual(ind[-1].ma_std_dev, 0.600567, places = 5) 28 | 29 | def test_update(self): 30 | self.assertIndicatorUpdate(SFX(12, 12, 3, self.input_values)) 31 | 32 | def test_delete(self): 33 | self.assertIndicatorDelete(SFX(12, 12, 3, self.input_values)) 34 | 35 | def test_purge_oldest(self): 36 | self.assertIndicatorPurgeOldest(SFX(12, 12, 3, self.input_values)) 37 | 38 | 39 | if __name__ == '__main__': 40 | unittest.main() 41 | -------------------------------------------------------------------------------- /test/test_SMA.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from TalippTest import TalippTest 4 | from talipp.indicators import SMA 5 | 6 | 7 | class Test(TalippTest): 8 | def setUp(self) -> None: 9 | self.input_values = list(TalippTest.CLOSE_TMPL) 10 | 11 | def test_init(self): 12 | ind = SMA(20, self.input_values) 13 | 14 | print(ind) 15 | 16 | self.assertAlmostEqual(ind[-3], 9.075500, places = 5) 17 | self.assertAlmostEqual(ind[-2], 9.183000, places = 5) 18 | self.assertAlmostEqual(ind[-1], 9.308500, places = 5) 19 | 20 | def test_update(self): 21 | self.assertIndicatorUpdate(SMA(20, self.input_values)) 22 | 23 | def test_delete(self): 24 | self.assertIndicatorDelete(SMA(20, self.input_values)) 25 | 26 | def test_purge_oldest(self): 27 | self.assertIndicatorPurgeOldest(SMA(20, self.input_values)) 28 | 29 | 30 | if __name__ == '__main__': 31 | unittest.main() 32 | -------------------------------------------------------------------------------- /test/test_SMMA.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import SMMA 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.CLOSE_TMPL) 11 | 12 | def test_init(self): 13 | ind = SMMA(20, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 9.149589, places = 5) 18 | self.assertAlmostEqual(ind[-2], 9.203610, places = 5) 19 | self.assertAlmostEqual(ind[-1], 9.243429, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(SMMA(20, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(SMMA(20, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(SMMA(20, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_SOBV.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import SOBV 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = SOBV(20, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 90.868499, places = 5) 18 | self.assertAlmostEqual(ind[-2], 139.166499, places = 5) 19 | self.assertAlmostEqual(ind[-1], 187.558499, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(SOBV(20, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(SOBV(20, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(SOBV(20, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_STC.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import STC 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.CLOSE_TMPL) 11 | 12 | def test_init(self): 13 | ind = STC(5, 10, 10, 3, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 55.067364, places = 5) 18 | self.assertAlmostEqual(ind[-2], 82.248999, places = 5) 19 | self.assertAlmostEqual(ind[-1], 94.229147, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(STC(5, 10, 10, 3, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(STC(5, 10, 10, 3, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(STC(5, 10, 10, 3, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_StdDev.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import StdDev 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.CLOSE_TMPL) 11 | 12 | def test_init(self): 13 | ind = StdDev(20, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 0.800377, places = 5) 18 | self.assertAlmostEqual(ind[-2], 0.803828, places = 5) 19 | self.assertAlmostEqual(ind[-1], 0.721424, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(StdDev(20, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(StdDev(20, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(StdDev(20, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_Stoch.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import Stoch 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = Stoch(14, 3, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3].k, 88.934426, places = 5) 18 | self.assertAlmostEqual(ind[-3].d, 88.344442, places = 5) 19 | 20 | self.assertAlmostEqual(ind[-2].k, 74.180327, places = 5) 21 | self.assertAlmostEqual(ind[-2].d, 84.499789, places = 5) 22 | 23 | self.assertAlmostEqual(ind[-1].k, 64.754098, places = 5) 24 | self.assertAlmostEqual(ind[-1].d, 75.956284, places = 5) 25 | 26 | def test_update(self): 27 | self.assertIndicatorUpdate(Stoch(14, 3, self.input_values)) 28 | 29 | def test_delete(self): 30 | self.assertIndicatorDelete(Stoch(14, 3, self.input_values)) 31 | 32 | def test_purge_oldest(self): 33 | self.assertIndicatorPurgeOldest(Stoch(14, 3, self.input_values)) 34 | 35 | 36 | if __name__ == '__main__': 37 | unittest.main() 38 | -------------------------------------------------------------------------------- /test/test_StochRSI.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import StochRSI 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.CLOSE_TMPL) 11 | 12 | def test_init(self): 13 | ind = StochRSI(14, 14, 3, 3, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3].k, 100.000000, places = 5) 18 | self.assertAlmostEqual(ind[-3].d, 82.573394, places = 5) 19 | 20 | self.assertAlmostEqual(ind[-2].k, 92.453271, places = 5) 21 | self.assertAlmostEqual(ind[-2].d, 92.500513, places = 5) 22 | 23 | self.assertAlmostEqual(ind[-1].k, 80.286409, places = 5) 24 | self.assertAlmostEqual(ind[-1].d, 90.913227, places = 5) 25 | 26 | def test_update(self): 27 | self.assertIndicatorUpdate(StochRSI(14, 14, 3, 3, self.input_values)) 28 | 29 | def test_delete(self): 30 | self.assertIndicatorDelete(StochRSI(14, 14, 3, 3, self.input_values)) 31 | 32 | def test_purge_oldest(self): 33 | self.assertIndicatorPurgeOldest(StochRSI(14, 14, 3, 3, self.input_values)) 34 | 35 | 36 | if __name__ == '__main__': 37 | unittest.main() 38 | -------------------------------------------------------------------------------- /test/test_SuperTrend.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import SuperTrend 4 | from talipp.indicators.SuperTrend import Trend 5 | 6 | 7 | from TalippTest import TalippTest 8 | 9 | 10 | class Test(TalippTest): 11 | def setUp(self) -> None: 12 | self.input_values = list(TalippTest.OHLCV_TMPL) 13 | 14 | def test_init(self): 15 | ind = SuperTrend(10, 3, self.input_values) 16 | 17 | print(ind) 18 | 19 | self.assertAlmostEqual(ind[-16].value, 9.711592, places = 5) 20 | self.assertAlmostEqual(ind[-16].trend, Trend.DOWN, places = 5) 21 | 22 | self.assertAlmostEqual(ind[-4].value, 8.110029, places = 5) 23 | self.assertAlmostEqual(ind[-4].trend, Trend.UP, places = 5) 24 | 25 | self.assertAlmostEqual(ind[-3].value, 8.488026, places = 5) 26 | self.assertAlmostEqual(ind[-3].trend, Trend.UP, places = 5) 27 | 28 | self.assertAlmostEqual(ind[-2].value, 8.488026, places = 5) 29 | self.assertAlmostEqual(ind[-2].trend, Trend.UP, places = 5) 30 | 31 | self.assertAlmostEqual(ind[-1].value, 8.488026, places = 5) 32 | self.assertAlmostEqual(ind[-1].trend, Trend.UP, places = 5) 33 | 34 | def test_update(self): 35 | self.assertIndicatorUpdate(SuperTrend(10, 3, self.input_values)) 36 | 37 | def test_delete(self): 38 | self.assertIndicatorDelete(SuperTrend(10, 3, self.input_values)) 39 | 40 | def test_purge_oldest(self): 41 | self.assertIndicatorPurgeOldest(SuperTrend(10, 3, self.input_values)) 42 | 43 | 44 | if __name__ == '__main__': 45 | unittest.main() 46 | -------------------------------------------------------------------------------- /test/test_T3.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from TalippTest import TalippTest 4 | from talipp.indicators import T3 5 | 6 | 7 | class Test(TalippTest): 8 | def setUp(self) -> None: 9 | self.input_values = list(TalippTest.CLOSE_TMPL) 10 | 11 | def test_init(self): 12 | ind = T3(5, 0.7, self.input_values) 13 | 14 | print(ind) 15 | 16 | self.assertAlmostEqual(ind[-3], 9.718661, places = 5) 17 | self.assertAlmostEqual(ind[-2], 9.968503, places = 5) 18 | self.assertAlmostEqual(ind[-1], 10.124616, places = 5) 19 | 20 | def test_update(self): 21 | self.assertIndicatorUpdate(T3(5, 0.7, self.input_values)) 22 | 23 | def test_delete(self): 24 | self.assertIndicatorDelete(T3(5, 0.7, self.input_values)) 25 | 26 | def test_purge_oldest(self): 27 | self.assertIndicatorPurgeOldest(T3(5, 0.7, self.input_values)) 28 | 29 | 30 | if __name__ == '__main__': 31 | unittest.main() 32 | -------------------------------------------------------------------------------- /test/test_TEMA.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import TEMA 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.CLOSE_TMPL) 11 | 12 | def test_init(self): 13 | ind = TEMA(10, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 10.330217, places = 5) 18 | self.assertAlmostEqual(ind[-2], 10.399910, places = 5) 19 | self.assertAlmostEqual(ind[-1], 10.323950, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(TEMA(10, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(TEMA(10, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(TEMA(10, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_TRIX.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import TRIX 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.CLOSE_TMPL) 11 | 12 | def test_init(self): 13 | ind = TRIX(10, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 66.062922, places = 5) 18 | self.assertAlmostEqual(ind[-2], 75.271366, places = 5) 19 | self.assertAlmostEqual(ind[-1], 80.317194, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(TRIX(10, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(TRIX(10, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(TRIX(10, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_TSI.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import TSI 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.CLOSE_TMPL) 11 | self.input_values_equal = list(TalippTest.CLOSE_EQUAL_VALUES_TMPL) 12 | 13 | def test_init(self): 14 | ind = TSI(14, 23, self.input_values) 15 | 16 | print(ind) 17 | 18 | self.assertAlmostEqual(ind[-3], 9.159520, places = 5) 19 | self.assertAlmostEqual(ind[-2], 10.724944, places = 5) 20 | self.assertAlmostEqual(ind[-1], 11.181863, places = 5) 21 | 22 | def test_init_equal(self): 23 | """ Check that if there is no price difference between two consecutive prices, the indicator does not crash""" 24 | ind = TSI(3, 5, self.input_values_equal) 25 | 26 | print(ind) 27 | 28 | self.assertSetEqual(set(ind), {None}) 29 | 30 | def test_update(self): 31 | self.assertIndicatorUpdate(TSI(14, 23, self.input_values)) 32 | 33 | def test_delete(self): 34 | self.assertIndicatorDelete(TSI(14, 23, self.input_values)) 35 | 36 | def test_purge_oldest(self): 37 | self.assertIndicatorPurgeOldest(TSI(14, 23, self.input_values)) 38 | 39 | 40 | if __name__ == '__main__': 41 | unittest.main() 42 | -------------------------------------------------------------------------------- /test/test_TTM.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import TTM 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = TTM(20, 2, 2, input_values = self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertTrue(ind[-12].squeeze) 18 | self.assertAlmostEqual(ind[-12].histogram, 0.778771, places = 5) 19 | 20 | self.assertFalse(ind[-3].squeeze) 21 | self.assertAlmostEqual(ind[-3].histogram, 1.135782, places = 5) 22 | 23 | self.assertFalse(ind[-2].squeeze) 24 | self.assertAlmostEqual(ind[-2].histogram, 1.136939, places = 5) 25 | 26 | self.assertFalse(ind[-1].squeeze) 27 | self.assertAlmostEqual(ind[-1].histogram, 1.036864, places = 5) 28 | 29 | def test_update(self): 30 | self.assertIndicatorUpdate(TTM(20, 2, 2, input_values = self.input_values)) 31 | 32 | def test_delete(self): 33 | self.assertIndicatorDelete(TTM(20, 2, 2, input_values = self.input_values)) 34 | 35 | def test_purge_oldest(self): 36 | self.assertIndicatorPurgeOldest(TTM(20, 2, 2, input_values = self.input_values)) 37 | 38 | 39 | if __name__ == '__main__': 40 | unittest.main() 41 | -------------------------------------------------------------------------------- /test/test_UO.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import UO 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class TestAO(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = UO(3, 5, 7, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 67.574669, places = 5) 18 | self.assertAlmostEqual(ind[-2], 54.423675, places = 5) 19 | self.assertAlmostEqual(ind[-1], 47.901125, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(UO(3, 5, 7, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(UO(3, 5, 7, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(UO(3, 5, 7, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_VTX.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import VTX 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = VTX(14, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3].plus_vtx, 1.133113, places = 5) 18 | self.assertAlmostEqual(ind[-3].minus_vtx, 0.818481, places = 5) 19 | 20 | self.assertAlmostEqual(ind[-2].plus_vtx, 1.141292, places = 5) 21 | self.assertAlmostEqual(ind[-2].minus_vtx, 0.834611, places = 5) 22 | 23 | self.assertAlmostEqual(ind[-1].plus_vtx, 1.030133, places = 5) 24 | self.assertAlmostEqual(ind[-1].minus_vtx, 0.968750, places = 5) 25 | 26 | def test_update(self): 27 | self.assertIndicatorUpdate(VTX(14, self.input_values)) 28 | 29 | def test_delete(self): 30 | self.assertIndicatorDelete(VTX(14, self.input_values)) 31 | 32 | def test_purge_oldest(self): 33 | self.assertIndicatorPurgeOldest(VTX(14, self.input_values)) 34 | 35 | 36 | if __name__ == '__main__': 37 | unittest.main() 38 | -------------------------------------------------------------------------------- /test/test_VWAP.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import VWAP 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = VWAP(self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[0], 10.47333, places = 5) 18 | self.assertAlmostEqual(ind[1], 10.21883, places = 5) 19 | self.assertAlmostEqual(ind[2], 10.20899, places = 5) 20 | self.assertAlmostEqual(ind[-3], 9.125770, places = 5) 21 | self.assertAlmostEqual(ind[-2], 9.136613, places = 5) 22 | self.assertAlmostEqual(ind[-1], 9.149069, places = 5) 23 | 24 | def test_update(self): 25 | self.assertIndicatorUpdate(VWAP(self.input_values)) 26 | 27 | def test_delete(self): 28 | self.assertIndicatorDelete(VWAP(self.input_values)) 29 | 30 | def test_purge_oldest(self): 31 | self.assertIndicatorPurgeOldest(VWAP(self.input_values)) 32 | 33 | 34 | if __name__ == '__main__': 35 | unittest.main() 36 | -------------------------------------------------------------------------------- /test/test_VWMA.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import VWMA 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.OHLCV_TMPL) 11 | 12 | def test_init(self): 13 | ind = VWMA(20, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 9.320203, places = 5) 18 | self.assertAlmostEqual(ind[-2], 9.352602, places = 5) 19 | self.assertAlmostEqual(ind[-1], 9.457708, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(VWMA(20, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(VWMA(20, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(VWMA(20, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_WMA.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.indicators import WMA 4 | 5 | from TalippTest import TalippTest 6 | 7 | 8 | class Test(TalippTest): 9 | def setUp(self) -> None: 10 | self.input_values = list(TalippTest.CLOSE_TMPL) 11 | 12 | def test_init(self): 13 | ind = WMA(20, self.input_values) 14 | 15 | print(ind) 16 | 17 | self.assertAlmostEqual(ind[-3], 9.417523, places = 5) 18 | self.assertAlmostEqual(ind[-2], 9.527476, places = 5) 19 | self.assertAlmostEqual(ind[-1], 9.605285, places = 5) 20 | 21 | def test_update(self): 22 | self.assertIndicatorUpdate(WMA(20, self.input_values)) 23 | 24 | def test_delete(self): 25 | self.assertIndicatorDelete(WMA(20, self.input_values)) 26 | 27 | def test_purge_oldest(self): 28 | self.assertIndicatorPurgeOldest(WMA(20, self.input_values)) 29 | 30 | 31 | if __name__ == '__main__': 32 | unittest.main() 33 | -------------------------------------------------------------------------------- /test/test_ZLEMA.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from TalippTest import TalippTest 4 | from talipp.indicators import ZLEMA 5 | 6 | 7 | class Test(TalippTest): 8 | def setUp(self) -> None: 9 | self.input_values = list(TalippTest.CLOSE_TMPL) 10 | 11 | def test_init(self): 12 | ind = ZLEMA(20, self.input_values) 13 | 14 | print(ind) 15 | 16 | self.assertAlmostEqual(ind[-3], 9.738243, places = 5) 17 | self.assertAlmostEqual(ind[-2], 9.871744, places = 5) 18 | self.assertAlmostEqual(ind[-1], 9.975387, places = 5) 19 | 20 | def test_update(self): 21 | self.assertIndicatorUpdate(ZLEMA(20, self.input_values)) 22 | 23 | def test_delete(self): 24 | self.assertIndicatorDelete(ZLEMA(20, self.input_values)) 25 | 26 | def test_purge_oldest(self): 27 | self.assertIndicatorPurgeOldest(ZLEMA(20, self.input_values)) 28 | 29 | 30 | if __name__ == '__main__': 31 | unittest.main() 32 | -------------------------------------------------------------------------------- /test/test_ZigZag.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from TalippTest import TalippTest 4 | from talipp.exceptions import TalippException 5 | from talipp.indicators import ZigZag 6 | from talipp.indicators.ZigZag import PivotType 7 | from talipp.ohlcv import OHLCV 8 | 9 | 10 | class Test(TalippTest): 11 | def setUp(self) -> None: 12 | self.input_values = list(TalippTest.OHLCV_TMPL) 13 | 14 | def test_init(self): 15 | ind = ZigZag(0.05, 3, self.input_values) 16 | 17 | print(ind) 18 | 19 | self.assertEqual(ind[-3].type, PivotType.HIGH) 20 | self.assertEqual(ind[-3].ohlcv, OHLCV(open=9.16, high=10.1, low=9.16, close=9.76, volume=199.2, time=None)) 21 | 22 | self.assertEqual(ind[-2].type, PivotType.LOW) 23 | self.assertEqual(ind[-2].ohlcv, OHLCV(open=9.18, high=9.32, low=8.6, close=9.32, volume=29.73, time=None)) 24 | 25 | self.assertEqual(ind[-1].type, PivotType.HIGH) 26 | self.assertEqual(ind[-1].ohlcv, OHLCV(open=10.29, high=10.86, low=10.19, close=10.59, volume=108.27, time=None)) 27 | 28 | def test_update(self): 29 | zigzag = ZigZag(0.5, 5, self.input_values) 30 | 31 | with self.assertRaises(TalippException) as e: 32 | zigzag.update(1) 33 | 34 | print(e.exception) 35 | self.assertTrue( 36 | 'Operation not supported.' in e.exception.args[0]) 37 | 38 | def test_delete(self): 39 | zigzag = ZigZag(0.5, 5, self.input_values) 40 | 41 | with self.assertRaises(TalippException) as e: 42 | zigzag.remove() 43 | 44 | print(e.exception) 45 | self.assertTrue( 46 | 'Operation not supported.' in e.exception.args[0]) 47 | 48 | def test_purge_oldest(self): 49 | zigzag = ZigZag(0.5, 5, self.input_values) 50 | 51 | with self.assertRaises(TalippException) as e: 52 | zigzag.purge_oldest(1) 53 | 54 | print(e.exception) 55 | self.assertTrue( 56 | 'Operation not supported.' in e.exception.args[0]) 57 | 58 | 59 | if __name__ == '__main__': 60 | unittest.main() 61 | -------------------------------------------------------------------------------- /test/test_indicator_sampling.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from datetime import datetime 3 | 4 | from TalippTest import TalippTest 5 | from talipp.indicators import OBV 6 | from talipp.input import SamplingPeriodType 7 | from talipp.ohlcv import OHLCV 8 | 9 | 10 | class Test(TalippTest): 11 | def test_sampling(self): 12 | obv = OBV(input_sampling=SamplingPeriodType.SEC_1) 13 | dt = datetime(2024, 1, 1, 0, 0, 0) 14 | 15 | obv.add(OHLCV(1, 1, 1, 1, 1, dt)) 16 | self.assertEqual(len(obv), 1) 17 | 18 | dt = dt.replace(second=1) 19 | obv.add(OHLCV(1, 1, 1, 2, 2, dt)) 20 | self.assertEqual(len(obv), 2) 21 | self.assertEqual(obv[-1], 3) 22 | 23 | dt = dt.replace(microsecond=1) 24 | obv.add(OHLCV(1, 1, 1, 3, 3, dt)) 25 | self.assertEqual(len(obv), 2) 26 | self.assertEqual(obv[-1], 4) 27 | 28 | dt = dt.replace(microsecond=2) 29 | obv.add(OHLCV(1, 1, 1, 4, 4, dt)) 30 | self.assertEqual(len(obv), 2) 31 | self.assertEqual(obv[-1], 5) 32 | 33 | dt = dt.replace(second=2) 34 | obv.add(OHLCV(1, 1, 1, 5, 5, dt)) 35 | self.assertEqual(len(obv), 3) 36 | self.assertEqual(obv[-2], 5) 37 | self.assertEqual(obv[-1], 10) 38 | 39 | 40 | if __name__ == '__main__': 41 | unittest.main() 42 | -------------------------------------------------------------------------------- /test/test_indicator_util.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from talipp.exceptions import TalippException 4 | from talipp.indicator_util import composite_to_lists, has_valid_values, previous_if_exists 5 | from talipp.indicators import BB, SMA 6 | 7 | 8 | class Test(unittest.TestCase): 9 | def test_to_list(self): 10 | bb = BB(3, 2, [1, 2, 3, 4, 5]) 11 | bb_lists = composite_to_lists(bb) 12 | 13 | print(bb_lists) 14 | 15 | self.assertTrue('lb' in bb_lists) 16 | self.assertTrue('cb' in bb_lists) 17 | self.assertTrue('ub' in bb_lists) 18 | 19 | self.assertEqual(len(bb_lists['lb']), 5) 20 | self.assertEqual(len(bb_lists['cb']), 5) 21 | self.assertEqual(len(bb_lists['ub']), 5) 22 | 23 | self.assertListEqual(bb_lists['cb'], [None, None, 2.0, 3.0, 4.0]) 24 | 25 | def test_to_list_simple_type(self): 26 | sma = SMA(3, [1, 2, 3, 4, 5]) 27 | 28 | with self.assertRaises(TalippException) as e: 29 | composite_to_lists(sma) 30 | 31 | print(e.exception) 32 | self.assertTrue('composite_to_lists(...) method can be used only with indicators returning composite output values, ' 33 | 'this indicator returns' in e.exception.args[0]) 34 | 35 | def test_to_list_empty(self): 36 | bb = BB(3, 2) 37 | bb_lists = composite_to_lists(bb) 38 | 39 | print(bb_lists) 40 | 41 | self.assertDictEqual(bb_lists, {}) 42 | 43 | def test_has_valid_values(self): 44 | self.assertTrue(has_valid_values([1], 1)) 45 | self.assertTrue(has_valid_values([1, 2], 1)) 46 | 47 | self.assertTrue(has_valid_values([1], 1, exact=True)) 48 | self.assertFalse(has_valid_values([1, 2], 1, exact=True)) 49 | self.assertFalse(has_valid_values([], 1, exact=True)) 50 | self.assertFalse(has_valid_values([None], 1, exact=True)) 51 | self.assertFalse(has_valid_values([1, None], 1, exact=True)) 52 | 53 | self.assertFalse(has_valid_values([], 1)) 54 | self.assertFalse(has_valid_values([None], 1)) 55 | self.assertFalse(has_valid_values([1, None], 1)) 56 | 57 | def test_previous_if_exists(self): 58 | self.assertEqual(previous_if_exists([]), 0) 59 | self.assertEqual(previous_if_exists([], default=1), 1) 60 | self.assertEqual(previous_if_exists([1]), 1) 61 | self.assertEqual(previous_if_exists([1], index=-2), 0) 62 | self.assertEqual(previous_if_exists([1,2], index=-2), 1) 63 | 64 | 65 | if __name__ == '__main__': 66 | unittest.main() 67 | --------------------------------------------------------------------------------