diff --git a/PyFin/Analysis/SecurityValueHolders.pyx b/PyFin/Analysis/SecurityValueHolders.pyx index 905328c..018c57e 100644 --- a/PyFin/Analysis/SecurityValueHolders.pyx +++ b/PyFin/Analysis/SecurityValueHolders.pyx @@ -138,18 +138,34 @@ cdef class SecurityValueHolder(object): def __add__(self, right): return SecurityAddedValueHolder(self, right) + def __radd__(self, left): + return SecurityAddedValueHolder(left, self) + def __sub__(self, right): return SecuritySubbedValueHolder(self, right) + def __rsub__(self, left): + return SecuritySubbedValueHolder(left, self) + def __mul__(self, right): return SecurityMultipliedValueHolder(self, right) + def __rmul__(self, left): + return SecurityMultipliedValueHolder(left, self) + + def __div__(self, right): return SecurityDividedValueHolder(self, right) + def __rdiv__(self, left): + return SecurityDividedValueHolder(left, self) + def __truediv__(self, right): return SecurityDividedValueHolder(self, right) + def __rtruediv__(self, left): + return SecurityDividedValueHolder(left, self) + def __richcmp__(self, right, int op): if op == 0: diff --git a/PyFin/Analysis/SeriesValues.pyx b/PyFin/Analysis/SeriesValues.pyx index 5b334b1..8d72f2e 100644 --- a/PyFin/Analysis/SeriesValues.pyx +++ b/PyFin/Analysis/SeriesValues.pyx @@ -92,6 +92,15 @@ cdef class SeriesValues(object): else: return SeriesValues(self.values + right, self.name_mapping) + def __radd__(self, left): + if isinstance(left, SeriesValues): + if isinstance(self, SeriesValues): + return SeriesValues(left.values + self.values, self.name_mapping) + else: + return SeriesValues(left.values + self, left.name_mapping) + else: + return SeriesValues(left + self.values, self.name_mapping) + def __sub__(self, right): if isinstance(right, SeriesValues): if isinstance(self, SeriesValues): @@ -101,6 +110,15 @@ cdef class SeriesValues(object): else: return SeriesValues(self.values - right, self.name_mapping) + def __rsub__(self, left): + if isinstance(left, SeriesValues): + if isinstance(self, SeriesValues): + return SeriesValues(left.values - self.values, self.name_mapping) + else: + return SeriesValues(left.values - self, left.name_mapping) + else: + return SeriesValues(left - self.values, self.name_mapping) + def __mul__(self, right): if isinstance(right, SeriesValues): if isinstance(self, SeriesValues): @@ -110,6 +128,15 @@ cdef class SeriesValues(object): else: return SeriesValues(self.values * right, self.name_mapping) + def __rmul__(self, left): + if isinstance(left, SeriesValues): + if isinstance(self, SeriesValues): + return SeriesValues(left.values * self.values, self.name_mapping) + else: + return SeriesValues(left.values * self, left.name_mapping) + else: + return SeriesValues(left * self.values, self.name_mapping) + @cython.cdivision(True) def __truediv__(self, right): cdef np.ndarray[double, ndim=1] values @@ -128,6 +155,24 @@ cdef class SeriesValues(object): values[~np.isfinite(values)] = NAN return SeriesValues(values, name_mapping) + @cython.cdivision(True) + def __rtruediv__(self, left): + cdef np.ndarray[double, ndim=1] values + cdef dict name_mapping + if isinstance(left, SeriesValues): + if isinstance(self, SeriesValues): + values = left.values / self.values + name_mapping = self.name_mapping + else: + values = left.values / self + name_mapping = left.name_mapping + else: + values = left / self.values + name_mapping = self.name_mapping + + values[~np.isfinite(values)] = NAN + return SeriesValues(values, name_mapping) + @cython.cdivision(True) def __div__(self, right): cdef np.ndarray[double, ndim=1] values @@ -146,6 +191,24 @@ cdef class SeriesValues(object): values[~np.isfinite(values)] = NAN return SeriesValues(values, name_mapping) + @cython.cdivision(True) + def __rdiv__(self, left): + cdef np.ndarray[double, ndim=1] values + cdef dict name_mapping + if isinstance(left, SeriesValues): + if isinstance(self, SeriesValues): + values = left.values / self.values + name_mapping = self.name_mapping + else: + values = left.values / self + name_mapping = left.name_mapping + else: + values = left / self.values + name_mapping = self.name_mapping + + values[~np.isfinite(values)] = NAN + return SeriesValues(values, name_mapping) + def __and__(self, right): if isinstance(right, SeriesValues): if isinstance(self, SeriesValues): @@ -155,6 +218,15 @@ cdef class SeriesValues(object): else: return SeriesValues(self.values.astype(bool) & right, self.name_mapping) + def __rand__(self, left): + if isinstance(left, SeriesValues): + if isinstance(self, SeriesValues): + return SeriesValues(left.values.astype(bool) & self.values.astype(bool), self.name_mapping) + else: + return SeriesValues(left.values.astype(bool) & self, left.name_mapping) + else: + return SeriesValues(left & self.values.astype(bool), self.name_mapping) + def __or__(self, right): if isinstance(right, SeriesValues): if isinstance(self, SeriesValues): @@ -164,6 +236,15 @@ cdef class SeriesValues(object): else: return SeriesValues(self.values.astype(bool) | right, self.name_mapping) + def __ror__(self, left): + if isinstance(left, SeriesValues): + if isinstance(self, SeriesValues): + return SeriesValues(left.values.astype(bool) | self.values.astype(bool), self.name_mapping) + else: + return SeriesValues(left.values.astype(bool) | self, left.name_mapping) + else: + return SeriesValues(left | self.values.astype(bool), self.name_mapping) + def __xor__(self, right): if isinstance(right, SeriesValues): if isinstance(self, SeriesValues): @@ -231,7 +312,7 @@ cdef class SeriesValues(object): start = diff_loc + 1 data[isnan(self.values)] = NAN else: - data = rankdata(self.values).astype(float) + data = rankdata(self.values, nan_policy="omit").astype(float) data[isnan(self.values)] = NAN return SeriesValues(data, self.name_mapping) diff --git a/PyFin/DateUtilities/Calendar.pyx b/PyFin/DateUtilities/Calendar.pyx index 056ed59..3a38307 100644 --- a/PyFin/DateUtilities/Calendar.pyx +++ b/PyFin/DateUtilities/Calendar.pyx @@ -709,7 +709,45 @@ cdef set sse_holDays = { Date(2022, 10, 4), Date(2022, 10, 5), Date(2022, 10, 6), - Date(2022, 10, 7) + Date(2022, 10, 7), + Date(2023, 1, 2), + Date(2023, 1, 23), + Date(2023, 1, 24), + Date(2023, 1, 25), + Date(2023, 1, 26), + Date(2023, 1, 27), + Date(2023, 4, 5), + Date(2023, 5, 1), + Date(2023, 5, 2), + Date(2023, 5, 3), + Date(2023, 6, 22), + Date(2023, 6, 23), + Date(2023, 9, 29), + Date(2023, 10, 2), + Date(2023, 10, 3), + Date(2023, 10, 4), + Date(2023, 10, 5), + Date(2023, 10, 6), + Date(2024, 1, 1), + Date(2024, 2, 9), + Date(2024, 2, 12), + Date(2024, 2, 13), + Date(2024, 2, 14), + Date(2024, 2, 15), + Date(2024, 2, 16), + Date(2024, 4, 4), + Date(2024, 4, 5), + Date(2024, 5, 1), + Date(2024, 5, 2), + Date(2024, 5, 3), + Date(2024, 6, 10), + Date(2024, 9, 16), + Date(2024, 9, 17), + Date(2024, 10, 1), + Date(2024, 10, 2), + Date(2024, 10, 3), + Date(2024, 10, 4), + Date(2024, 10, 7), } @@ -873,7 +911,25 @@ cdef set ib_working_weekends = { Date(2022, 4, 24), Date(2022, 5, 7), Date(2022, 10, 8), - Date(2022, 10, 9) + Date(2022, 10, 9), + # 2023 + Date(2023, 1, 28), + Date(2023, 1, 29), + Date(2023, 4, 23), + Date(2023, 5, 6), + Date(2023, 6, 25), + Date(2023, 10, 7), + Date(2023, 10, 8), + # 2024 + Date(2024, 2, 4), + Date(2024, 2, 9), + Date(2024, 2, 18), + Date(2024, 4, 7), + Date(2024, 4, 28), + Date(2024, 5, 11), + Date(2024, 9, 14), + Date(2024, 9, 29), + Date(2024, 10, 12) } cdef ChinaSseImpl _sseImpl = ChinaSseImpl() diff --git a/PyFin/Math/Accumulators/IAccumulators.pyx b/PyFin/Math/Accumulators/IAccumulators.pyx index 10890ef..1c944a3 100644 --- a/PyFin/Math/Accumulators/IAccumulators.pyx +++ b/PyFin/Math/Accumulators/IAccumulators.pyx @@ -36,19 +36,34 @@ cdef class IAccumulator(object): def __add__(self, right): return AddedValueHolder(self, right) + def __radd__(self, left): + return AddedValueHolder(left, self) + def __sub__(self, right): return MinusedValueHolder(self, right) + def __rsub__(self, left): + return MinusedValueHolder(left, self) + def __mul__(self, right): return MultipliedValueHolder(self, right) + def __rmul__(self, left): + return MultipliedValueHolder(left, self) + def __div__(self, right): return DividedValueHolder(self, right) + def __rdiv__(self, left): + return DividedValueHolder(left, self) + # only work for python 3 def __truediv__(self, right): return DividedValueHolder(self, right) + def __rtruediv__(self, left): + return DividedValueHolder(left, self) + def __richcmp__(self, right, int op): if op == 0: return LtOperatorValueHolder(self, right) diff --git a/PyFin/__init__.py b/PyFin/__init__.py index a60eebf..07db660 100644 --- a/PyFin/__init__.py +++ b/PyFin/__init__.py @@ -23,4 +23,4 @@ 'Analysis', 'Utilities'] -__version__ = "0.9.8" +__version__ = "0.9.10" diff --git a/PyFin/tests/DateUtilities/testCalendar.py b/PyFin/tests/DateUtilities/testCalendar.py index e3993c4..e4f9448 100644 --- a/PyFin/tests/DateUtilities/testCalendar.py +++ b/PyFin/tests/DateUtilities/testCalendar.py @@ -140,7 +140,23 @@ def testChinaSSE(self): Date(2022, 5, 2), Date(2022, 5, 3), Date(2022, 5, 4), Date(2022, 6, 3), Date(2022, 9, 12), - Date(2022, 10, 3), Date(2022, 10, 4), Date(2022, 10, 5), Date(2022, 10, 6), Date(2022, 10, 7) + Date(2022, 10, 3), Date(2022, 10, 4), Date(2022, 10, 5), Date(2022, 10, 6), Date(2022, 10, 7), + # China Shanghai Securities Exchange holiday list in the year 2023 + Date(2023, 1, 1), Date(2023, 1, 2), + Date(2023, 1, 21), Date(2023, 1, 22), Date(2023, 1, 23), Date(2023, 1, 24), Date(2023, 1, 25), Date(2023, 1, 26), Date(2023, 1, 27), + Date(2023, 4, 5), Date(2023, 4, 29), Date(2023, 4, 30), + Date(2023, 5, 1), Date(2023, 5, 2), Date(2023, 5, 3), + Date(2023, 6, 22), Date(2023, 6, 23), Date(2023, 6, 24), + Date(2023, 9, 29), Date(2023, 9, 30), + Date(2023, 10, 1), Date(2023, 10, 2), Date(2023, 10, 3), Date(2023, 10, 4), Date(2023, 10, 5), Date(2023, 10, 6), + # China Shanghai Securities Exchange holiday list in the year 2024 + Date(2024, 1, 1), + Date(2024, 2, 10), Date(2024, 2, 11), Date(2024, 2, 12), Date(2024, 2, 13), Date(2024, 2, 14), Date(2024, 2, 15), Date(2024, 2, 16), Date(2024, 2, 17), + Date(2024, 4, 5), Date(2024, 4, 6), Date(2024, 4, 7), + Date(2024, 5, 1), Date(2024, 5, 2), Date(2024, 5, 3), Date(2024, 5, 4), Date(2024, 5, 5), + Date(2024, 6, 10), + Date(2024, 9, 15), Date(2024, 9, 16), Date(2024, 9, 17), + Date(2024, 10, 1), Date(2024, 10, 2), Date(2024, 10, 3), Date(2024, 10, 4), Date(2024, 10, 5), Date(2024, 10, 6), Date(2024, 10, 7), ] cal = Calendar('China.SSE') @@ -213,7 +229,26 @@ def testChinaIB(self): Date(2022, 4, 24), Date(2022, 5, 7), Date(2022, 10, 8), - Date(2022, 10, 9)] + Date(2022, 10, 9), + # China Inter Bank working weekend list in the year 2023 + Date(2023, 1, 28), + Date(2023, 1, 29), + Date(2023, 4, 23), + Date(2023, 5, 6), + Date(2023, 6, 25), + Date(2023, 10, 7), + Date(2023, 10, 8), + # China Inter Bank working weekend list in the year 2024 + Date(2024, 2, 4), + Date(2024, 2, 9), + Date(2024, 2, 18), + Date(2024, 4, 7), + Date(2024, 4, 28), + Date(2024, 5, 11), + Date(2024, 9, 14), + Date(2024, 9, 29), + Date(2024, 10, 12) + ] cal = Calendar('China.IB') diff --git a/setup.py b/setup.py index 8273b21..ad1a25f 100644 --- a/setup.py +++ b/setup.py @@ -25,7 +25,7 @@ PACKAGE = "PyFin" NAME = "Finance-Python" -__version__ = "0.9.8" +__version__ = "0.9.10" DESCRIPTION = "PyFin " + __version__ AUTHOR = "cheng li" AUTHOR_EMAIL = "wegamekinglc@hotmail.com"