Compare commits
	
		
			10 Commits
		
	
	
		
			5512a647ad
			...
			38fb9ca7d0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 38fb9ca7d0 | |||
| 0a113fdd8a | |||
| 9a71cdf355 | |||
| 66ad448516 | |||
| 49cebecb88 | |||
| da0bfcbcb1 | |||
| cad069d351 | |||
| 130f4e58e9 | |||
| 2ca6167c8b | |||
| 95e9bfd51c | 
@ -7,6 +7,7 @@ from collections import UserList
 | 
				
			|||||||
from dataclasses import dataclass
 | 
					from dataclasses import dataclass
 | 
				
			||||||
from numbers import Number
 | 
					from numbers import Number
 | 
				
			||||||
from typing import Any, Callable, Iterable, List, Literal, Mapping, Sequence, Type
 | 
					from typing import Any, Callable, Iterable, List, Literal, Mapping, Sequence, Type
 | 
				
			||||||
 | 
					from unittest import skip
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from dateutil.relativedelta import relativedelta
 | 
					from dateutil.relativedelta import relativedelta
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -156,14 +157,14 @@ class Series(UserList):
 | 
				
			|||||||
        else:
 | 
					        else:
 | 
				
			||||||
            return self.data[i]
 | 
					            return self.data[i]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _comparison_validator(self, other):
 | 
					    def _comparison_validator(self, other, skip_bool: bool = False):
 | 
				
			||||||
        """Validates other before making comparison"""
 | 
					        """Validates other before making comparison"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if isinstance(other, (str, datetime.datetime, datetime.date)):
 | 
					        if isinstance(other, (str, datetime.datetime, datetime.date)):
 | 
				
			||||||
            other = _parse_date(other)
 | 
					            other = _parse_date(other)
 | 
				
			||||||
            return other
 | 
					            return other
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if self.dtype == bool:
 | 
					        if self.dtype == bool and not skip_bool:
 | 
				
			||||||
            raise TypeError("Comparison operation not supported for boolean series")
 | 
					            raise TypeError("Comparison operation not supported for boolean series")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        elif isinstance(other, Series):
 | 
					        elif isinstance(other, Series):
 | 
				
			||||||
@ -221,7 +222,23 @@ class Series(UserList):
 | 
				
			|||||||
        if isinstance(other, Series):
 | 
					        if isinstance(other, Series):
 | 
				
			||||||
            return Series([j != other[i] for i, j in enumerate(self)], "bool")
 | 
					            return Series([j != other[i] for i, j in enumerate(self)], "bool")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return Series([i == other for i in self.data], "bool")
 | 
					        return Series([i != other for i in self.data], "bool")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __and__(self, other):
 | 
				
			||||||
 | 
					        other = self._comparison_validator(other, skip_bool=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if isinstance(other, Series):
 | 
				
			||||||
 | 
					            return Series([j and other[i] for i, j in enumerate(self)], "bool")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return Series([i and other for i in self.data], "bool")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __or__(self, other):
 | 
				
			||||||
 | 
					        other = self._comparison_validator(other, skip_bool=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if isinstance(other, Series):
 | 
				
			||||||
 | 
					            return Series([j or other[i] for i, j in enumerate(self)], "bool")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return Series([i or other for i in self.data], "bool")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def _math_validator(self, other):
 | 
					    def _math_validator(self, other):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -81,7 +81,7 @@ def create_date_series(
 | 
				
			|||||||
            extend_by_days = 7 - end_date.weekday()
 | 
					            extend_by_days = 7 - end_date.weekday()
 | 
				
			||||||
            end_date += relativedelta(days=extend_by_days)
 | 
					            end_date += relativedelta(days=extend_by_days)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # To-do: Add code to ensure coverage for other frequencies as well
 | 
					        # TODO: Add code to ensure coverage for other frequencies as well
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    datediff = (end_date - start_date).days / frequency.days + 1
 | 
					    datediff = (end_date - start_date).days / frequency.days + 1
 | 
				
			||||||
    dates = []
 | 
					    dates = []
 | 
				
			||||||
@ -91,8 +91,8 @@ def create_date_series(
 | 
				
			|||||||
        date = start_date + relativedelta(**diff)
 | 
					        date = start_date + relativedelta(**diff)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if eomonth:
 | 
					        if eomonth:
 | 
				
			||||||
            next_month = 1 if date.month == 12 else date.month + 1
 | 
					            replacement = {"month": date.month + 1} if date.month < 12 else {"year": date.year + 1}
 | 
				
			||||||
            date = date.replace(day=1).replace(month=next_month) - relativedelta(days=1)
 | 
					            date = date.replace(day=1).replace(**replacement) - relativedelta(days=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if date <= end_date:
 | 
					        if date <= end_date:
 | 
				
			||||||
            if frequency.days > 1 or not skip_weekends:
 | 
					            if frequency.days > 1 or not skip_weekends:
 | 
				
			||||||
@ -727,7 +727,10 @@ class TimeSeries(TimeSeriesCore):
 | 
				
			|||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        closest: str = "previous" if method == "ffill" else "next"
 | 
					        closest: str = "previous" if method == "ffill" else "next"
 | 
				
			||||||
        new_ts: dict = {dt: self.get(dt, closest=closest)[1] for dt in new_dates}
 | 
					        new_ts = {}
 | 
				
			||||||
 | 
					        for dt in new_dates:
 | 
				
			||||||
 | 
					            new_ts.update({dt: self.get(dt, closest=closest)[1]})
 | 
				
			||||||
 | 
					        # new_ts: dict = {dt: self.get(dt, closest=closest)[1] for dt in new_dates}
 | 
				
			||||||
        output_ts: TimeSeries = TimeSeries(new_ts, frequency=to_frequency.symbol)
 | 
					        output_ts: TimeSeries = TimeSeries(new_ts, frequency=to_frequency.symbol)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return output_ts
 | 
					        return output_ts
 | 
				
			||||||
@ -780,6 +783,67 @@ class TimeSeries(TimeSeriesCore):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return statistics.mean(self.values)
 | 
					        return statistics.mean(self.values)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def transform(
 | 
				
			||||||
 | 
					        self, to_frequency: Literal["W", "M", "Q", "H", "Y"], method: Literal["sum", "mean"], eomonth: bool = False
 | 
				
			||||||
 | 
					    ) -> TimeSeries:
 | 
				
			||||||
 | 
					        """Transform a time series object into a lower frequency object with an aggregation function.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Parameters
 | 
				
			||||||
 | 
					        ----------
 | 
				
			||||||
 | 
					        to_frequency:
 | 
				
			||||||
 | 
					            Frequency to which the time series needs to be transformed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        method:
 | 
				
			||||||
 | 
					            Aggregation method to be used. Can be either mean or sum
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        eomonth:
 | 
				
			||||||
 | 
					            User end of month dates. Only applicable for frequencies monthly and lower.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Returns
 | 
				
			||||||
 | 
					        -------
 | 
				
			||||||
 | 
					            Returns a TimeSeries object
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Raises
 | 
				
			||||||
 | 
					        -------
 | 
				
			||||||
 | 
					            ValueError:
 | 
				
			||||||
 | 
					                * If invalid input is passed for frequency
 | 
				
			||||||
 | 
					                * if invalid input is passed for method
 | 
				
			||||||
 | 
					                * If to_frequency is higher than the current frequency
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            to_frequency: Frequency = getattr(AllFrequencies, to_frequency)
 | 
				
			||||||
 | 
					        except AttributeError:
 | 
				
			||||||
 | 
					            raise ValueError(f"Invalid argument for to_frequency {to_frequency}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if to_frequency.days <= self.frequency.days:
 | 
				
			||||||
 | 
					            raise ValueError("TimeSeries can be only shrunk to a lower frequency")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if method not in ["sum", "mean"]:
 | 
				
			||||||
 | 
					            raise ValueError(f"Method not recognised: {method}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dates = create_date_series(
 | 
				
			||||||
 | 
					            self.start_date,
 | 
				
			||||||
 | 
					            self.end_date
 | 
				
			||||||
 | 
					            + datetime.timedelta(to_frequency.days),  # need extra date at the end for calculation of last value
 | 
				
			||||||
 | 
					            to_frequency.symbol,
 | 
				
			||||||
 | 
					            ensure_coverage=True,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        prev_date = dates[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        new_ts_dict = {}
 | 
				
			||||||
 | 
					        for date in dates[1:]:
 | 
				
			||||||
 | 
					            cur_data = self[(self.dates >= prev_date) & (self.dates < date)]
 | 
				
			||||||
 | 
					            if method == "sum":
 | 
				
			||||||
 | 
					                value = sum(cur_data.values)
 | 
				
			||||||
 | 
					            elif method == "mean":
 | 
				
			||||||
 | 
					                value = cur_data.mean()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            new_ts_dict.update({prev_date: value})
 | 
				
			||||||
 | 
					            prev_date = date
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.__class__(new_ts_dict, to_frequency.symbol)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def _preprocess_csv(file_path: str | pathlib.Path, delimiter: str = ",", encoding: str = "utf-8") -> List[list]:
 | 
					def _preprocess_csv(file_path: str | pathlib.Path, delimiter: str = ",", encoding: str = "utf-8") -> List[list]:
 | 
				
			||||||
    """Preprocess csv data"""
 | 
					    """Preprocess csv data"""
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								requirements.txt
									
									
									
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								requirements.txt
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										570
									
								
								testing.ipynb
									
									
									
									
									
								
							
							
						
						
									
										570
									
								
								testing.ipynb
									
									
									
									
									
								
							@ -2,38 +2,21 @@
 | 
				
			|||||||
 "cells": [
 | 
					 "cells": [
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
   "cell_type": "code",
 | 
					   "cell_type": "code",
 | 
				
			||||||
   "execution_count": 1,
 | 
					   "execution_count": 2,
 | 
				
			||||||
   "id": "e1ecfa55",
 | 
					   "id": "e40a5526-458a-4d11-8eaa-3b584f723738",
 | 
				
			||||||
   "metadata": {},
 | 
					   "metadata": {
 | 
				
			||||||
 | 
					    "tags": []
 | 
				
			||||||
 | 
					   },
 | 
				
			||||||
   "outputs": [],
 | 
					   "outputs": [],
 | 
				
			||||||
   "source": [
 | 
					   "source": [
 | 
				
			||||||
    "import fincal as fc"
 | 
					    "import fincal as fc\n",
 | 
				
			||||||
 | 
					    "import datetime\n",
 | 
				
			||||||
 | 
					    "from dateutil.relativedelta import relativedelta"
 | 
				
			||||||
   ]
 | 
					   ]
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
   "cell_type": "code",
 | 
					   "cell_type": "code",
 | 
				
			||||||
   "execution_count": 2,
 | 
					   "execution_count": 2,
 | 
				
			||||||
   "id": "ccac3896",
 | 
					 | 
				
			||||||
   "metadata": {},
 | 
					 | 
				
			||||||
   "outputs": [
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
     "data": {
 | 
					 | 
				
			||||||
      "text/plain": [
 | 
					 | 
				
			||||||
       "fincal.fincal.TimeSeries"
 | 
					 | 
				
			||||||
      ]
 | 
					 | 
				
			||||||
     },
 | 
					 | 
				
			||||||
     "execution_count": 2,
 | 
					 | 
				
			||||||
     "metadata": {},
 | 
					 | 
				
			||||||
     "output_type": "execute_result"
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
   ],
 | 
					 | 
				
			||||||
   "source": [
 | 
					 | 
				
			||||||
    "fc.TimeSeries"
 | 
					 | 
				
			||||||
   ]
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  {
 | 
					 | 
				
			||||||
   "cell_type": "code",
 | 
					 | 
				
			||||||
   "execution_count": 3,
 | 
					 | 
				
			||||||
   "id": "a54bfbdf",
 | 
					   "id": "a54bfbdf",
 | 
				
			||||||
   "metadata": {},
 | 
					   "metadata": {},
 | 
				
			||||||
   "outputs": [],
 | 
					   "outputs": [],
 | 
				
			||||||
@ -41,8 +24,8 @@
 | 
				
			|||||||
    "data = [\n",
 | 
					    "data = [\n",
 | 
				
			||||||
    "    (\"2022-01-01\", 10),\n",
 | 
					    "    (\"2022-01-01\", 10),\n",
 | 
				
			||||||
    "    (\"2022-01-02\", 12),\n",
 | 
					    "    (\"2022-01-02\", 12),\n",
 | 
				
			||||||
    "    (\"2022-01-03\", 14)\n",
 | 
					    "    (\"2022-01-03\", 14),\n",
 | 
				
			||||||
    "    # (\"2022-01-04\", 16),\n",
 | 
					    "    (\"2022-01-04\", 16)\n",
 | 
				
			||||||
    "    # (\"2022-01-06\", 18),\n",
 | 
					    "    # (\"2022-01-06\", 18),\n",
 | 
				
			||||||
    "    # (\"2022-01-07\", 20),\n",
 | 
					    "    # (\"2022-01-07\", 20),\n",
 | 
				
			||||||
    "    # (\"2022-01-09\", 22),\n",
 | 
					    "    # (\"2022-01-09\", 22),\n",
 | 
				
			||||||
@ -57,52 +40,70 @@
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
   "cell_type": "code",
 | 
					   "cell_type": "code",
 | 
				
			||||||
   "execution_count": 5,
 | 
					   "execution_count": 3,
 | 
				
			||||||
   "id": "fcc5f8f1",
 | 
					   "id": "fcc5f8f1",
 | 
				
			||||||
   "metadata": {},
 | 
					   "metadata": {},
 | 
				
			||||||
   "outputs": [
 | 
					   "outputs": [
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
     "data": {
 | 
					     "data": {
 | 
				
			||||||
      "text/plain": [
 | 
					      "text/plain": [
 | 
				
			||||||
       "TimeSeries([(datetime.datetime(2022, 1, 1, 0, 0), 10),\n",
 | 
					       "TimeSeries([(datetime.datetime(2022, 1, 1, 0, 0), 10.0),\n",
 | 
				
			||||||
       "\t(datetime.datetime(2022, 1, 2, 0, 0), 12),\n",
 | 
					       "\t(datetime.datetime(2022, 1, 2, 0, 0), 12.0),\n",
 | 
				
			||||||
       "\t(datetime.datetime(2022, 1, 3, 0, 0), 14)], frequency='M')"
 | 
					       "\t(datetime.datetime(2022, 1, 3, 0, 0), 14.0),\n",
 | 
				
			||||||
 | 
					       "\t(datetime.datetime(2022, 1, 4, 0, 0), 16.0)], frequency='D')"
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
     },
 | 
					     },
 | 
				
			||||||
     "execution_count": 5,
 | 
					     "execution_count": 3,
 | 
				
			||||||
     "metadata": {},
 | 
					     "metadata": {},
 | 
				
			||||||
     "output_type": "execute_result"
 | 
					     "output_type": "execute_result"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
   ],
 | 
					   ],
 | 
				
			||||||
   "source": [
 | 
					   "source": [
 | 
				
			||||||
    "ts = fc.TimeSeries(data, 'M')\n",
 | 
					    "ts = fc.TimeSeries(data, 'D')\n",
 | 
				
			||||||
 | 
					    "ts2 = fc.TimeSeries(data, 'D')\n",
 | 
				
			||||||
    "ts"
 | 
					    "ts"
 | 
				
			||||||
   ]
 | 
					   ]
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
   "cell_type": "code",
 | 
					   "cell_type": "code",
 | 
				
			||||||
   "execution_count": 7,
 | 
					   "execution_count": 21,
 | 
				
			||||||
   "id": "c9e9cb1b",
 | 
					   "id": "c091da16-d3a2-4d5b-93da-099d67373932",
 | 
				
			||||||
   "metadata": {},
 | 
					   "metadata": {},
 | 
				
			||||||
   "outputs": [
 | 
					   "outputs": [
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
     "data": {
 | 
					     "data": {
 | 
				
			||||||
      "text/plain": [
 | 
					      "text/plain": [
 | 
				
			||||||
       "TimeSeries([(datetime.datetime(2022, 1, 1, 0, 0), 10),\n",
 | 
					       "Series([datetime.datetime(2021, 1, 1, 0, 0), datetime.datetime(2021, 1, 2, 0, 0)], data_type='datetime')"
 | 
				
			||||||
       "\t(datetime.datetime(2022, 1, 2, 0, 0), 12),\n",
 | 
					 | 
				
			||||||
       "\t(datetime.datetime(2022, 1, 3, 0, 0), 14),\n",
 | 
					 | 
				
			||||||
       "\t(datetime.datetime(2022, 1, 4, 0, 0), 15),\n",
 | 
					 | 
				
			||||||
       "\t(datetime.datetime(2022, 1, 5, 0, 0), 16)], frequency='M')"
 | 
					 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
     },
 | 
					     },
 | 
				
			||||||
     "execution_count": 7,
 | 
					     "execution_count": 21,
 | 
				
			||||||
     "metadata": {},
 | 
					     "metadata": {},
 | 
				
			||||||
     "output_type": "execute_result"
 | 
					     "output_type": "execute_result"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
   ],
 | 
					   ],
 | 
				
			||||||
   "source": [
 | 
					   "source": [
 | 
				
			||||||
    "ts['2022-01-04'] = 15\n",
 | 
					    "fc.Series(['2021-01-01', '2021-01-02'], data_type='date')"
 | 
				
			||||||
    "ts"
 | 
					   ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					   "cell_type": "code",
 | 
				
			||||||
 | 
					   "execution_count": 15,
 | 
				
			||||||
 | 
					   "id": "77fc30d8-2843-40c4-9842-d943e6ef9813",
 | 
				
			||||||
 | 
					   "metadata": {},
 | 
				
			||||||
 | 
					   "outputs": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					     "data": {
 | 
				
			||||||
 | 
					      "text/plain": [
 | 
				
			||||||
 | 
					       "Series([11.0, 14.0, 17.0, 20.0], data_type='float')"
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					     "execution_count": 15,
 | 
				
			||||||
 | 
					     "metadata": {},
 | 
				
			||||||
 | 
					     "output_type": "execute_result"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					   ],
 | 
				
			||||||
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "ts.values + fc.Series([1, 2, 3, 4])"
 | 
				
			||||||
   ]
 | 
					   ]
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
@ -112,20 +113,16 @@
 | 
				
			|||||||
   "metadata": {},
 | 
					   "metadata": {},
 | 
				
			||||||
   "outputs": [
 | 
					   "outputs": [
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
     "data": {
 | 
					     "ename": "ValueError",
 | 
				
			||||||
      "text/plain": [
 | 
					     "evalue": "TimeSeries can be only expanded to a higher frequency",
 | 
				
			||||||
       "TimeSeries([(datetime.datetime(2022, 1, 1, 0, 0), 10),\n",
 | 
					     "output_type": "error",
 | 
				
			||||||
       "\t    (datetime.datetime(2022, 1, 8, 0, 0), 20),\n",
 | 
					     "traceback": [
 | 
				
			||||||
       "\t    (datetime.datetime(2022, 1, 15, 0, 0), 28)\n",
 | 
					      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
 | 
				
			||||||
       "\t    ...\n",
 | 
					      "\u001b[0;31mValueError\u001b[0m                                Traceback (most recent call last)",
 | 
				
			||||||
       "\t    (datetime.datetime(2022, 12, 17, 0, 0), 28),\n",
 | 
					      "Input \u001b[0;32mIn [8]\u001b[0m, in \u001b[0;36m<cell line: 1>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mts\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mexpand\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mW\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mffill\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m\n",
 | 
				
			||||||
       "\t    (datetime.datetime(2022, 12, 24, 0, 0), 28),\n",
 | 
					      "File \u001b[0;32m~/Documents/projects/fincal/fincal/fincal.py:624\u001b[0m, in \u001b[0;36mTimeSeries.expand\u001b[0;34m(self, to_frequency, method, skip_weekends, eomonth)\u001b[0m\n\u001b[1;32m    621\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mInvalid argument for to_frequency \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mto_frequency\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m    623\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m to_frequency\u001b[38;5;241m.\u001b[39mdays \u001b[38;5;241m>\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfrequency\u001b[38;5;241m.\u001b[39mdays:\n\u001b[0;32m--> 624\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mValueError\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mTimeSeries can be only expanded to a higher frequency\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m    626\u001b[0m new_dates \u001b[38;5;241m=\u001b[39m create_date_series(\n\u001b[1;32m    627\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstart_date,\n\u001b[1;32m    628\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mend_date,\n\u001b[0;32m   (...)\u001b[0m\n\u001b[1;32m    632\u001b[0m     ensure_coverage\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m,\n\u001b[1;32m    633\u001b[0m )\n\u001b[1;32m    635\u001b[0m closest: \u001b[38;5;28mstr\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mprevious\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m method \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mffill\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mnext\u001b[39m\u001b[38;5;124m\"\u001b[39m\n",
 | 
				
			||||||
       "\t    (datetime.datetime(2022, 12, 31, 0, 0), 28)], frequency='W')"
 | 
					      "\u001b[0;31mValueError\u001b[0m: TimeSeries can be only expanded to a higher frequency"
 | 
				
			||||||
      ]
 | 
					     ]
 | 
				
			||||||
     },
 | 
					 | 
				
			||||||
     "execution_count": 8,
 | 
					 | 
				
			||||||
     "metadata": {},
 | 
					 | 
				
			||||||
     "output_type": "execute_result"
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
   ],
 | 
					   ],
 | 
				
			||||||
   "source": [
 | 
					   "source": [
 | 
				
			||||||
@ -159,48 +156,72 @@
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
   "cell_type": "code",
 | 
					   "cell_type": "code",
 | 
				
			||||||
   "execution_count": 13,
 | 
					   "execution_count": 2,
 | 
				
			||||||
   "id": "36eefec7-7dbf-4a28-ac50-2e502d9d6864",
 | 
					   "id": "9431eb8c",
 | 
				
			||||||
   "metadata": {},
 | 
					   "metadata": {},
 | 
				
			||||||
   "outputs": [],
 | 
					   "outputs": [],
 | 
				
			||||||
   "source": [
 | 
					   "source": [
 | 
				
			||||||
    "weekly_data = [('2017-01-01', 67),\n",
 | 
					    "from fincal.utils import _is_eomonth"
 | 
				
			||||||
    "('2017-01-08', 79),\n",
 | 
					 | 
				
			||||||
    "('2017-01-15', 73),\n",
 | 
					 | 
				
			||||||
    "('2017-01-22', 63),\n",
 | 
					 | 
				
			||||||
    "('2017-01-29', 85),\n",
 | 
					 | 
				
			||||||
    "('2017-02-05', 66),\n",
 | 
					 | 
				
			||||||
    "('2017-02-12', 78),\n",
 | 
					 | 
				
			||||||
    "('2017-02-19', 75),\n",
 | 
					 | 
				
			||||||
    "('2017-02-26', 76),\n",
 | 
					 | 
				
			||||||
    "('2017-03-05', 82),\n",
 | 
					 | 
				
			||||||
    "('2017-03-12', 85),\n",
 | 
					 | 
				
			||||||
    "('2017-03-19', 63),\n",
 | 
					 | 
				
			||||||
    "('2017-03-26', 78),\n",
 | 
					 | 
				
			||||||
    "('2017-04-02', 65),\n",
 | 
					 | 
				
			||||||
    "('2017-04-09', 85),\n",
 | 
					 | 
				
			||||||
    "('2017-04-16', 86),\n",
 | 
					 | 
				
			||||||
    "('2017-04-23', 67),\n",
 | 
					 | 
				
			||||||
    "('2017-04-30', 65),\n",
 | 
					 | 
				
			||||||
    "('2017-05-07', 82),\n",
 | 
					 | 
				
			||||||
    "('2017-05-14', 73),\n",
 | 
					 | 
				
			||||||
    "('2017-05-21', 78),\n",
 | 
					 | 
				
			||||||
    "('2017-05-28', 74),\n",
 | 
					 | 
				
			||||||
    "('2017-06-04', 62),\n",
 | 
					 | 
				
			||||||
    "('2017-06-11', 84),\n",
 | 
					 | 
				
			||||||
    "('2017-06-18', 83)]"
 | 
					 | 
				
			||||||
   ]
 | 
					   ]
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
   "cell_type": "code",
 | 
					   "cell_type": "code",
 | 
				
			||||||
   "execution_count": 15,
 | 
					   "execution_count": 5,
 | 
				
			||||||
   "id": "39bd8598-ab0f-4c81-8428-ad8248e686d3",
 | 
					   "id": "36eefec7-7dbf-4a28-ac50-2e502d9d6864",
 | 
				
			||||||
   "metadata": {},
 | 
					   "metadata": {},
 | 
				
			||||||
   "outputs": [],
 | 
					   "outputs": [],
 | 
				
			||||||
   "source": [
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "weekly_data = [\n",
 | 
				
			||||||
 | 
					    "    ('2018-01-31', 26),\n",
 | 
				
			||||||
 | 
					    "    ('2018-02-28', 44),\n",
 | 
				
			||||||
 | 
					    "    ('2018-03-30', 40),\n",
 | 
				
			||||||
 | 
					    "    ('2018-04-30', 36),\n",
 | 
				
			||||||
 | 
					    "    ('2018-05-31', 31),\n",
 | 
				
			||||||
 | 
					    "    ('2018-06-30', 45),\n",
 | 
				
			||||||
 | 
					    "    ('2018-07-30', 31),\n",
 | 
				
			||||||
 | 
					    "    ('2018-08-31', 42),\n",
 | 
				
			||||||
 | 
					    "    ('2018-09-30', 40),\n",
 | 
				
			||||||
 | 
					    "    ('2018-10-30', 30),\n",
 | 
				
			||||||
 | 
					    "    ('2018-11-30', 35),\n",
 | 
				
			||||||
 | 
					    "    ('2018-12-31', 37),\n",
 | 
				
			||||||
 | 
					    "    ('2019-01-31', 31),\n",
 | 
				
			||||||
 | 
					    "    ('2019-02-28', 44),\n",
 | 
				
			||||||
 | 
					    "    ('2019-03-31', 31),\n",
 | 
				
			||||||
 | 
					    "    ('2019-04-29', 32),\n",
 | 
				
			||||||
 | 
					    "    ('2019-05-30', 39),\n",
 | 
				
			||||||
 | 
					    "    ('2019-06-30', 27),\n",
 | 
				
			||||||
 | 
					    "    ('2019-07-31', 35),\n",
 | 
				
			||||||
 | 
					    "    ('2019-08-31', 33),\n",
 | 
				
			||||||
 | 
					    "    ('2019-09-30', 29),\n",
 | 
				
			||||||
 | 
					    "    ('2019-10-30', 26),\n",
 | 
				
			||||||
 | 
					    "    ('2019-11-30', 39),\n",
 | 
				
			||||||
 | 
					    "    ('2019-12-30', 30),\n",
 | 
				
			||||||
 | 
					    "    ('2020-01-30', 29)\n",
 | 
				
			||||||
 | 
					    "]\n",
 | 
				
			||||||
    "week_ts = fc.TimeSeries(weekly_data, 'W')"
 | 
					    "week_ts = fc.TimeSeries(weekly_data, 'W')"
 | 
				
			||||||
   ]
 | 
					   ]
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					   "cell_type": "code",
 | 
				
			||||||
 | 
					   "execution_count": 6,
 | 
				
			||||||
 | 
					   "id": "e1071f90",
 | 
				
			||||||
 | 
					   "metadata": {},
 | 
				
			||||||
 | 
					   "outputs": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					     "data": {
 | 
				
			||||||
 | 
					      "text/plain": [
 | 
				
			||||||
 | 
					       "False"
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					     "execution_count": 6,
 | 
				
			||||||
 | 
					     "metadata": {},
 | 
				
			||||||
 | 
					     "output_type": "execute_result"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					   ],
 | 
				
			||||||
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "_is_eomonth(week_ts.dates)"
 | 
				
			||||||
 | 
					   ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
   "cell_type": "code",
 | 
					   "cell_type": "code",
 | 
				
			||||||
   "execution_count": 22,
 | 
					   "execution_count": 22,
 | 
				
			||||||
@ -227,31 +248,10 @@
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
   "cell_type": "code",
 | 
					   "cell_type": "code",
 | 
				
			||||||
   "execution_count": 23,
 | 
					   "execution_count": null,
 | 
				
			||||||
   "id": "a549c5c0-c89a-4cc3-b396-c4afa77a9879",
 | 
					   "id": "a549c5c0-c89a-4cc3-b396-c4afa77a9879",
 | 
				
			||||||
   "metadata": {},
 | 
					   "metadata": {},
 | 
				
			||||||
   "outputs": [
 | 
					   "outputs": [],
 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
     "ename": "OverflowError",
 | 
					 | 
				
			||||||
     "evalue": "date value out of range",
 | 
					 | 
				
			||||||
     "output_type": "error",
 | 
					 | 
				
			||||||
     "traceback": [
 | 
					 | 
				
			||||||
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
 | 
					 | 
				
			||||||
      "\u001b[0;31mKeyError\u001b[0m                                  Traceback (most recent call last)",
 | 
					 | 
				
			||||||
      "File \u001b[0;32m~/Documents/projects/fincal/fincal/core.py:405\u001b[0m, in \u001b[0;36mTimeSeriesCore.get\u001b[0;34m(self, date, default, closest)\u001b[0m\n\u001b[1;32m    404\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 405\u001b[0m     item \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_get_item_from_date\u001b[49m\u001b[43m(\u001b[49m\u001b[43mdate\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    406\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m item\n",
 | 
					 | 
				
			||||||
      "File \u001b[0;32m~/Documents/projects/fincal/fincal/core.py:69\u001b[0m, in \u001b[0;36mdate_parser.<locals>.parse_dates.<locals>.wrapper_func\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m     68\u001b[0m         args[j] \u001b[38;5;241m=\u001b[39m parsed_date\n\u001b[0;32m---> 69\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
 | 
					 | 
				
			||||||
      "File \u001b[0;32m~/Documents/projects/fincal/fincal/core.py:328\u001b[0m, in \u001b[0;36mTimeSeriesCore._get_item_from_date\u001b[0;34m(self, date)\u001b[0m\n\u001b[1;32m    326\u001b[0m \u001b[38;5;129m@date_parser\u001b[39m(\u001b[38;5;241m1\u001b[39m)\n\u001b[1;32m    327\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m_get_item_from_date\u001b[39m(\u001b[38;5;28mself\u001b[39m, date: \u001b[38;5;28mstr\u001b[39m \u001b[38;5;241m|\u001b[39m datetime\u001b[38;5;241m.\u001b[39mdatetime):\n\u001b[0;32m--> 328\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m date, \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mdata\u001b[49m\u001b[43m[\u001b[49m\u001b[43mdate\u001b[49m\u001b[43m]\u001b[49m\n",
 | 
					 | 
				
			||||||
      "\u001b[0;31mKeyError\u001b[0m: datetime.datetime(1, 1, 1, 0, 0)",
 | 
					 | 
				
			||||||
      "\nDuring handling of the above exception, another exception occurred:\n",
 | 
					 | 
				
			||||||
      "\u001b[0;31mOverflowError\u001b[0m                             Traceback (most recent call last)",
 | 
					 | 
				
			||||||
      "Input \u001b[0;32mIn [23]\u001b[0m, in \u001b[0;36m<cell line: 1>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mweek_ts\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43msync\u001b[49m\u001b[43m(\u001b[49m\u001b[43mts\u001b[49m\u001b[43m)\u001b[49m\n",
 | 
					 | 
				
			||||||
      "File \u001b[0;32m~/Documents/projects/fincal/fincal/fincal.py:733\u001b[0m, in \u001b[0;36mTimeSeries.sync\u001b[0;34m(self, other, fill_method)\u001b[0m\n\u001b[1;32m    731\u001b[0m         new_other[dt] \u001b[38;5;241m=\u001b[39m other[dt][\u001b[38;5;241m1\u001b[39m]\n\u001b[1;32m    732\u001b[0m     \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m--> 733\u001b[0m         new_other[dt] \u001b[38;5;241m=\u001b[39m other\u001b[38;5;241m.\u001b[39mget(dt, closest\u001b[38;5;241m=\u001b[39mclosest)[\u001b[38;5;241m1\u001b[39m]\n\u001b[1;32m    735\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m\u001b[38;5;18m__class__\u001b[39m(new_other, frequency\u001b[38;5;241m=\u001b[39mother\u001b[38;5;241m.\u001b[39mfrequency\u001b[38;5;241m.\u001b[39msymbol)\n",
 | 
					 | 
				
			||||||
      "File \u001b[0;32m~/Documents/projects/fincal/fincal/core.py:69\u001b[0m, in \u001b[0;36mdate_parser.<locals>.parse_dates.<locals>.wrapper_func\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m     67\u001b[0m     \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m     68\u001b[0m         args[j] \u001b[38;5;241m=\u001b[39m parsed_date\n\u001b[0;32m---> 69\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n",
 | 
					 | 
				
			||||||
      "File \u001b[0;32m~/Documents/projects/fincal/fincal/core.py:408\u001b[0m, in \u001b[0;36mTimeSeriesCore.get\u001b[0;34m(self, date, default, closest)\u001b[0m\n\u001b[1;32m    406\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m item\n\u001b[1;32m    407\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m:\n\u001b[0;32m--> 408\u001b[0m     date \u001b[38;5;241m+\u001b[39m\u001b[38;5;241m=\u001b[39m delta\n",
 | 
					 | 
				
			||||||
      "\u001b[0;31mOverflowError\u001b[0m: date value out of range"
 | 
					 | 
				
			||||||
     ]
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
   ],
 | 
					 | 
				
			||||||
   "source": [
 | 
					   "source": [
 | 
				
			||||||
    "week_ts.sync(ts)"
 | 
					    "week_ts.sync(ts)"
 | 
				
			||||||
   ]
 | 
					   ]
 | 
				
			||||||
@ -277,8 +277,8 @@
 | 
				
			|||||||
     "output_type": "stream",
 | 
					     "output_type": "stream",
 | 
				
			||||||
     "text": [
 | 
					     "text": [
 | 
				
			||||||
      "['date', 'nav']\n",
 | 
					      "['date', 'nav']\n",
 | 
				
			||||||
      "CPU times: user 56.9 ms, sys: 3.3 ms, total: 60.2 ms\n",
 | 
					      "CPU times: user 57.5 ms, sys: 3.38 ms, total: 60.8 ms\n",
 | 
				
			||||||
      "Wall time: 60.2 ms\n"
 | 
					      "Wall time: 60.5 ms\n"
 | 
				
			||||||
     ]
 | 
					     ]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
   ],
 | 
					   ],
 | 
				
			||||||
@ -289,7 +289,7 @@
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
   "cell_type": "code",
 | 
					   "cell_type": "code",
 | 
				
			||||||
   "execution_count": 3,
 | 
					   "execution_count": 7,
 | 
				
			||||||
   "id": "b7c176d4-d89f-4bda-9d67-75463eb90468",
 | 
					   "id": "b7c176d4-d89f-4bda-9d67-75463eb90468",
 | 
				
			||||||
   "metadata": {},
 | 
					   "metadata": {},
 | 
				
			||||||
   "outputs": [
 | 
					   "outputs": [
 | 
				
			||||||
@ -297,9 +297,9 @@
 | 
				
			|||||||
     "name": "stdout",
 | 
					     "name": "stdout",
 | 
				
			||||||
     "output_type": "stream",
 | 
					     "output_type": "stream",
 | 
				
			||||||
     "text": [
 | 
					     "text": [
 | 
				
			||||||
      "(datetime.datetime(2022, 2, 9, 0, 0), 311.209991)\n",
 | 
					 | 
				
			||||||
      "(datetime.datetime(2022, 2, 10, 0, 0), 302.380005)\n",
 | 
					 | 
				
			||||||
      "(datetime.datetime(2022, 2, 11, 0, 0), 295.040009)\n",
 | 
					      "(datetime.datetime(2022, 2, 11, 0, 0), 295.040009)\n",
 | 
				
			||||||
 | 
					      "(datetime.datetime(2022, 2, 12, 0, 0), 296.0)\n",
 | 
				
			||||||
 | 
					      "(datetime.datetime(2022, 2, 13, 0, 0), 296.0)\n",
 | 
				
			||||||
      "(datetime.datetime(2022, 2, 14, 0, 0), 295.0)\n",
 | 
					      "(datetime.datetime(2022, 2, 14, 0, 0), 295.0)\n",
 | 
				
			||||||
      "(datetime.datetime(2022, 2, 15, 0, 0), 300.470001)\n",
 | 
					      "(datetime.datetime(2022, 2, 15, 0, 0), 300.470001)\n",
 | 
				
			||||||
      "(datetime.datetime(2022, 2, 16, 0, 0), 299.5)\n",
 | 
					      "(datetime.datetime(2022, 2, 16, 0, 0), 299.5)\n",
 | 
				
			||||||
@ -315,7 +315,7 @@
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
   "cell_type": "code",
 | 
					   "cell_type": "code",
 | 
				
			||||||
   "execution_count": 4,
 | 
					   "execution_count": 6,
 | 
				
			||||||
   "id": "69c57754-a6fb-4881-9359-ba17c7fb8be5",
 | 
					   "id": "69c57754-a6fb-4881-9359-ba17c7fb8be5",
 | 
				
			||||||
   "metadata": {},
 | 
					   "metadata": {},
 | 
				
			||||||
   "outputs": [
 | 
					   "outputs": [
 | 
				
			||||||
@ -323,19 +323,19 @@
 | 
				
			|||||||
     "name": "stdout",
 | 
					     "name": "stdout",
 | 
				
			||||||
     "output_type": "stream",
 | 
					     "output_type": "stream",
 | 
				
			||||||
     "text": [
 | 
					     "text": [
 | 
				
			||||||
      "CPU times: user 1.85 ms, sys: 143 µs, total: 1.99 ms\n",
 | 
					      "CPU times: user 1.76 ms, sys: 123 µs, total: 1.88 ms\n",
 | 
				
			||||||
      "Wall time: 2 ms\n"
 | 
					      "Wall time: 1.88 ms\n"
 | 
				
			||||||
     ]
 | 
					     ]
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
   ],
 | 
					   ],
 | 
				
			||||||
   "source": [
 | 
					   "source": [
 | 
				
			||||||
    "%%time\n",
 | 
					    "%%time\n",
 | 
				
			||||||
    "ts['2022-02-12'] = 295"
 | 
					    "ts['2022-02-12'] = 296"
 | 
				
			||||||
   ]
 | 
					   ]
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  {
 | 
					  {
 | 
				
			||||||
   "cell_type": "code",
 | 
					   "cell_type": "code",
 | 
				
			||||||
   "execution_count": 5,
 | 
					   "execution_count": 8,
 | 
				
			||||||
   "id": "7aa02023-406e-4700-801c-c06390ddf914",
 | 
					   "id": "7aa02023-406e-4700-801c-c06390ddf914",
 | 
				
			||||||
   "metadata": {},
 | 
					   "metadata": {},
 | 
				
			||||||
   "outputs": [
 | 
					   "outputs": [
 | 
				
			||||||
@ -343,8 +343,8 @@
 | 
				
			|||||||
     "name": "stdout",
 | 
					     "name": "stdout",
 | 
				
			||||||
     "output_type": "stream",
 | 
					     "output_type": "stream",
 | 
				
			||||||
     "text": [
 | 
					     "text": [
 | 
				
			||||||
      "CPU times: user 3.7 ms, sys: 121 µs, total: 3.82 ms\n",
 | 
					      "CPU times: user 3.61 ms, sys: 68 µs, total: 3.68 ms\n",
 | 
				
			||||||
      "Wall time: 3.84 ms\n"
 | 
					      "Wall time: 3.7 ms\n"
 | 
				
			||||||
     ]
 | 
					     ]
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
@ -355,7 +355,7 @@
 | 
				
			|||||||
       " 'drawdown': -0.7456453305351521}"
 | 
					       " 'drawdown': -0.7456453305351521}"
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
     },
 | 
					     },
 | 
				
			||||||
     "execution_count": 5,
 | 
					     "execution_count": 8,
 | 
				
			||||||
     "metadata": {},
 | 
					     "metadata": {},
 | 
				
			||||||
     "output_type": "execute_result"
 | 
					     "output_type": "execute_result"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -364,9 +364,335 @@
 | 
				
			|||||||
    "%%time\n",
 | 
					    "%%time\n",
 | 
				
			||||||
    "ts.max_drawdown()"
 | 
					    "ts.max_drawdown()"
 | 
				
			||||||
   ]
 | 
					   ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					   "cell_type": "code",
 | 
				
			||||||
 | 
					   "execution_count": 9,
 | 
				
			||||||
 | 
					   "id": "72cb4da4-1318-4b9b-b563-adac46accfb3",
 | 
				
			||||||
 | 
					   "metadata": {},
 | 
				
			||||||
 | 
					   "outputs": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					     "data": {
 | 
				
			||||||
 | 
					      "text/plain": [
 | 
				
			||||||
 | 
					       "True"
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					     "execution_count": 9,
 | 
				
			||||||
 | 
					     "metadata": {},
 | 
				
			||||||
 | 
					     "output_type": "execute_result"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					   ],
 | 
				
			||||||
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "from typing import Mapping\n",
 | 
				
			||||||
 | 
					    "isinstance(ts, Mapping)"
 | 
				
			||||||
 | 
					   ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					   "cell_type": "code",
 | 
				
			||||||
 | 
					   "execution_count": 23,
 | 
				
			||||||
 | 
					   "id": "96bbecbf",
 | 
				
			||||||
 | 
					   "metadata": {},
 | 
				
			||||||
 | 
					   "outputs": [],
 | 
				
			||||||
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "import fincal as fc"
 | 
				
			||||||
 | 
					   ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					   "cell_type": "code",
 | 
				
			||||||
 | 
					   "execution_count": 24,
 | 
				
			||||||
 | 
					   "id": "19199c92",
 | 
				
			||||||
 | 
					   "metadata": {},
 | 
				
			||||||
 | 
					   "outputs": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					     "name": "stdout",
 | 
				
			||||||
 | 
					     "output_type": "stream",
 | 
				
			||||||
 | 
					     "text": [
 | 
				
			||||||
 | 
					      "['amfi_code', 'date', 'nav']\n"
 | 
				
			||||||
 | 
					     ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					     "name": "stderr",
 | 
				
			||||||
 | 
					     "output_type": "stream",
 | 
				
			||||||
 | 
					     "text": [
 | 
				
			||||||
 | 
					      "/Users/gourav/Documents/projects/fincal/fincal/core.py:308: UserWarning: The input data contains duplicate dates which have been ignored.\n",
 | 
				
			||||||
 | 
					      "  warnings.warn(\"The input data contains duplicate dates which have been ignored.\")\n"
 | 
				
			||||||
 | 
					     ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					     "data": {
 | 
				
			||||||
 | 
					      "text/plain": [
 | 
				
			||||||
 | 
					       "TimeSeries([(datetime.datetime(2013, 1, 2, 0, 0), 18.972),\n",
 | 
				
			||||||
 | 
					       "\t    (datetime.datetime(2013, 1, 3, 0, 0), 19.011),\n",
 | 
				
			||||||
 | 
					       "\t    (datetime.datetime(2013, 1, 4, 0, 0), 19.008)\n",
 | 
				
			||||||
 | 
					       "\t    ...\n",
 | 
				
			||||||
 | 
					       "\t    (datetime.datetime(2022, 2, 10, 0, 0), 86.5),\n",
 | 
				
			||||||
 | 
					       "\t    (datetime.datetime(2022, 2, 11, 0, 0), 85.226),\n",
 | 
				
			||||||
 | 
					       "\t    (datetime.datetime(2022, 2, 14, 0, 0), 82.533)], frequency='D')"
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					     "execution_count": 24,
 | 
				
			||||||
 | 
					     "metadata": {},
 | 
				
			||||||
 | 
					     "output_type": "execute_result"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					   ],
 | 
				
			||||||
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "ts = fc.read_csv('test_files/nav_history_daily - copy.csv', col_index=(1, 2), frequency='D', date_format='%d-%m-%y')\n",
 | 
				
			||||||
 | 
					    "ts"
 | 
				
			||||||
 | 
					   ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					   "cell_type": "code",
 | 
				
			||||||
 | 
					   "execution_count": 28,
 | 
				
			||||||
 | 
					   "id": "51c9ae9a",
 | 
				
			||||||
 | 
					   "metadata": {},
 | 
				
			||||||
 | 
					   "outputs": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					     "data": {
 | 
				
			||||||
 | 
					      "text/plain": [
 | 
				
			||||||
 | 
					       "0.12031455056454916"
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					     "execution_count": 28,
 | 
				
			||||||
 | 
					     "metadata": {},
 | 
				
			||||||
 | 
					     "output_type": "execute_result"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					   ],
 | 
				
			||||||
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "fc.sharpe_ratio(\n",
 | 
				
			||||||
 | 
					    "    ts,\n",
 | 
				
			||||||
 | 
					    "    risk_free_rate=0.06,\n",
 | 
				
			||||||
 | 
					    "    from_date='2013-02-04',\n",
 | 
				
			||||||
 | 
					    "    to_date='2022-02-14',\n",
 | 
				
			||||||
 | 
					    "    return_period_unit='months',\n",
 | 
				
			||||||
 | 
					    "    return_period_value=1\n",
 | 
				
			||||||
 | 
					    ")"
 | 
				
			||||||
 | 
					   ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					   "cell_type": "markdown",
 | 
				
			||||||
 | 
					   "id": "b3fb7b59-eaa3-41a5-b1ab-89d63b69edb0",
 | 
				
			||||||
 | 
					   "metadata": {},
 | 
				
			||||||
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "# Data generator"
 | 
				
			||||||
 | 
					   ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					   "cell_type": "code",
 | 
				
			||||||
 | 
					   "execution_count": 1,
 | 
				
			||||||
 | 
					   "id": "aead3e77-2670-4541-846a-5537b01f3d2e",
 | 
				
			||||||
 | 
					   "metadata": {},
 | 
				
			||||||
 | 
					   "outputs": [],
 | 
				
			||||||
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "import random\n",
 | 
				
			||||||
 | 
					    "import math\n",
 | 
				
			||||||
 | 
					    "import fincal as fc\n",
 | 
				
			||||||
 | 
					    "from typing import List\n",
 | 
				
			||||||
 | 
					    "import datetime\n",
 | 
				
			||||||
 | 
					    "from dateutil.relativedelta import relativedelta"
 | 
				
			||||||
 | 
					   ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					   "cell_type": "code",
 | 
				
			||||||
 | 
					   "execution_count": 2,
 | 
				
			||||||
 | 
					   "id": "f287e05f",
 | 
				
			||||||
 | 
					   "metadata": {},
 | 
				
			||||||
 | 
					   "outputs": [],
 | 
				
			||||||
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "def create_prices(s0: float, mu: float, sigma: float, num_prices: int) -> list:\n",
 | 
				
			||||||
 | 
					    "    \"\"\"Generates a price following a geometric brownian motion process based on the input of the arguments.\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "        Since this function is used only to generate data for tests, the seed is fixed as 1234.\n",
 | 
				
			||||||
 | 
					    "        Many of the tests rely on exact values generated using this seed.\n",
 | 
				
			||||||
 | 
					    "        If the seed is changed, those tests will fail.\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "    Parameters:\n",
 | 
				
			||||||
 | 
					    "    ------------\n",
 | 
				
			||||||
 | 
					    "    s0: float\n",
 | 
				
			||||||
 | 
					    "        Asset inital price.\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "    mu: float\n",
 | 
				
			||||||
 | 
					    "        Interest rate expressed annual terms.\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "    sigma: float\n",
 | 
				
			||||||
 | 
					    "        Volatility expressed annual terms.\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "    num_prices: int\n",
 | 
				
			||||||
 | 
					    "        number of prices to generate\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "    Returns:\n",
 | 
				
			||||||
 | 
					    "    --------\n",
 | 
				
			||||||
 | 
					    "        Returns a list of values generated using GBM algorithm\n",
 | 
				
			||||||
 | 
					    "    \"\"\"\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "    random.seed(1234)  # WARNING! Changing the seed will cause most tests to fail\n",
 | 
				
			||||||
 | 
					    "    all_values = []\n",
 | 
				
			||||||
 | 
					    "    for _ in range(num_prices):\n",
 | 
				
			||||||
 | 
					    "        s0 *= math.exp(\n",
 | 
				
			||||||
 | 
					    "            (mu - 0.5 * sigma**2) * (1.0 / 365.0) + sigma * math.sqrt(1.0 / 365.0) * random.gauss(mu=0, sigma=1)\n",
 | 
				
			||||||
 | 
					    "        )\n",
 | 
				
			||||||
 | 
					    "        all_values.append(round(s0, 2))\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "    return all_values\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "def sample_data_generator(\n",
 | 
				
			||||||
 | 
					    "    frequency: fc.Frequency,\n",
 | 
				
			||||||
 | 
					    "    num: int = 1000,\n",
 | 
				
			||||||
 | 
					    "    skip_weekends: bool = False,\n",
 | 
				
			||||||
 | 
					    "    mu: float = 0.1,\n",
 | 
				
			||||||
 | 
					    "    sigma: float = 0.05,\n",
 | 
				
			||||||
 | 
					    "    eomonth: bool = False,\n",
 | 
				
			||||||
 | 
					    ") -> List[tuple]:\n",
 | 
				
			||||||
 | 
					    "    \"\"\"Creates TimeSeries data\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "    Parameters:\n",
 | 
				
			||||||
 | 
					    "    -----------\n",
 | 
				
			||||||
 | 
					    "    frequency: Frequency\n",
 | 
				
			||||||
 | 
					    "        The frequency of the time series data to be generated.\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "    num: int\n",
 | 
				
			||||||
 | 
					    "        Number of date: value pairs to be generated.\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "    skip_weekends: bool\n",
 | 
				
			||||||
 | 
					    "        Whether weekends (saturday, sunday) should be skipped.\n",
 | 
				
			||||||
 | 
					    "        Gets used only if the frequency is daily.\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "    mu: float\n",
 | 
				
			||||||
 | 
					    "        Mean return for the values.\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "    sigma: float\n",
 | 
				
			||||||
 | 
					    "        standard deviation of the values.\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "    Returns:\n",
 | 
				
			||||||
 | 
					    "    --------\n",
 | 
				
			||||||
 | 
					    "        Returns a TimeSeries object\n",
 | 
				
			||||||
 | 
					    "    \"\"\"\n",
 | 
				
			||||||
 | 
					    "\n",
 | 
				
			||||||
 | 
					    "    start_date = datetime.datetime(2017, 1, 1)\n",
 | 
				
			||||||
 | 
					    "    timedelta_dict = {\n",
 | 
				
			||||||
 | 
					    "        frequency.freq_type: int(\n",
 | 
				
			||||||
 | 
					    "            frequency.value * num * (7 / 5 if frequency == fc.AllFrequencies.D and skip_weekends else 1)\n",
 | 
				
			||||||
 | 
					    "        )\n",
 | 
				
			||||||
 | 
					    "    }\n",
 | 
				
			||||||
 | 
					    "    end_date = start_date + relativedelta(**timedelta_dict)\n",
 | 
				
			||||||
 | 
					    "    dates = fc.create_date_series(start_date, end_date, frequency.symbol, skip_weekends=skip_weekends, eomonth=eomonth)\n",
 | 
				
			||||||
 | 
					    "    values = create_prices(1000, mu, sigma, num)\n",
 | 
				
			||||||
 | 
					    "    ts = list(zip(dates, values))\n",
 | 
				
			||||||
 | 
					    "    return ts\n"
 | 
				
			||||||
 | 
					   ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					   "cell_type": "code",
 | 
				
			||||||
 | 
					   "execution_count": 12,
 | 
				
			||||||
 | 
					   "id": "c85b5dd9-9a88-4608-ac58-1a141295f63f",
 | 
				
			||||||
 | 
					   "metadata": {},
 | 
				
			||||||
 | 
					   "outputs": [],
 | 
				
			||||||
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "data = sample_data_generator(num=261, frequency=fc.AllFrequencies.W)\n",
 | 
				
			||||||
 | 
					    "ts = fc.TimeSeries(data, \"W\")"
 | 
				
			||||||
 | 
					   ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					   "cell_type": "code",
 | 
				
			||||||
 | 
					   "execution_count": 13,
 | 
				
			||||||
 | 
					   "id": "0488a4d0-bca1-4341-9fae-1fd254adc0dc",
 | 
				
			||||||
 | 
					   "metadata": {},
 | 
				
			||||||
 | 
					   "outputs": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					     "data": {
 | 
				
			||||||
 | 
					      "text/plain": [
 | 
				
			||||||
 | 
					       "TimeSeries([(datetime.datetime(2017, 1, 1, 0, 0), 1003.03),\n",
 | 
				
			||||||
 | 
					       "\t    (datetime.datetime(2017, 1, 8, 0, 0), 1002.71),\n",
 | 
				
			||||||
 | 
					       "\t    (datetime.datetime(2017, 1, 15, 0, 0), 1008.77)\n",
 | 
				
			||||||
 | 
					       "\t    ...\n",
 | 
				
			||||||
 | 
					       "\t    (datetime.datetime(2021, 12, 12, 0, 0), 1107.21),\n",
 | 
				
			||||||
 | 
					       "\t    (datetime.datetime(2021, 12, 19, 0, 0), 1106.66),\n",
 | 
				
			||||||
 | 
					       "\t    (datetime.datetime(2021, 12, 26, 0, 0), 1104.32)], frequency='W')"
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					     "execution_count": 13,
 | 
				
			||||||
 | 
					     "metadata": {},
 | 
				
			||||||
 | 
					     "output_type": "execute_result"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					   ],
 | 
				
			||||||
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "ts"
 | 
				
			||||||
 | 
					   ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					   "cell_type": "code",
 | 
				
			||||||
 | 
					   "execution_count": 14,
 | 
				
			||||||
 | 
					   "id": "04624145-4fce-484c-aa69-0d17d159b598",
 | 
				
			||||||
 | 
					   "metadata": {},
 | 
				
			||||||
 | 
					   "outputs": [],
 | 
				
			||||||
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "tst = ts.transform('Q', 'mean', False)"
 | 
				
			||||||
 | 
					   ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					   "cell_type": "code",
 | 
				
			||||||
 | 
					   "execution_count": 16,
 | 
				
			||||||
 | 
					   "id": "75ed1666-5fc8-4707-bf42-62d44adcae18",
 | 
				
			||||||
 | 
					   "metadata": {},
 | 
				
			||||||
 | 
					   "outputs": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					     "data": {
 | 
				
			||||||
 | 
					      "text/plain": [
 | 
				
			||||||
 | 
					       "20"
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					     },
 | 
				
			||||||
 | 
					     "execution_count": 16,
 | 
				
			||||||
 | 
					     "metadata": {},
 | 
				
			||||||
 | 
					     "output_type": "execute_result"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					   ],
 | 
				
			||||||
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "len(tst)"
 | 
				
			||||||
 | 
					   ]
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					   "cell_type": "code",
 | 
				
			||||||
 | 
					   "execution_count": 15,
 | 
				
			||||||
 | 
					   "id": "bccd7d1c-2d57-444c-af68-290f476f2b05",
 | 
				
			||||||
 | 
					   "metadata": {},
 | 
				
			||||||
 | 
					   "outputs": [
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					     "name": "stdout",
 | 
				
			||||||
 | 
					     "output_type": "stream",
 | 
				
			||||||
 | 
					     "text": [
 | 
				
			||||||
 | 
					      "(datetime.datetime(2017, 1, 1, 0, 0), 1010.4553846153846)\n",
 | 
				
			||||||
 | 
					      "(datetime.datetime(2017, 4, 1, 0, 0), 1019.34)\n",
 | 
				
			||||||
 | 
					      "(datetime.datetime(2017, 7, 1, 0, 0), 1015.3515384615384)\n",
 | 
				
			||||||
 | 
					      "(datetime.datetime(2017, 10, 1, 0, 0), 1031.2892857142858)\n",
 | 
				
			||||||
 | 
					      "(datetime.datetime(2018, 1, 1, 0, 0), 1054.7216666666666)\n",
 | 
				
			||||||
 | 
					      "(datetime.datetime(2018, 4, 1, 0, 0), 1059.736153846154)\n",
 | 
				
			||||||
 | 
					      "(datetime.datetime(2018, 7, 1, 0, 0), 1049.1100000000001)\n",
 | 
				
			||||||
 | 
					      "(datetime.datetime(2018, 10, 1, 0, 0), 1051.663076923077)\n",
 | 
				
			||||||
 | 
					      "(datetime.datetime(2019, 1, 1, 0, 0), 1062.2869230769231)\n",
 | 
				
			||||||
 | 
					      "(datetime.datetime(2019, 4, 1, 0, 0), 1059.7423076923076)\n",
 | 
				
			||||||
 | 
					      "(datetime.datetime(2019, 7, 1, 0, 0), 1050.7661538461539)\n",
 | 
				
			||||||
 | 
					      "(datetime.datetime(2019, 10, 1, 0, 0), 1045.2061538461537)\n",
 | 
				
			||||||
 | 
					      "(datetime.datetime(2020, 1, 1, 0, 0), 1046.11)\n",
 | 
				
			||||||
 | 
					      "(datetime.datetime(2020, 4, 1, 0, 0), 1053.126923076923)\n",
 | 
				
			||||||
 | 
					      "(datetime.datetime(2020, 7, 1, 0, 0), 1053.273846153846)\n",
 | 
				
			||||||
 | 
					      "(datetime.datetime(2020, 10, 1, 0, 0), 1064.2384615384615)\n",
 | 
				
			||||||
 | 
					      "(datetime.datetime(2021, 1, 1, 0, 0), 1073.1538461538462)\n",
 | 
				
			||||||
 | 
					      "(datetime.datetime(2021, 4, 1, 0, 0), 1094.3215384615385)\n",
 | 
				
			||||||
 | 
					      "(datetime.datetime(2021, 7, 1, 0, 0), 1104.3584615384616)\n",
 | 
				
			||||||
 | 
					      "(datetime.datetime(2021, 10, 1, 0, 0), 1112.806923076923)\n"
 | 
				
			||||||
 | 
					     ]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					   ],
 | 
				
			||||||
 | 
					   "source": [
 | 
				
			||||||
 | 
					    "for i in tst:\n",
 | 
				
			||||||
 | 
					    "    print(i)"
 | 
				
			||||||
 | 
					   ]
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 ],
 | 
					 ],
 | 
				
			||||||
 "metadata": {
 | 
					 "metadata": {
 | 
				
			||||||
 | 
					  "interpreter": {
 | 
				
			||||||
 | 
					   "hash": "71e6a8e087576f7c2a714460e6ef0339bac111b70cc81e9aa980fde63219ab06"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  "kernelspec": {
 | 
					  "kernelspec": {
 | 
				
			||||||
   "display_name": "Python 3 (ipykernel)",
 | 
					   "display_name": "Python 3 (ipykernel)",
 | 
				
			||||||
   "language": "python",
 | 
					   "language": "python",
 | 
				
			||||||
 | 
				
			|||||||
@ -340,20 +340,54 @@ class TestExpand:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestShrink:
 | 
					class TestShrink:
 | 
				
			||||||
    # To-do
 | 
					    # TODO
 | 
				
			||||||
    pass
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestMeanReturns:
 | 
					class TestMeanReturns:
 | 
				
			||||||
    # To-do
 | 
					    # TODO
 | 
				
			||||||
    pass
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestReadCsv:
 | 
					class TestReadCsv:
 | 
				
			||||||
    # To-do
 | 
					    # TODO
 | 
				
			||||||
    pass
 | 
					    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TestTransform:
 | 
				
			||||||
 | 
					    def test_daily_to_yearly(self, create_test_data):
 | 
				
			||||||
 | 
					        ts_data = create_test_data(AllFrequencies.D, num=782, skip_weekends=True)
 | 
				
			||||||
 | 
					        ts = TimeSeries(ts_data, "D")
 | 
				
			||||||
 | 
					        tst = ts.transform("Y", "mean")
 | 
				
			||||||
 | 
					        assert isinstance(tst, TimeSeries)
 | 
				
			||||||
 | 
					        assert len(tst) == 3
 | 
				
			||||||
 | 
					        assert "2019-01-02" in tst
 | 
				
			||||||
 | 
					        assert tst.iloc[2] == (datetime.datetime(2019, 1, 2), 1238.5195)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_weekly_to_monthly(self, create_test_data):
 | 
				
			||||||
 | 
					        ts_data = create_test_data(AllFrequencies.W, num=261)
 | 
				
			||||||
 | 
					        ts = TimeSeries(ts_data, "W")
 | 
				
			||||||
 | 
					        tst = ts.transform("M", "mean")
 | 
				
			||||||
 | 
					        assert isinstance(tst, TimeSeries)
 | 
				
			||||||
 | 
					        assert "2017-01-01" in tst
 | 
				
			||||||
 | 
					        assert tst.iloc[0] == (datetime.datetime(2017, 1, 1), 1007.33)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_weekly_to_qty(self, create_test_data):
 | 
				
			||||||
 | 
					        ts_data = create_test_data(AllFrequencies.W, num=261)
 | 
				
			||||||
 | 
					        ts = TimeSeries(ts_data, "W")
 | 
				
			||||||
 | 
					        tst = ts.transform("Q", "mean")
 | 
				
			||||||
 | 
					        assert len(tst) == 20
 | 
				
			||||||
 | 
					        assert "2018-01-01" in tst
 | 
				
			||||||
 | 
					        assert round(tst.iloc[4][1], 2) == 1054.72
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test_weekly_to_yearly(self, create_test_data):
 | 
				
			||||||
 | 
					        ts_data = create_test_data(AllFrequencies.W, num=261)
 | 
				
			||||||
 | 
					        ts = TimeSeries(ts_data, "W")
 | 
				
			||||||
 | 
					        tst = ts.transform("Y", "mean")
 | 
				
			||||||
 | 
					        assert "2019-01-01" in tst
 | 
				
			||||||
 | 
					        assert round(tst.iloc[2][1], 2) == 1054.50
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestReturnsAgain:
 | 
					class TestReturnsAgain:
 | 
				
			||||||
    data = [
 | 
					    data = [
 | 
				
			||||||
        ("2020-01-01", 10),
 | 
					        ("2020-01-01", 10),
 | 
				
			||||||
 | 
				
			|||||||
@ -72,3 +72,13 @@ class TestSharpe:
 | 
				
			|||||||
            return_period_value=1,
 | 
					            return_period_value=1,
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
        assert round(sharpe_ratio, 4) == 0.4898
 | 
					        assert round(sharpe_ratio, 4) == 0.4898
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sharpe_ratio = fc.sharpe_ratio(
 | 
				
			||||||
 | 
					            ts,
 | 
				
			||||||
 | 
					            risk_free_rate=0.052,
 | 
				
			||||||
 | 
					            from_date="2018-01-01",
 | 
				
			||||||
 | 
					            to_date="2021-12-31",
 | 
				
			||||||
 | 
					            return_period_unit="months",
 | 
				
			||||||
 | 
					            return_period_value=12,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        assert round(sharpe_ratio, 4) == 0.3199
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user