PyFacts/tests/test_core.py

436 lines
15 KiB
Python

import datetime
import random
from typing import Mapping
import pyfacts as pft
import pytest
from pyfacts.utils import PyfactsOptions
class TestFrequency:
def test_creation(self):
D = pft.Frequency("daily", "days", 1, 1, "D")
assert D.days == 1
assert D.symbol == "D"
assert D.name == "daily"
assert D.value == 1
assert D.freq_type == "days"
class TestAllFrequencies:
def test_attributes(self):
assert hasattr(pft.AllFrequencies, "D")
assert hasattr(pft.AllFrequencies, "M")
assert hasattr(pft.AllFrequencies, "Q")
def test_days(self):
assert pft.AllFrequencies.D.days == 1
assert pft.AllFrequencies.M.days == 30
assert pft.AllFrequencies.Q.days == 91
def test_symbol(self):
assert pft.AllFrequencies.H.symbol == "H"
assert pft.AllFrequencies.W.symbol == "W"
def test_values(self):
assert pft.AllFrequencies.H.value == 6
assert pft.AllFrequencies.Y.value == 1
def test_type(self):
assert pft.AllFrequencies.Q.freq_type == "months"
assert pft.AllFrequencies.W.freq_type == "days"
class TestSeries:
def test_creation(self):
series = pft.Series([1, 2, 3, 4, 5, 6, 7], dtype="number")
assert series.dtype == float
assert series[2] == 3
dates = pft.create_date_series("2021-01-01", "2021-01-31", frequency="D")
series = pft.Series(dates, dtype="date")
assert series.dtype == datetime.datetime
class TestTimeSeriesCore:
data = [("2021-01-01", 220), ("2021-02-01", 230), ("2021-03-01", 240)]
def test_repr_str(self, create_test_data):
ts = pft.TimeSeriesCore(self.data, frequency="M")
assert str(ts) in repr(ts).replace("\t", " ")
data = create_test_data(frequency=pft.AllFrequencies.D, eomonth=False, num=50, dates_as_string=True)
ts = pft.TimeSeriesCore(data, frequency="D")
assert "..." in str(ts)
assert "..." in repr(ts)
def test_creation(self):
ts = pft.TimeSeriesCore(self.data, frequency="M")
assert isinstance(ts, pft.TimeSeriesCore)
assert isinstance(ts, Mapping)
def test_creation_no_freq(self, create_test_data):
data = create_test_data(num=300, frequency=pft.AllFrequencies.D)
ts = pft.TimeSeriesCore(data)
assert ts.frequency == pft.AllFrequencies.D
data = create_test_data(num=300, frequency=pft.AllFrequencies.M)
ts = pft.TimeSeriesCore(data)
assert ts.frequency == pft.AllFrequencies.M
def test_creation_no_freq_missing_data(self, create_test_data):
data = create_test_data(num=300, frequency=pft.AllFrequencies.D)
data = random.sample(data, 182)
ts = pft.TimeSeriesCore(data)
assert ts.frequency == pft.AllFrequencies.D
data = create_test_data(num=300, frequency=pft.AllFrequencies.D)
data = random.sample(data, 175)
with pytest.raises(ValueError):
ts = pft.TimeSeriesCore(data)
data = create_test_data(num=100, frequency=pft.AllFrequencies.W)
data = random.sample(data, 70)
ts = pft.TimeSeriesCore(data)
assert ts.frequency == pft.AllFrequencies.W
data = create_test_data(num=100, frequency=pft.AllFrequencies.W)
data = random.sample(data, 68)
with pytest.raises(ValueError):
pft.TimeSeriesCore(data)
def test_creation_wrong_freq(self, create_test_data):
data = create_test_data(num=100, frequency=pft.AllFrequencies.W)
with pytest.raises(ValueError):
pft.TimeSeriesCore(data, frequency="D")
data = create_test_data(num=100, frequency=pft.AllFrequencies.D)
with pytest.raises(ValueError):
pft.TimeSeriesCore(data, frequency="W")
class TestSlicing:
data = [("2021-01-01", 220), ("2021-02-01", 230), ("2021-03-01", 240)]
def test_getitem(self):
ts = pft.TimeSeriesCore(self.data, frequency="M")
assert ts.dates[0] == datetime.datetime(2021, 1, 1, 0, 0)
assert ts.values[0] == 220
assert ts["2021-01-01"][1] == 220
assert len(ts[ts.dates > "2021-01-01"]) == 2
assert ts[ts.dates == "2021-02-01"].iloc[0][1] == 230
assert ts.iloc[2][0] == datetime.datetime(2021, 3, 1)
assert len(ts.iloc[:2]) == 2
with pytest.raises(KeyError):
ts["2021-02-03"]
subset_ts = ts[["2021-01-01", "2021-03-01"]]
assert len(subset_ts) == 2
assert isinstance(subset_ts, pft.TimeSeriesCore)
assert subset_ts.iloc[1][1] == 240
def test_get(self):
ts = pft.TimeSeriesCore(self.data, frequency="M")
assert ts.dates[0] == datetime.datetime(2021, 1, 1, 0, 0)
assert ts.values[0] == 220
assert ts.get("2021-01-01")[1] == 220
assert ts.get("2021-02-15") is None
assert ts.get("2021-02-23", -1) == -1
assert ts.get("2021-02-10", closest="previous")[1] == 230
assert ts.get("2021-02-10", closest="next")[1] == 240
PyfactsOptions.get_closest = "previous"
assert ts.get("2021-02-10")[1] == 230
PyfactsOptions.get_closest = "next"
assert ts.get("2021-02-10")[1] == 240
def test_contains(self):
ts = pft.TimeSeriesCore(self.data, frequency="M")
assert datetime.datetime(2021, 1, 1) in ts
assert "2021-01-01" in ts
assert "2021-01-14" not in ts
def test_items(self):
ts = pft.TimeSeriesCore(self.data, frequency="M")
for i, j in ts.items():
assert j == self.data[0][1]
break
def test_special_keys(self):
ts = pft.TimeSeriesCore(self.data, frequency="M")
dates = ts["dates"]
values = ts["values"]
assert isinstance(dates, pft.Series)
assert isinstance(values, pft.Series)
assert len(dates) == 3
assert len(values) == 3
assert dates[0] == datetime.datetime(2021, 1, 1, 0, 0)
assert values[0] == 220
def test_iloc_slicing(self):
ts = pft.TimeSeriesCore(self.data, frequency="M")
assert ts.iloc[0] == (datetime.datetime(2021, 1, 1), 220)
assert ts.iloc[-1] == (datetime.datetime(2021, 3, 1), 240)
ts_slice = ts.iloc[0:2]
assert isinstance(ts_slice, pft.TimeSeriesCore)
assert len(ts_slice) == 2
class TestComparativeSlicing:
def test_date_gt_daily(self, create_test_data):
data = create_test_data(num=300, frequency=pft.AllFrequencies.D)
ts = pft.TimeSeries(data, "D")
ts_rr = ts.calculate_rolling_returns(return_period_unit="months")
assert len(ts_rr) == 269
subset = ts_rr[ts_rr.values < 0.1]
assert isinstance(subset, pft.TimeSeriesCore)
assert subset.frequency == pft.AllFrequencies.D
def test_date_gt_monthly(self, create_test_data):
data = create_test_data(num=60, frequency=pft.AllFrequencies.M)
ts = pft.TimeSeries(data, "M")
ts_rr = ts.calculate_rolling_returns(return_period_unit="months")
assert len(ts_rr) == 59
subset = ts_rr[ts_rr.values < 0.1]
assert isinstance(subset, pft.TimeSeriesCore)
assert subset.frequency == pft.AllFrequencies.M
class TestSetitem:
data = [("2021-01-01", 220), ("2021-01-04", 230), ("2021-03-07", 240)]
def test_setitem(self):
ts = pft.TimeSeriesCore(self.data, frequency="M")
assert len(ts) == 3
ts["2021-01-02"] = 225
assert len(ts) == 4
assert ts["2021-01-02"][1] == 225
ts["2021-01-02"] = 227.6
assert len(ts) == 4
assert ts["2021-01-02"][1] == 227.6
def test_errors(self):
ts = pft.TimeSeriesCore(self.data, frequency="M")
with pytest.raises(TypeError):
ts["2021-01-03"] = "abc"
with pytest.raises(NotImplementedError):
ts.iloc[4] = 4
with pytest.raises(ValueError):
ts["abc"] = 12
class TestTimeSeriesCoreHeadTail:
data = [
("2021-01-01", 220),
("2021-02-01", 230),
("2021-03-01", 240),
("2021-04-01", 250),
("2021-05-01", 260),
("2021-06-01", 270),
("2021-07-01", 280),
("2021-08-01", 290),
("2021-09-01", 300),
("2021-10-01", 310),
("2021-11-01", 320),
("2021-12-01", 330),
]
def test_head(self):
ts = pft.TimeSeriesCore(self.data, frequency="M")
assert len(ts.head()) == 6
assert len(ts.head(3)) == 3
assert isinstance(ts.head(), pft.TimeSeriesCore)
head_ts = ts.head(6)
assert head_ts.iloc[-1][1] == 270
def test_tail(self):
ts = pft.TimeSeriesCore(self.data, frequency="M")
assert len(ts.tail()) == 6
assert len(ts.tail(8)) == 8
assert isinstance(ts.tail(), pft.TimeSeriesCore)
tail_ts = ts.tail(6)
assert tail_ts.iloc[0][1] == 280
def test_head_tail(self):
ts = pft.TimeSeriesCore(self.data, frequency="M")
head_tail_ts = ts.head(8).tail(2)
assert isinstance(head_tail_ts, pft.TimeSeriesCore)
assert "2021-07-01" in head_tail_ts
assert head_tail_ts.iloc[1][1] == 290
class TestDelitem:
data = [
("2021-01-01", 220),
("2021-02-01", 230),
("2021-03-01", 240),
("2021-04-01", 250),
]
def test_deletion(self):
ts = pft.TimeSeriesCore(self.data, "M")
assert len(ts) == 4
del ts["2021-03-01"]
assert len(ts) == 3
assert "2021-03-01" not in ts
with pytest.raises(KeyError):
del ts["2021-03-01"]
class TestTimeSeriesComparisons:
data1 = [
("2021-01-01", 220),
("2021-02-01", 230),
("2021-03-01", 240),
("2021-04-01", 250),
]
data2 = [
("2021-01-01", 240),
("2021-02-01", 210),
("2021-03-01", 240),
("2021-04-01", 270),
]
def test_number_comparison(self):
ts1 = pft.TimeSeriesCore(self.data1, "M")
assert isinstance(ts1 > 23, pft.TimeSeriesCore)
assert (ts1 > 230).values == pft.Series([0.0, 0.0, 1.0, 1.0], "float")
assert (ts1 >= 230).values == pft.Series([0.0, 1.0, 1.0, 1.0], "float")
assert (ts1 < 240).values == pft.Series([1.0, 1.0, 0.0, 0.0], "float")
assert (ts1 <= 240).values == pft.Series([1.0, 1.0, 1.0, 0.0], "float")
assert (ts1 == 240).values == pft.Series([0.0, 0.0, 1.0, 0.0], "float")
assert (ts1 != 240).values == pft.Series([1.0, 1.0, 0.0, 1.0], "float")
def test_series_comparison(self):
ts1 = pft.TimeSeriesCore(self.data1, "M")
ser = pft.Series([240, 210, 240, 270], dtype="int")
assert (ts1 > ser).values == pft.Series([0.0, 1.0, 0.0, 0.0], "float")
assert (ts1 >= ser).values == pft.Series([0.0, 1.0, 1.0, 0.0], "float")
assert (ts1 < ser).values == pft.Series([1.0, 0.0, 0.0, 1.0], "float")
assert (ts1 <= ser).values == pft.Series([1.0, 0.0, 1.0, 1.0], "float")
assert (ts1 == ser).values == pft.Series([0.0, 0.0, 1.0, 0.0], "float")
assert (ts1 != ser).values == pft.Series([1.0, 1.0, 0.0, 1.0], "float")
def test_tsc_comparison(self):
ts1 = pft.TimeSeriesCore(self.data1, "M")
ts2 = pft.TimeSeriesCore(self.data2, "M")
assert (ts1 > ts2).values == pft.Series([0.0, 1.0, 0.0, 0.0], "float")
assert (ts1 >= ts2).values == pft.Series([0.0, 1.0, 1.0, 0.0], "float")
assert (ts1 < ts2).values == pft.Series([1.0, 0.0, 0.0, 1.0], "float")
assert (ts1 <= ts2).values == pft.Series([1.0, 0.0, 1.0, 1.0], "float")
assert (ts1 == ts2).values == pft.Series([0.0, 0.0, 1.0, 0.0], "float")
assert (ts1 != ts2).values == pft.Series([1.0, 1.0, 0.0, 1.0], "float")
def test_errors(self):
ts1 = pft.TimeSeriesCore(self.data1, "M")
ts2 = pft.TimeSeriesCore(self.data2, "M")
ser = pft.Series([240, 210, 240], dtype="int")
ser2 = pft.Series(["2021-01-01", "2021-02-01", "2021-03-01", "2021-04-01"], dtype="date")
del ts2["2021-04-01"]
with pytest.raises(TypeError):
ts1 == "a"
with pytest.raises(ValueError):
ts1 > ts2
with pytest.raises(TypeError):
ts1 == ser2
with pytest.raises(ValueError):
ts1 <= ser
with pytest.raises(TypeError):
ts2 < [23, 24, 25, 26]
class TestTimeSeriesArithmatic:
data = [
("2021-01-01", 220),
("2021-02-01", 230),
("2021-03-01", 240),
("2021-04-01", 250),
]
def test_add(self):
ts = pft.TimeSeriesCore(self.data, "M")
ser = ts.values
num_add_ts = ts + 40
assert num_add_ts["2021-01-01"][1] == 260
assert num_add_ts["2021-04-01"][1] == 290
num_radd_ts = 40 + ts
assert num_radd_ts["2021-01-01"][1] == 260
assert num_radd_ts["2021-04-01"][1] == 290
ser_add_ts = ts + ser
assert ser_add_ts["2021-01-01"][1] == 440
assert ser_add_ts["2021-04-01"][1] == 500
ts_add_ts = ts + num_add_ts
assert ts_add_ts["2021-01-01"][1] == 480
assert ts_add_ts["2021-04-01"][1] == 540
def test_sub(self):
ts = pft.TimeSeriesCore(self.data, "M")
ser = pft.Series([20, 30, 40, 50], "number")
num_sub_ts = ts - 40
assert num_sub_ts["2021-01-01"][1] == 180
assert num_sub_ts["2021-04-01"][1] == 210
num_rsub_ts = 240 - ts
assert num_rsub_ts["2021-01-01"][1] == 20
assert num_rsub_ts["2021-04-01"][1] == -10
ser_sub_ts = ts - ser
assert ser_sub_ts["2021-01-01"][1] == 200
assert ser_sub_ts["2021-04-01"][1] == 200
ts_sub_ts = ts - num_sub_ts
assert ts_sub_ts["2021-01-01"][1] == 40
assert ts_sub_ts["2021-04-01"][1] == 40
def test_truediv(self):
ts = pft.TimeSeriesCore(self.data, "M")
ser = pft.Series([22, 23, 24, 25], "number")
num_div_ts = ts / 10
assert num_div_ts["2021-01-01"][1] == 22
assert num_div_ts["2021-04-01"][1] == 25
num_rdiv_ts = 1000 / ts
assert num_rdiv_ts["2021-04-01"][1] == 4
ser_div_ts = ts / ser
assert ser_div_ts["2021-01-01"][1] == 10
assert ser_div_ts["2021-04-01"][1] == 10
ts_div_ts = ts / num_div_ts
assert ts_div_ts["2021-01-01"][1] == 10
assert ts_div_ts["2021-04-01"][1] == 10
def test_floordiv(self):
ts = pft.TimeSeriesCore(self.data, "M")
ser = pft.Series([22, 23, 24, 25], "number")
num_div_ts = ts // 11
assert num_div_ts["2021-02-01"][1] == 20
assert num_div_ts["2021-04-01"][1] == 22
num_rdiv_ts = 1000 // ts
assert num_rdiv_ts["2021-01-01"][1] == 4
ser_div_ts = ts // ser
assert ser_div_ts["2021-01-01"][1] == 10
assert ser_div_ts["2021-04-01"][1] == 10