diff --git a/.gitignore b/.gitignore index c814156..81b935e 100644 --- a/.gitignore +++ b/.gitignore @@ -83,6 +83,9 @@ celerybeat-schedule # SageMath parsed files *.sage.py +# pycharm +.idea/* + # dotenv .env @@ -112,9 +115,11 @@ env/** pandas_ta/_wrapper.py # twopirllc stuff +IBclient/ data/datas.csv data/SPY_5min.csv data/SPY_1min.csv +examples/ib_trader.ipynb setup.cfg .README.md README diff --git a/pandas_ta/utils.py b/pandas_ta/utils.py index 20c1105..6961855 100644 --- a/pandas_ta/utils.py +++ b/pandas_ta/utils.py @@ -87,7 +87,7 @@ def get_offset(x:int): return int(x) if x else 0 -def pascals_triangle(**kwargs): +def pascals_triangle(n=None, **kwargs): """Pascal's Triangle Returns a numpy array of the nth row of Pascal's Triangle. @@ -95,7 +95,7 @@ def pascals_triangle(**kwargs): => weighted: [0.0625, 0.25, 0.375, 0.25, 0.0625 => inverse weighted: [0.9375, 0.75, 0.625, 0.75, 0.9375] """ - n = int(math.fabs(kwargs.pop('n', 0))) + n = int(math.fabs(n)) if n is not None else 0 weighted = kwargs.pop('weighted', False) inverse = kwargs.pop('inverse', False) @@ -125,6 +125,31 @@ def signed_series(series:pd.Series, initial:int = None): return sign +def symmetric_triangle(n=None, **kwargs): + n = int(math.fabs(n)) if n is not None else 2 + weighted = kwargs.pop('weighted', False) + + if n == 2: + triangle = [1, 1] + + if n > 2: + if n % 2 == 0: + front = [i + 1 for i in range(0, math.floor(n/2))] + triangle = front + front[::-1] + else: + front = [i + 1 for i in range(0, math.floor(0.5 * (n + 1)))] + triangle = front.copy() + front.pop() + triangle += front[::-1] + + if weighted: + triangle_sum = np.sum(triangle) + triangle_weights = triangle / triangle_sum + return triangle_weights + + return triangle + + def verify_series(series:pd.Series): """If a Pandas Series return it.""" if series is not None and isinstance(series, pd.core.series.Series): diff --git a/setup.py b/setup.py index f7a8dd9..cf41061 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ long_description = "An easy to use Python 3 Pandas Extension of Technical Analys setup( name = "pandas_ta", packages = ["pandas_ta"], - version = "0.1.9a", + version = "0.1.10a", description=long_description, long_description=long_description, author = "Kevin Johnson", diff --git a/tests/test_utils.py b/tests/test_utils.py index 6c3d185..97f8131 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -25,7 +25,6 @@ class TestUtilities(TestCase): self.assertEqual(self.utils.combination(n=10, r=4, repetition=False), 210) self.assertEqual(self.utils.combination(n=10, r=4, repetition=True), 715) - def test_fibonacci(self): self.assertIs(type(self.utils.fibonacci(zero=True, weighted=False)), np.ndarray) @@ -37,7 +36,6 @@ class TestUtilities(TestCase): npt.assert_array_equal(self.utils.fibonacci(n=5, zero=True, weighted=False), np.array([0, 1, 1, 2, 3, 5])) npt.assert_array_equal(self.utils.fibonacci(n=5, zero=False, weighted=False), np.array([1, 1, 2, 3, 5])) - def test_fibonacci_weighted(self): self.assertIs(type(self.utils.fibonacci(zero=True, weighted=True)), np.ndarray) @@ -47,7 +45,6 @@ class TestUtilities(TestCase): npt.assert_allclose(self.utils.fibonacci(n=5, zero=True, weighted=True), np.array([0, 1/12, 1/12, 1/6, 1/4, 5/12])) npt.assert_allclose(self.utils.fibonacci(n=5, zero=False, weighted=True), np.array([1/12, 1/12, 1/6, 1/4, 5/12])) - def test_pascals_triangle(self): self.assertIsNone(self.utils.pascals_triangle(inverse=True), None) @@ -67,6 +64,19 @@ class TestUtilities(TestCase): npt.assert_array_equal(self.utils.pascals_triangle(n=5, weighted=True), array_5w) npt.assert_array_equal(self.utils.pascals_triangle(n=5, weighted=True, inverse=True), array_5iw) + def test_symmetric_triangle(self): + npt.assert_array_equal(self.utils.symmetric_triangle(), np.array([1, 1])) + npt.assert_array_equal(self.utils.symmetric_triangle(weighted=True), np.array([0.5, 0.5])) + + array_4 = self.utils.symmetric_triangle(n=4) #or np.array([1, 2, 2, 1]) + array_4w = array_4 / np.sum(array_4) + npt.assert_array_equal(self.utils.symmetric_triangle(n=4), array_4) + npt.assert_array_equal(self.utils.symmetric_triangle(n=4, weighted=True), array_4w) + + array_5 = self.utils.symmetric_triangle(n=5) #or np.array([1, 2, 3, 2, 1]) + array_5w = array_5 / np.sum(array_5) + npt.assert_array_equal(self.utils.symmetric_triangle(n=5), array_5) + npt.assert_array_equal(self.utils.symmetric_triangle(n=5, weighted=True), array_5w) def test_zero(self): self.assertEqual(self.utils.zero(-0.0000000000000001), 0) @@ -78,7 +88,6 @@ class TestUtilities(TestCase): self.assertNotEqual(self.utils.zero(0.000000000000001), 0) self.assertNotEqual(self.utils.zero(1), 0) - def test_get_drift(self): for s in [0, None, '', [], {}]: self.assertIsInstance(self.utils.get_drift(s), int) @@ -90,7 +99,6 @@ class TestUtilities(TestCase): self.assertEqual(self.utils.get_drift(1.9999999999999999), 2) self.assertEqual(self.utils.get_drift(-10), -10) - def test_get_offset(self): for s in [0, None, '', [], {}]: self.assertIsInstance(self.utils.get_offset(s), int)