From f0e2ea37e1aa01964f68dcbf7ce849b769542345 Mon Sep 17 00:00:00 2001 From: Bukosabino Date: Sun, 3 May 2020 14:00:41 +0200 Subject: [PATCH 1/2] improve setup syntax --- setup.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/setup.py b/setup.py index 0b77f3e8..02dac610 100644 --- a/setup.py +++ b/setup.py @@ -1,30 +1,31 @@ # -*- coding: utf-8 -*- from distutils.core import setup + setup( - name = 'ta', - packages = ['ta'], - version = '0.5.21', + name='ta', + packages=['ta'], + version='0.5.21', description='Technical Analysis Library in Python', long_description='It is a Technical Analysis library to financial time series datasets. You can use to do feature engineering. It is builded on Python Pandas library.', - author = 'Dario Lopez Padial (Bukosabino)', - author_email = 'Bukosabino@gmail.com', - url = 'https://github.com/bukosabino/ta', + author='Dario Lopez Padial (Bukosabino)', + author_email='Bukosabino@gmail.com', + url='https://github.com/bukosabino/ta', maintainer='Dario Lopez Padial (Bukosabino)', maintainer_email='Bukosabino@gmail.com', install_requires=[ 'numpy', 'pandas', ], - download_url = 'https://github.com/bukosabino/ta/tarball/0.5.21', - keywords = ['technical analysis', 'python3', 'pandas'], + download_url='https://github.com/bukosabino/ta/tarball/0.5.21', + keywords=['technical analysis', 'python3', 'pandas'], license='The MIT License (MIT)', - classifiers = [ + classifiers=[ 'Intended Audience :: Financial and Insurance Industry', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'License :: OSI Approved :: MIT License' ], - project_urls = { + project_urls={ 'Documentation': 'https://technical-analysis-library-in-python.readthedocs.io/en/latest/', 'Bug Reports': 'https://github.com/bukosabino/ta/issues', 'Source': 'https://github.com/bukosabino/ta', From fd2d368ae455e0e8d4ccc3d3eb44aed5d25d19b8 Mon Sep 17 00:00:00 2001 From: Bukosabino Date: Sun, 3 May 2020 23:43:41 +0200 Subject: [PATCH 2/2] Keltner Channel: adding tests; adding n atr input parametr; fixing some minor bug; adding unittests for adx --- ta/tests/__init__.py | 5 +- ta/tests/data/cs-atr.csv | 62 ++++++------- ta/tests/data/cs-atr2.csv | 31 +++++++ ta/tests/data/cs-kc.csv | 31 +++++++ ta/tests/volatility.py | 190 ++++++++++++++++++++++++++++++++++++-- ta/volatility.py | 83 +++++++++++------ 6 files changed, 336 insertions(+), 66 deletions(-) create mode 100644 ta/tests/data/cs-atr2.csv create mode 100644 ta/tests/data/cs-kc.csv diff --git a/ta/tests/__init__.py b/ta/tests/__init__.py index 43e60f85..2870d144 100644 --- a/ta/tests/__init__.py +++ b/ta/tests/__init__.py @@ -6,8 +6,9 @@ TestMACDIndicator, TestPSARIndicator, TestVortexIndicator) from ta.tests.utils import TestGeneral -from ta.tests.volatility import (TestAverageTrueRange, TestBollingerBands, - TestDonchianChannel) +from ta.tests.volatility import (TestAverageTrueRange, TestAverageTrueRange2, + TestBollingerBands, TestDonchianChannel, + TestKeltnerChannel) from ta.tests.volume import (TestAccDistIndexIndicator, TestEaseOfMovementIndicator, TestForceIndexIndicator, TestMFIIndicator, diff --git a/ta/tests/data/cs-atr.csv b/ta/tests/data/cs-atr.csv index c534c80f..927fc8a2 100644 --- a/ta/tests/data/cs-atr.csv +++ b/ta/tests/data/cs-atr.csv @@ -1,31 +1,31 @@ -Date,High,Low,Close,H - L,I H - Cp I,I L - Cp I,TR,ATR -01-Apr-10,48.700000,47.790000,48.160000,0.910000,,,0.910000, -05-Apr-10,48.720000,48.140000,48.610000,0.580000,0.560000,0.020000,0.580000, -06-Apr-10,48.900000,48.390000,48.750000,0.510000,0.290000,0.220000,0.510000, -07-Apr-10,48.870000,48.370000,48.630000,0.500000,0.120000,0.380000,0.500000, -08-Apr-10,48.820000,48.240000,48.740000,0.580000,0.190000,0.390000,0.580000, -09-Apr-10,49.050000,48.635000,49.030000,0.415000,0.310000,0.105000,0.415000, -12-Apr-10,49.200000,48.940000,49.070000,0.260000,0.170000,0.090000,0.260000, -13-Apr-10,49.350000,48.860000,49.320000,0.490000,0.280000,0.210000,0.490000, -14-Apr-10,49.920000,49.500000,49.910000,0.420000,0.600000,0.180000,0.600000, -15-Apr-10,50.190000,49.870000,50.130000,0.320000,0.280000,0.040000,0.320000, -16-Apr-10,50.120000,49.200000,49.530000,0.920000,0.010000,0.930000,0.930000, -19-Apr-10,49.660000,48.900000,49.500000,0.760000,0.130000,0.630000,0.760000, -20-Apr-10,49.880000,49.430000,49.750000,0.450000,0.380000,0.070000,0.450000, -21-Apr-10,50.190000,49.725000,50.030000,0.465000,0.440000,0.025000,0.465000,0.555000 -22-Apr-10,50.360000,49.260000,50.310000,1.100000,0.330000,0.770000,1.100000,0.593929 -23-Apr-10,50.570000,50.090000,50.520000,0.480000,0.260000,0.220000,0.480000,0.585791 -26-Apr-10,50.650000,50.300000,50.410000,0.350000,0.130000,0.220000,0.350000,0.568949 -27-Apr-10,50.430000,49.210000,49.340000,1.220000,0.020000,1.200000,1.220000,0.615452 -28-Apr-10,49.630000,48.980000,49.370000,0.650000,0.290000,0.360000,0.650000,0.617920 -29-Apr-10,50.330000,49.610000,50.230000,0.720000,0.960000,0.240000,0.960000,0.642354 -30-Apr-10,50.290000,49.200000,49.237500,1.090000,0.060000,1.030000,1.090000,0.674329 -03-May-10,50.170000,49.430000,49.930000,0.740000,0.932500,0.192500,0.932500,0.692770 -04-May-10,49.320000,48.080000,48.430000,1.240000,0.610000,1.850000,1.850000,0.775429 -05-May-10,48.500000,47.640000,48.180000,0.860000,0.070000,0.790000,0.860000,0.781470 -06-May-10,48.320100,41.550000,46.570000,6.770100,0.140100,6.630000,6.770100,1.209229 -07-May-10,46.800000,44.283300,45.410000,2.516700,0.230000,2.286700,2.516700,1.302620 -10-May-10,47.800000,47.310000,47.770000,0.490000,2.390000,1.900000,2.390000,1.380290 -11-May-10,48.390000,47.200000,47.720000,1.190000,0.620000,0.570000,1.190000,1.366698 -12-May-10,48.660000,47.900000,48.620000,0.760000,0.940000,0.180000,0.940000,1.336219 -13-May-10,48.790000,47.730100,47.850000,1.059900,0.170000,0.889900,1.059900,1.316482 +Date,High,Low,Close,TR,ATR +01-Apr-10,48.700000000000000,47.790000000000000,48.160000000000000,0.910000000000004,0.000000000000000 +05-Apr-10,48.720000000000000,48.140000000000000,48.610000000000000,0.579999999999998,0.000000000000000 +06-Apr-10,48.900000000000000,48.390000000000000,48.750000000000000,0.509999999999998,0.000000000000000 +07-Apr-10,48.870000000000000,48.370000000000000,48.630000000000000,0.500000000000000,0.000000000000000 +08-Apr-10,48.820000000000000,48.240000000000000,48.740000000000000,0.579999999999998,0.000000000000000 +09-Apr-10,49.050000000000000,48.635000000000000,49.030000000000000,0.414999999999999,0.000000000000000 +12-Apr-10,49.200000000000000,48.940000000000000,49.070000000000000,0.260000000000005,0.000000000000000 +13-Apr-10,49.350000000000000,48.860000000000000,49.320000000000000,0.490000000000002,0.000000000000000 +14-Apr-10,49.920000000000000,49.500000000000000,49.910000000000000,0.600000000000001,0.000000000000000 +15-Apr-10,50.190000000000000,49.870000000000000,50.130000000000000,0.320000000000000,0.000000000000000 +16-Apr-10,50.120000000000000,49.200000000000000,49.530000000000000,0.930000000000000,0.000000000000000 +19-Apr-10,49.660000000000000,48.900000000000000,49.500000000000000,0.759999999999998,0.000000000000000 +20-Apr-10,49.880000000000000,49.430000000000000,49.750000000000000,0.450000000000003,0.000000000000000 +21-Apr-10,50.190000000000000,49.725000000000000,50.030000000000000,0.464999999999996,0.555000000000000 +22-Apr-10,50.360000000000000,49.260000000000000,50.310000000000000,1.100000000000000,0.5939285714 +23-Apr-10,50.570000000000000,50.090000000000000,50.520000000000000,0.479999999999997,0.5857908163 +26-Apr-10,50.650000000000000,50.300000000000000,50.410000000000000,0.350000000000001,0.5689486152 +27-Apr-10,50.430000000000000,49.210000000000000,49.340000000000000,1.220000000000000,0.6154522855 +28-Apr-10,49.630000000000000,48.980000000000000,49.370000000000000,0.650000000000006,0.6179199794 +29-Apr-10,50.330000000000000,49.610000000000000,50.230000000000000,0.960000000000001,0.6423542666 +30-Apr-10,50.290000000000000,49.200000000000000,49.237500000000000,1.090000000000000,0.6743289618 +03-May-10,50.170000000000000,49.430000000000000,49.930000000000000,0.932500000000005,0.6927697503 +04-May-10,49.320000000000000,48.080000000000000,48.430000000000000,1.850000000000000,0.7754290538 +05-May-10,48.500000000000000,47.640000000000000,48.180000000000000,0.859999999999999,0.7814698357 +06-May-10,48.320100000000000,41.550000000000000,46.570000000000000,6.770100000000000,1.209229133 +07-May-10,46.800000000000000,44.283300000000000,45.410000000000000,2.516700000000000,1.302619909 +10-May-10,47.800000000000000,47.310000000000000,47.770000000000000,2.390000000000000,1.380289916 +11-May-10,48.390000000000000,47.200000000000000,47.720000000000000,1.190000000000000,1.366697779 +12-May-10,48.660000000000000,47.900000000000000,48.620000000000000,0.939999999999998,1.336219366 +13-May-10,48.790000000000000,47.730100000000000,47.850000000000000,1.059900000000000,1.316482269 \ No newline at end of file diff --git a/ta/tests/data/cs-atr2.csv b/ta/tests/data/cs-atr2.csv new file mode 100644 index 00000000..b1b0b492 --- /dev/null +++ b/ta/tests/data/cs-atr2.csv @@ -0,0 +1,31 @@ +Date,High,Low,Close,TR,ATR +01-Apr-10,48.700000000000000,47.790000000000000,48.160000000000000,0.910000000000004,0.000000000000000 +05-Apr-10,48.720000000000000,48.140000000000000,48.610000000000000,0.579999999999998,0.000000000000000 +06-Apr-10,48.900000000000000,48.390000000000000,48.750000000000000,0.509999999999998,0.000000000000000 +07-Apr-10,48.870000000000000,48.370000000000000,48.630000000000000,0.500000000000000,0.000000000000000 +08-Apr-10,48.820000000000000,48.240000000000000,48.740000000000000,0.579999999999998,0.000000000000000 +09-Apr-10,49.050000000000000,48.635000000000000,49.030000000000000,0.414999999999999,0.000000000000000 +12-Apr-10,49.200000000000000,48.940000000000000,49.070000000000000,0.260000000000005,0.000000000000000 +13-Apr-10,49.350000000000000,48.860000000000000,49.320000000000000,0.490000000000002,0.000000000000000 +14-Apr-10,49.920000000000000,49.500000000000000,49.910000000000000,0.600000000000001,0.000000000000000 +15-Apr-10,50.190000000000000,49.870000000000000,50.130000000000000,0.320000000000000,0.516500000000001 +16-Apr-10,50.120000000000000,49.200000000000000,49.530000000000000,0.930000000000000,0.557850000000001 +19-Apr-10,49.660000000000000,48.900000000000000,49.500000000000000,0.759999999999998,0.578065000000000 +20-Apr-10,49.880000000000000,49.430000000000000,49.750000000000000,0.450000000000003,0.565258500000001 +21-Apr-10,50.190000000000000,49.725000000000000,50.030000000000000,0.464999999999996,0.555232650000000 +22-Apr-10,50.360000000000000,49.260000000000000,50.310000000000000,1.100000000000000,0.609709385000000 +23-Apr-10,50.570000000000000,50.090000000000000,50.520000000000000,0.479999999999997,0.596738446500000 +26-Apr-10,50.650000000000000,50.300000000000000,50.410000000000000,0.350000000000001,0.572064601850000 +27-Apr-10,50.430000000000000,49.210000000000000,49.340000000000000,1.220000000000000,0.636858141665000 +28-Apr-10,49.630000000000000,48.980000000000000,49.370000000000000,0.650000000000006,0.638172327498501 +29-Apr-10,50.330000000000000,49.610000000000000,50.230000000000000,0.960000000000001,0.670355094748651 +30-Apr-10,50.290000000000000,49.200000000000000,49.237500000000000,1.090000000000000,0.712319585273785 +03-May-10,50.170000000000000,49.430000000000000,49.930000000000000,0.932500000000005,0.734337626746407 +04-May-10,49.320000000000000,48.080000000000000,48.430000000000000,1.850000000000000,0.845903864071767 +05-May-10,48.500000000000000,47.640000000000000,48.180000000000000,0.859999999999999,0.847313477664590 +06-May-10,48.320100000000000,41.550000000000000,46.570000000000000,6.770100000000000,1.439592129898130 +07-May-10,46.800000000000000,44.283300000000000,45.410000000000000,2.516700000000000,1.547302916908320 +10-May-10,47.800000000000000,47.310000000000000,47.770000000000000,2.390000000000000,1.631572625217490 +11-May-10,48.390000000000000,47.200000000000000,47.720000000000000,1.190000000000000,1.587415362695740 +12-May-10,48.660000000000000,47.900000000000000,48.620000000000000,0.939999999999998,1.522673826426160 +13-May-10,48.790000000000000,47.730100000000000,47.850000000000000,1.059900000000000,1.476396443783550 \ No newline at end of file diff --git a/ta/tests/data/cs-kc.csv b/ta/tests/data/cs-kc.csv new file mode 100644 index 00000000..735fae49 --- /dev/null +++ b/ta/tests/data/cs-kc.csv @@ -0,0 +1,31 @@ +date,High,Low,Close,true_range,atr,upper_band,middle_band,lower_band,kc_high_indicator,kc_low_indicator,kc_band_width,kc_percentage +01-Apr-10,48.700000000000000,47.790000000000000,48.160000000000000,0.910000000000004,0.000000000000000,,48.160000000000000,,,,, +05-Apr-10,48.720000000000000,48.140000000000000,48.610000000000000,0.579999999999998,0.000000000000000,,48.202857142857100,,,,, +06-Apr-10,48.900000000000000,48.390000000000000,48.750000000000000,0.509999999999998,0.000000000000000,,48.254965986394600,,,,, +07-Apr-10,48.870000000000000,48.370000000000000,48.630000000000000,0.500000000000000,0.000000000000000,,48.290683511499800,,,,, +08-Apr-10,48.820000000000000,48.240000000000000,48.740000000000000,0.579999999999998,0.000000000000000,,48.333475558023700,,,,, +09-Apr-10,49.050000000000000,48.635000000000000,49.030000000000000,0.414999999999999,0.000000000000000,,48.399811219164300,,,,, +12-Apr-10,49.200000000000000,48.940000000000000,49.070000000000000,0.260000000000005,0.000000000000000,,48.463638722101000,,,,, +13-Apr-10,49.350000000000000,48.860000000000000,49.320000000000000,0.490000000000002,0.000000000000000,,48.545196939043800,,,,, +14-Apr-10,49.920000000000000,49.500000000000000,49.910000000000000,0.600000000000001,0.000000000000000,,48.675178182944400,,,,, +15-Apr-10,50.190000000000000,49.870000000000000,50.130000000000000,0.320000000000000,0.516500000000001,49.846732641711600,48.813732641711600,47.780732641711600,1.00,0.00,4.232415528,1.13710908 +16-Apr-10,50.120000000000000,49.200000000000000,49.530000000000000,0.930000000000000,0.557850000000001,49.997648580596200,48.881948580596200,47.766248580596200,0.00,0.00,4.564875306,0.7904236889 +19-Apr-10,49.660000000000000,48.900000000000000,49.500000000000000,0.759999999999998,0.578065000000000,50.096940620539400,48.940810620539400,47.784680620539400,0.00,0.00,4.724605029,0.7418367223 +20-Apr-10,49.880000000000000,49.430000000000000,49.750000000000000,0.450000000000003,0.565258500000001,50.148393275726100,49.017876275726100,47.887359275726100,0.00,0.00,4.612672298,0.8238004047 +21-Apr-10,50.190000000000000,49.725000000000000,50.030000000000000,0.464999999999996,0.555232650000000,50.224734311371300,49.114269011371300,48.003803711371300,0.00,0.00,4.52196611,0.9123185968 +22-Apr-10,50.360000000000000,49.260000000000000,50.310000000000000,1.100000000000000,0.609709385000000,50.447566923145400,49.228148153145400,48.008729383145400,0.00,0.00,4.954152515,0.9435932403 +23-Apr-10,50.570000000000000,50.090000000000000,50.520000000000000,0.479999999999997,0.596738446500000,50.544658555369700,49.351181662369700,48.157704769369700,0.00,0.00,4.836669975,0.9896694458 +26-Apr-10,50.650000000000000,50.300000000000000,50.410000000000000,0.350000000000001,0.572064601850000,50.596150707748800,49.452021504048800,48.307892300348800,0.00,0.00,4.627229257,0.9186496127 +27-Apr-10,50.430000000000000,49.210000000000000,49.340000000000000,1.220000000000000,0.636858141665000,50.715069072707500,49.441352789377500,48.167636506047400,0.00,0.00,5.15243298,0.4602137498 +28-Apr-10,49.630000000000000,48.980000000000000,49.370000000000000,0.650000000000006,0.638172327498501,50.710901940624200,49.434557285627200,48.158212630630200,0.00,0.00,5.163774999,0.4747100889 +29-Apr-10,50.330000000000000,49.610000000000000,50.230000000000000,0.960000000000001,0.670355094748651,50.851023924112400,49.510313734615100,48.169603545117800,0.00,0.00,5.415882423,0.7683974027 +30-Apr-10,50.290000000000000,49.200000000000000,49.237500000000000,1.090000000000000,0.712319585273785,50.908970644723100,49.484331474175600,48.059692303628000,0.00,0.00,5.757940456,0.4133705294 +03-May-10,50.170000000000000,49.430000000000000,49.930000000000000,0.932500000000005,0.734337626746407,50.995451349175500,49.526776095682700,48.058100842189800,0.00,0.00,5.930833255,0.6372746982 +04-May-10,49.320000000000000,48.080000000000000,48.430000000000000,1.850000000000000,0.845903864071767,51.114128957570700,49.422321229427200,47.730513501283600,0.00,0.00,6.846330508,0.2067275397 +05-May-10,48.500000000000000,47.640000000000000,48.180000000000000,0.859999999999999,0.847313477664590,50.998631877191800,49.304004921862700,47.609377966533500,0.00,0.00,6.874195952,0.1683621377 +06-May-10,48.320100000000000,41.550000000000000,46.570000000000000,6.770100000000000,1.439592129898130,51.922807760529100,49.043623500732900,46.164439240936600,0.00,0.00,11.74131948,0.07042980276 +07-May-10,46.800000000000000,44.283300000000000,45.410000000000000,2.516700000000000,1.547302916908320,51.792169953527300,48.697564119710700,45.602958285894100,0.00,1.00,12.70948923,-0.03117655305 +10-May-10,47.800000000000000,47.310000000000000,47.770000000000000,2.390000000000000,1.631572625217490,51.872369930173200,48.609224679738300,45.346079429303300,0.00,0.00,13.42603291,0.3714086234 +11-May-10,48.390000000000000,47.200000000000000,47.720000000000000,1.190000000000000,1.587415362695740,51.699367340392800,48.524536615001300,45.349705889609800,0.00,0.00,13.0854654,0.3732945652 +12-May-10,48.660000000000000,47.900000000000000,48.620000000000000,0.939999999999998,1.522673826426160,51.578976018805900,48.533628365953500,45.488280713101200,0.00,0.00,12.54943327,0.5141809153 +13-May-10,48.790000000000000,47.730100000000000,47.850000000000000,1.059900000000000,1.476396443783550,51.421313790096500,48.468520902529400,45.515728014962300,0.00,0.00,12.18437383,0.3952651056 \ No newline at end of file diff --git a/ta/tests/volatility.py b/ta/tests/volatility.py index f0314aab..a58ec82f 100644 --- a/ta/tests/volatility.py +++ b/ta/tests/volatility.py @@ -4,17 +4,24 @@ from ta.tests.utils import TestIndicator from ta.volatility import (AverageTrueRange, BollingerBands, DonchianChannel, - average_true_range, donchian_channel_hband, + KeltnerChannel, average_true_range, + donchian_channel_hband, donchian_channel_hband_indicator, donchian_channel_lband, donchian_channel_lband_indicator, donchian_channel_mband, donchian_channel_pband, - donchian_channel_wband) + donchian_channel_wband, keltner_channel_hband, + keltner_channel_hband_indicator, + keltner_channel_lband, + keltner_channel_lband_indicator, + keltner_channel_mband, keltner_channel_pband, + keltner_channel_wband) class TestAverageTrueRange(TestIndicator): """ https://school.stockcharts.com/doku.php?id=technical_indicators:average_true_range_atr + https://docs.google.com/spreadsheets/d/1DYG5NI_1px30aZ6oJkDIkWsyJW5V8jGbBVKIr9NWtec/edit?usp=sharing """ _filename = 'ta/tests/data/cs-atr.csv' @@ -33,6 +40,28 @@ def test_atr2(self): pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) +class TestAverageTrueRange2(TestIndicator): + """ + https://school.stockcharts.com/doku.php?id=technical_indicators:average_true_range_atr + https://docs.google.com/spreadsheets/d/1IRlmwVmRLAzjIIt2iXBukZyyaSAYB_0iRyAoOowZaBk/edit?usp=sharing + """ + + _filename = 'ta/tests/data/cs-atr2.csv' + + def test_atr(self): + target = 'ATR' + result = AverageTrueRange( + high=self._df['High'], low=self._df['Low'], close=self._df['Close'], n=10, + fillna=False).average_true_range() + pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) + + def test_atr2(self): + target = 'ATR' + result = average_true_range( + high=self._df['High'], low=self._df['Low'], close=self._df['Close'], n=10, fillna=False) + pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) + + class TestBollingerBands(unittest.TestCase): """ https://school.stockcharts.com/doku.php?id=technical_indicators:bollinger_bands @@ -40,12 +69,14 @@ class TestBollingerBands(unittest.TestCase): _filename = 'ta/tests/data/cs-bbands.csv' - def setUp(self): - self._df = pd.read_csv(self._filename, sep=',') - self._indicator = BollingerBands(close=self._df['Close'], n=20, ndev=2, fillna=False) + @classmethod + def setUpClass(cls): + cls._df = pd.read_csv(cls._filename, sep=',') + cls._indicator = BollingerBands(close=cls._df['Close'], n=20, ndev=2, fillna=False) - def tearDown(self): - del(self._df) + @classmethod + def tearDownClass(cls): + del(cls._df) def test_mavg(self): target = 'MiddleBand' @@ -169,3 +200,148 @@ def test_lband_indicator2(self): target = 'dc_low_indicator' result = donchian_channel_lband_indicator(close=self._df['Close'], n=20, fillna=False) pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) + + +class TestKeltnerChannel(unittest.TestCase): + """ + https://school.stockcharts.com/doku.php?id=technical_indicators:keltner_channels + https://docs.google.com/spreadsheets/d/1qT8JbJ7F13bMV9-TcK-oFHL1F5sKPwakQWf6KrvGI3U/edit?usp=sharing + """ + + _filename = 'ta/tests/data/cs-kc.csv' + + @classmethod + def setUpClass(cls): + cls._df = pd.read_csv(cls._filename, sep=',') + cls._indicator = KeltnerChannel( + high=cls._df['High'], low=cls._df['Low'], close=cls._df['Close'], n=20, n_atr=10, fillna=False, ov=False) + + @classmethod + def tearDownClass(cls): + del(cls._df) + + def test_mavg(self): + target = 'middle_band' + result = self._indicator.keltner_channel_mband() + pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) + + def test_hband(self): + target = 'upper_band' + result = self._indicator.keltner_channel_hband() + pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) + + def test_lband(self): + target = 'lower_band' + result = self._indicator.keltner_channel_lband() + pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) + + def test_wband(self): + target = 'kc_band_width' + result = self._indicator.keltner_channel_wband() + pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) + + def test_pband(self): + target = 'kc_percentage' + result = self._indicator.keltner_channel_pband() + pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) + + def test_hband_indicator(self): + target = 'kc_high_indicator' + result = self._indicator.keltner_channel_hband_indicator() + pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) + + def test_lband_indicator(self): + target = 'kc_low_indicator' + result = self._indicator.keltner_channel_lband_indicator() + pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) + + def test_mavg2(self): + target = 'middle_band' + result = keltner_channel_mband( + high=self._df['High'], + low=self._df['Low'], + close=self._df['Close'], + n=20, + n_atr=10, + fillna=False, + ov=False + ) + pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) + + def test_hband2(self): + target = 'upper_band' + result = keltner_channel_hband( + high=self._df['High'], + low=self._df['Low'], + close=self._df['Close'], + n=20, + n_atr=10, + fillna=False, + ov=False + ) + pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) + + def test_lband2(self): + target = 'lower_band' + result = keltner_channel_lband( + high=self._df['High'], + low=self._df['Low'], + close=self._df['Close'], + n=20, + n_atr=10, + fillna=False, + ov=False + ) + pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) + + def test_wband2(self): + target = 'kc_band_width' + result = keltner_channel_wband( + high=self._df['High'], + low=self._df['Low'], + close=self._df['Close'], + n=20, + n_atr=10, + fillna=False, + ov=False + ) + pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) + + def test_pband2(self): + target = 'kc_percentage' + result = keltner_channel_pband( + high=self._df['High'], + low=self._df['Low'], + close=self._df['Close'], + n=20, + n_atr=10, + fillna=False, + ov=False + ) + pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) + + def test_hband_indicator2(self): + target = 'kc_high_indicator' + result = keltner_channel_hband_indicator( + high=self._df['High'], + low=self._df['Low'], + close=self._df['Close'], + n=20, + n_atr=10, + fillna=False, + ov=False + ) + pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) + + def test_lband_indicator2(self): + target = 'kc_low_indicator' + result = keltner_channel_lband_indicator( + high=self._df['High'], + low=self._df['Low'], + close=self._df['Close'], + n=20, + n_atr=10, + fillna=False, + ov=False + ) + pd.testing.assert_series_equal(self._df[target].tail(), result.tail(), check_names=False) diff --git a/ta/volatility.py b/ta/volatility.py index 5ffcfa02..ef89a1f9 100644 --- a/ta/volatility.py +++ b/ta/volatility.py @@ -170,6 +170,7 @@ class KeltnerChannel(IndicatorMixin): low(pandas.Series): dataset 'Low' column. close(pandas.Series): dataset 'Close' column. n(int): n period. + n_atr(int): n atr period. Only valid if ov param is False. fillna(bool): if True, fill nan values. ov(bool): if True, use original version as the centerline (SMA of typical price) if False, use EMA of close as the centerline. More info: @@ -177,27 +178,29 @@ class KeltnerChannel(IndicatorMixin): """ def __init__( - self, high: pd.Series, low: pd.Series, close: pd.Series, n: int = 14, fillna: bool = False, - ov: bool = True): + self, high: pd.Series, low: pd.Series, close: pd.Series, n: int = 20, n_atr: int = 10, + fillna: bool = False, ov: bool = True): self._high = high self._low = low self._close = close self._n = n + self._n_atr = n_atr self._fillna = fillna self._ov = ov self._run() def _run(self): + min_periods = 1 if self._fillna else self._n if self._ov: - self._tp = ((self._high + self._low + self._close) / 3.0).rolling(self._n, min_periods=0).mean() + self._tp = ((self._high + self._low + self._close) / 3.0).rolling(self._n, min_periods=min_periods).mean() self._tp_high = (((4 * self._high) - (2 * self._low) + self._close) / 3.0).rolling( self._n, min_periods=0).mean() self._tp_low = (((-2 * self._high) + (4 * self._low) + self._close) / 3.0).rolling( self._n, min_periods=0).mean() else: - self._tp = self._close.ewm(span=self._n, min_periods=0, adjust=False).mean() + self._tp = self._close.ewm(span=self._n, min_periods=min_periods, adjust=False).mean() atr = AverageTrueRange( - close=self._close, high=self._high, low=self._high, n=10, fillna=self._fillna + close=self._close, high=self._high, low=self._low, n=self._n_atr, fillna=self._fillna ).average_true_range() self._tp_high = self._tp + (2*atr) self._tp_low = self._tp - (2*atr) @@ -533,147 +536,175 @@ def bollinger_lband_indicator(close, n=20, ndev=2, fillna=False): return indicator.bollinger_lband_indicator() -def keltner_channel_mband(high, low, close, n=10, fillna=False, ov=True): +def keltner_channel_mband(high, low, close, n=20, n_atr=10, fillna=False, ov=True): """Keltner channel (KC) Showing a simple moving average line (central) of typical price. - https://en.wikipedia.org/wiki/Keltner_channel + https://school.stockcharts.com/doku.php?id=technical_indicators:keltner_channels Args: high(pandas.Series): dataset 'High' column. low(pandas.Series): dataset 'Low' column. close(pandas.Series): dataset 'Close' column. n(int): n period. + n_atr(int): n atr period. Only valid if ov param is False. fillna(bool): if True, fill nan values. + ov(bool): if True, use original version as the centerline (SMA of typical price) + if False, use EMA of close as the centerline. More info: + https://school.stockcharts.com/doku.php?id=technical_indicators:keltner_channels Returns: pandas.Series: New feature generated. """ - indicator = KeltnerChannel(high=high, low=low, close=close, n=n, fillna=False, ov=ov) + indicator = KeltnerChannel(high=high, low=low, close=close, n=n, n_atr=n_atr, fillna=fillna, ov=ov) return indicator.keltner_channel_mband() -def keltner_channel_hband(high, low, close, n=10, fillna=False, ov=True): +def keltner_channel_hband(high, low, close, n=20, n_atr=10, fillna=False, ov=True): """Keltner channel (KC) Showing a simple moving average line (high) of typical price. - https://en.wikipedia.org/wiki/Keltner_channel + https://school.stockcharts.com/doku.php?id=technical_indicators:keltner_channels Args: high(pandas.Series): dataset 'High' column. low(pandas.Series): dataset 'Low' column. close(pandas.Series): dataset 'Close' column. n(int): n period. + n_atr(int): n atr period. Only valid if ov param is False. fillna(bool): if True, fill nan values. + ov(bool): if True, use original version as the centerline (SMA of typical price) + if False, use EMA of close as the centerline. More info: + https://school.stockcharts.com/doku.php?id=technical_indicators:keltner_channels Returns: pandas.Series: New feature generated. """ - indicator = KeltnerChannel(high=high, low=low, close=close, n=n, fillna=False, ov=ov) + indicator = KeltnerChannel(high=high, low=low, close=close, n=n, n_atr=n_atr, fillna=fillna, ov=ov) return indicator.keltner_channel_hband() -def keltner_channel_lband(high, low, close, n=10, fillna=False, ov=True): +def keltner_channel_lband(high, low, close, n=20, n_atr=10, fillna=False, ov=True): """Keltner channel (KC) Showing a simple moving average line (low) of typical price. - https://en.wikipedia.org/wiki/Keltner_channel + https://school.stockcharts.com/doku.php?id=technical_indicators:keltner_channels Args: high(pandas.Series): dataset 'High' column. low(pandas.Series): dataset 'Low' column. close(pandas.Series): dataset 'Close' column. n(int): n period. + n_atr(int): n atr period. Only valid if ov param is False. fillna(bool): if True, fill nan values. + ov(bool): if True, use original version as the centerline (SMA of typical price) + if False, use EMA of close as the centerline. More info: + https://school.stockcharts.com/doku.php?id=technical_indicators:keltner_channels Returns: pandas.Series: New feature generated. """ - indicator = KeltnerChannel(high=high, low=low, close=close, n=n, fillna=False, ov=ov) + indicator = KeltnerChannel(high=high, low=low, close=close, n=n, n_atr=n_atr, fillna=fillna, ov=ov) return indicator.keltner_channel_lband() -def keltner_channel_wband(high, low, close, n=10, fillna=False, ov=True): +def keltner_channel_wband(high, low, close, n=20, n_atr=10, fillna=False, ov=True): """Keltner Channel Band Width - https://en.wikipedia.org/wiki/Keltner_channel + https://school.stockcharts.com/doku.php?id=technical_indicators:keltner_channels Args: high(pandas.Series): dataset 'High' column. low(pandas.Series): dataset 'Low' column. close(pandas.Series): dataset 'Close' column. n(int): n period. + n_atr(int): n atr period. Only valid if ov param is False. fillna(bool): if True, fill nan values. + ov(bool): if True, use original version as the centerline (SMA of typical price) + if False, use EMA of close as the centerline. More info: + https://school.stockcharts.com/doku.php?id=technical_indicators:keltner_channels Returns: pandas.Series: New feature generated. """ - indicator = KeltnerChannel(high=high, low=low, close=close, n=n, fillna=False, ov=ov) + indicator = KeltnerChannel(high=high, low=low, close=close, n=n, n_atr=n_atr, fillna=fillna, ov=ov) return indicator.keltner_channel_wband() -def keltner_channel_pband(high, low, close, n=10, fillna=False, ov=True): +def keltner_channel_pband(high, low, close, n=20, n_atr=10, fillna=False, ov=True): """Keltner Channel Percentage Band - https://en.wikipedia.org/wiki/Keltner_channel + https://school.stockcharts.com/doku.php?id=technical_indicators:keltner_channels Args: high(pandas.Series): dataset 'High' column. low(pandas.Series): dataset 'Low' column. close(pandas.Series): dataset 'Close' column. n(int): n period. + n_atr(int): n atr period. Only valid if ov param is False. fillna(bool): if True, fill nan values. + ov(bool): if True, use original version as the centerline (SMA of typical price) + if False, use EMA of close as the centerline. More info: + https://school.stockcharts.com/doku.php?id=technical_indicators:keltner_channels Returns: pandas.Series: New feature generated. """ - indicator = KeltnerChannel(high=high, low=low, close=close, n=n, fillna=False, ov=ov) + indicator = KeltnerChannel(high=high, low=low, close=close, n=n, n_atr=n_atr, fillna=fillna, ov=ov) return indicator.keltner_channel_pband() -def keltner_channel_hband_indicator(high, low, close, n=10, fillna=False, ov=True): +def keltner_channel_hband_indicator(high, low, close, n=20, n_atr=10, fillna=False, ov=True): """Keltner Channel High Band Indicator (KC) Returns 1, if close is higher than keltner high band channel. Else, return 0. - https://en.wikipedia.org/wiki/Keltner_channel + https://school.stockcharts.com/doku.php?id=technical_indicators:keltner_channels Args: high(pandas.Series): dataset 'High' column. low(pandas.Series): dataset 'Low' column. close(pandas.Series): dataset 'Close' column. n(int): n period. + n_atr(int): n atr period. Only valid if ov param is False. fillna(bool): if True, fill nan values. + ov(bool): if True, use original version as the centerline (SMA of typical price) + if False, use EMA of close as the centerline. More info: + https://school.stockcharts.com/doku.php?id=technical_indicators:keltner_channels Returns: pandas.Series: New feature generated. """ - indicator = KeltnerChannel(high=high, low=low, close=close, n=n, fillna=False, ov=ov) + indicator = KeltnerChannel(high=high, low=low, close=close, n=n, n_atr=n_atr, fillna=fillna, ov=ov) return indicator.keltner_channel_hband_indicator() -def keltner_channel_lband_indicator(high, low, close, n=10, fillna=False, ov=True): +def keltner_channel_lband_indicator(high, low, close, n=20, n_atr=10, fillna=False, ov=True): """Keltner Channel Low Band Indicator (KC) Returns 1, if close is lower than keltner low band channel. Else, return 0. - https://en.wikipedia.org/wiki/Keltner_channel + https://school.stockcharts.com/doku.php?id=technical_indicators:keltner_channels Args: high(pandas.Series): dataset 'High' column. low(pandas.Series): dataset 'Low' column. close(pandas.Series): dataset 'Close' column. n(int): n period. + n_atr(int): n atr period. Only valid if ov param is False. fillna(bool): if True, fill nan values. + ov(bool): if True, use original version as the centerline (SMA of typical price) + if False, use EMA of close as the centerline. More info: + https://school.stockcharts.com/doku.php?id=technical_indicators:keltner_channels Returns: pandas.Series: New feature generated. """ - indicator = KeltnerChannel(high=high, low=low, close=close, n=n, fillna=False, ov=ov) + indicator = KeltnerChannel(high=high, low=low, close=close, n=n, n_atr=n_atr, fillna=fillna, ov=ov) return indicator.keltner_channel_lband_indicator()