Skip to content

Commit

Permalink
added changes accroding to comments in pull_request
Browse files Browse the repository at this point in the history
  • Loading branch information
Alina Voilova committed Jul 3, 2024
1 parent 2049edc commit 383e11d
Show file tree
Hide file tree
Showing 18 changed files with 53 additions and 51 deletions.
4 changes: 2 additions & 2 deletions portfolyo/core/pfline/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
def assert_longest_allowed_freq(freq):
def decorator(fn):
def wrapped(self, *args, **kwargs):
if tools.freq.up_or_down2(self.index.freq, freq) == 1:
if tools.freq.up_or_down(self.index.freq, freq) == 1:
raise ValueError(
"The frequency of the index is too long; longest allowed:"
f" {freq}; passed: {self.index.freq}."
Expand All @@ -21,7 +21,7 @@ def wrapped(self, *args, **kwargs):
def assert_shortest_allowed_freq(freq):
def decorator(fn):
def wrapped(self, *args, **kwargs):
if tools.freq.up_or_down2(self.index.freq, freq) == -1:
if tools.freq.up_or_down(self.index.freq, freq) == -1:
raise ValueError(
"The frequency of the index is too short; shortest allowed:"
f" {freq}; passed: {self.index.freq}."
Expand Down
6 changes: 3 additions & 3 deletions portfolyo/dev/develop.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ def get_index(
if not startdate:
a, m, d = 2016, 1, 1 # earliest possible
a += np.random.randint(0, 8) if _seed else (periods % 8)
if tools.freq.up_or_down2(freq, "MS") <= 0:
if tools.freq.up_or_down(freq, "MS") <= 0:
m += np.random.randint(0, 12) if _seed else (periods % 12)
if tools.freq.up_or_down2(freq, "D") <= 0:
if tools.freq.up_or_down(freq, "D") <= 0:
d += np.random.randint(0, 28) if _seed else (periods % 28)
startdate = f"{a}-{m}-{d}"
if not start_of_day:
Expand All @@ -48,7 +48,7 @@ def get_index(
start = tools.stamp.create(startdate, tz, start_of_day)
i = pd.date_range(start, periods=periods, freq=freq) # tz included in start
# Some checks.
if tools.freq.up_or_down2(freq, "H") <= 0:
if tools.freq.up_or_down(freq, "H") <= 0:
i = _shorten_index_if_necessary(i, start_of_day)
return i

Expand Down
2 changes: 1 addition & 1 deletion portfolyo/tools/ceil.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def stamp(
----------
ts : pd.Timestamp
Timestamp to ceil.
freq : {{{tools_freq.ALLOWED_FREQUENCIES_DOCS}}}
freq : {tools_freq.ALLOWED_FREQUENCIES_DOCS}
Frequency for which to ceil the timestamp.
future : int, optional (default: 0)
0 to ceil to current period. 1 (-1) to round to period after (before) that, etc.
Expand Down
20 changes: 10 additions & 10 deletions portfolyo/tools/changefreq.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ def _downsample_summable(s: pd.Series, freq: str) -> pd.Series:
return _emptyseries(s, freq)

offset = tools_startofday.get(s.index, "timedelta")
source_vs_daily = tools_freq.up_or_down2(s.index.freq, "D")
target_vs_daily = tools_freq.up_or_down2(freq, "D")
source_vs_daily = tools_freq.up_or_down(s.index.freq, "D")
target_vs_daily = tools_freq.up_or_down(freq, "D")

# We cannot simply `.resample()`, e.g. from hourly to monthly, because in that
# case the start-of-day is lost. We need to do it in two steps.
Expand Down Expand Up @@ -89,8 +89,8 @@ def _upsample_avgable(s: pd.Series, freq: str) -> pd.Series:
return _emptyseries(s, freq)

offset = tools_startofday.get(s.index, "timedelta")
source_vs_daily = tools_freq.up_or_down2(s.index.freq, "D")
target_vs_daily = tools_freq.up_or_down2(freq, "D")
source_vs_daily = tools_freq.up_or_down(s.index.freq, "D")
target_vs_daily = tools_freq.up_or_down(freq, "D")

# Several isuses with pandas resampling:

Expand Down Expand Up @@ -127,7 +127,7 @@ def _general(is_summable: bool, s: pd.Series, freq: str = "MS") -> pd.Series:
True if data is summable, False if it is averagable.
s : pd.Series
Series that needs to be resampled.
freq : {{{tools_freq.ALLOWED_FREQUENCIES_DOCS}}}, optional (default: 'MS')
freq : {tools_freq.ALLOWED_FREQUENCIES_DOCS}, optional (default: 'MS')
Target frequency.
Returns
Expand All @@ -144,7 +144,7 @@ def _general(is_summable: bool, s: pd.Series, freq: str = "MS") -> pd.Series:

# s is now a Series with a 'float' or 'pint' dtype.

up_or_down = tools_freq.up_or_down2(s.index.freq, freq)
up_or_down = tools_freq.up_or_down(s.index.freq, freq)

# Nothing more needed; portfolio already in desired frequency.
if up_or_down == 0:
Expand Down Expand Up @@ -172,14 +172,14 @@ def index(i: pd.DatetimeIndex, freq: str = "MS") -> pd.DatetimeIndex:
----------
i : pd.DatetimeIndex
Index to resample.
freq : {{{tools_freq.ALLOWED_FREQUENCIES_DOCS}}}
freq : {tools_freq.ALLOWED_FREQUENCIES_DOCS}
Target frequency.
Returns
-------
pd.DatetimeIndex
"""
up_or_down = tools_freq.up_or_down2(i.freq, freq)
up_or_down = tools_freq.up_or_down(i.freq, freq)

# Nothing more needed; index already in desired frequency.
if up_or_down == 0:
Expand All @@ -203,7 +203,7 @@ def summable(fr: Series_or_DataFrame, freq: str = "MS") -> Series_or_DataFrame:
----------
fr : Series or DataFrame
Pandas Series or DataFrame to be resampled.
freq : {{{tools_freq.ALLOWED_FREQUENCIES_DOCS}}}, optional (default: 'MS')
freq : {tools_freq.ALLOWED_FREQUENCIES_DOCS}, optional (default: 'MS')
Target frequency.
Returns
Expand Down Expand Up @@ -239,7 +239,7 @@ def averagable(fr: Series_or_DataFrame, freq: str = "MS") -> Series_or_DataFrame
----------
fr : Series or DataFrame
Pandas Series or DataFrame to be resampled.
freq : {{{tools_freq.ALLOWED_FREQUENCIES_DOCS}}}, optional (default: 'MS')
freq : {tools_freq.ALLOWED_FREQUENCIES_DOCS}, optional (default: 'MS')
Target frequency.
Returns
Expand Down
2 changes: 1 addition & 1 deletion portfolyo/tools/duration.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def stamp(ts: pd.Timestamp, freq: str) -> tools_unit.Q_:
----------
ts : pd.Timestamp
Timestamp for which to calculate the duration.
freq : {{{tools_freq.ALLOWED_FREQUENCIES_DOCS}}}
freq : {tools_freq.ALLOWED_FREQUENCIES_DOCS}
Frequency to use in determining the duration.
Returns
Expand Down
2 changes: 1 addition & 1 deletion portfolyo/tools/floor.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def stamp(
----------
ts : pd.Timestamp
Timestamp to floor.
freq : {{{tools_freq.ALLOWED_FREQUENCIES_DOCS}}}
freq : {tools_freq.ALLOWED_FREQUENCIES_DOCS}
Frequency for which to floor the timestamp.
future : int, optional (default: 0)
0 to floor to current period. 1 (-1) to round to period after (before) that, etc.
Expand Down
17 changes: 9 additions & 8 deletions portfolyo/tools/freq.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ def assert_freq_sufficiently_long(freq, freq_ref, strict: bool = False) -> None:
)


def up_or_down2(freq_source: str, freq_target: str) -> int:
def up_or_down(freq_source: str, freq_target: str) -> int:
"""
Compare source frequency with target frequency to see if it needs up- or downsampling.
Expand Down Expand Up @@ -123,18 +123,17 @@ def up_or_down2(freq_source: str, freq_target: str) -> int:
ValueError
"""
# check if passed freuenices are valid
# assert_freq_valid(freq_source)
# assert_freq_valid(freq_target)
# Compare if the freq are the same
if freq_source == freq_target:
return 0
restricted_classes = [
pd._libs.tslibs.offsets.QuarterBegin,
pd._libs.tslibs.offsets.YearBegin,
]
# Convert freq from str to offset
freq_source_as_offset = pd.tseries.frequencies.to_offset(freq_source)
freq_target_as_offset = pd.tseries.frequencies.to_offset(freq_target)

# Compare if the freq are the same
if freq_source_as_offset == freq_target_as_offset:
return 0
# One of the freq can be in restricted class, but not both
if not (
type(freq_source_as_offset) in restricted_classes
Expand Down Expand Up @@ -170,7 +169,9 @@ def up_or_down2(freq_source: str, freq_target: str) -> int:
# we are in the case QS and QS
return 0

raise ValueError
raise ValueError(
f"The passed frequency {freq_source} can't be aggregated to {freq_target}."
)


def assert_freq_equally_long(freq, freq_ref) -> None:
Expand Down
2 changes: 1 addition & 1 deletion portfolyo/tools/intersect.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def indices_flex(
if len(distinct_sod) != 1 and ignore_start_of_day is False:
raise ValueError(f"Indices must have equal start-of-day; got {distinct_sod}.")
for i in range(len(idxs)):
if len(distinct_sod) != 1 and tools_freq.up_or_down2(idxs[i].freq, "D") == -1:
if len(distinct_sod) != 1 and tools_freq.up_or_down(idxs[i].freq, "D") == -1:
raise ValueError(
"Downsample all indices to daily-or-longer, or trim them so they have the same start-of-day, before attempting to calculate the intersection"
)
Expand Down
12 changes: 6 additions & 6 deletions portfolyo/tools/isboundary.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def stamp(ts: pd.Timestamp, freq: str, start_of_day: dt.time = None) -> bool:
----------
ts : pd.Timestamp
Timestamp for which to do the assertion.
freq : {{{tools_freq.ALLOWED_FREQUENCIES_DOCS}}}
freq : {tools_freq.ALLOWED_FREQUENCIES_DOCS}
Frequency for which to check if the timestamp is a valid start (or end) timestamp.
start_of_day : dt.time, optional (default: midnight)
Time of day at which daily-or-longer delivery periods start. E.g. if
Expand Down Expand Up @@ -122,7 +122,7 @@ def index(i: pd.DatetimeIndex, freq: str) -> pd.Series:
----------
ts : pd.Timestamp
Timestamp for which to do the assertion.
freq : {{{tools_freq.ALLOWED_FREQUENCIES_DOCS}}}
freq : {tools_freq.ALLOWED_FREQUENCIES_DOCS}
Frequency for which to check if the timestamp is a valid start (or end) timestamp.
Returns
Expand All @@ -139,17 +139,17 @@ def index(i: pd.DatetimeIndex, freq: str) -> pd.Series:
until 06:00:00 (excl).)
"""
# When comparing index to shorter (or same) frequency, all timestamps are on boundary.
if tools_freq.up_or_down2(i.freq, freq) >= 0:
if tools_freq.up_or_down(i.freq, freq) >= 0:
values = True

# When comparing daily-or-longer index to other daily-or-longer frequency X,
# we only need check only if the stamps are on first day of X.
elif tools_freq.up_or_down2(i.freq, "D") >= 0:
elif tools_freq.up_or_down(i.freq, "D") >= 0:
values = is_X_start(i, freq)

# Comparing shorter-than-daily index to other shorter-than-daily frequency X,
# (i.e., '15T' with 'H')
elif tools_freq.up_or_down2(freq, "H") <= 0:
elif tools_freq.up_or_down(freq, "H") <= 0:
if i.freq == "15T" and freq == "H":
values = i.minute == 0
else:
Expand All @@ -163,7 +163,7 @@ def index(i: pd.DatetimeIndex, freq: str) -> pd.Series:
# . Check time of day.
values = i.time == tools_startofday.get(i)
# . Check day of X.
if tools_freq.up_or_down2(freq, "D") > 0:
if tools_freq.up_or_down(freq, "D") > 0:
values &= is_X_start(i, freq)

return pd.Series(values, i, name="isboundary")
6 changes: 3 additions & 3 deletions portfolyo/tools/peakconvert.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ def tseries2poframe(
2020-12-01 00:00:00+01:00 57.872246 35.055449
12 rows × 3 columns
"""
if tools_freq.up_or_down2(freq, "MS") < 0:
if tools_freq.up_or_down(freq, "MS") < 0:
raise ValueError(f"Parameter ``freq`` be monthly-or-longer; got '{freq}'.")

# Remove partial data.
Expand Down Expand Up @@ -412,10 +412,10 @@ def poframe2poframe(
2020-07-01 00:00:00+02:00 44.033511 26.371498
2020-10-01 00:00:00+02:00 54.468722 31.063728
"""
if tools_freq.up_or_down2(freq, "MS") < 0:
if tools_freq.up_or_down(freq, "MS") < 0:
raise ValueError(f"Parameter ``freq`` be monthly-or-longer; got '{freq}'.")

if tools_freq.up_or_down2(df.index.freq, freq) == 1:
if tools_freq.up_or_down(df.index.freq, freq) == 1:
warnings.warn(
"This conversion includes upsampling, e.g. from yearly to monthly values."
" The result will be uniform at the frequency of the original frame ``df``."
Expand Down
4 changes: 2 additions & 2 deletions portfolyo/tools/peakfn.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ def filter_time(i: pd.DatetimeIndex) -> np.ndarray:

def peak_fn(i: pd.DatetimeIndex) -> pd.Series:
# Check if function works for this frequency.
if tools_freq.up_or_down2(i.freq, longest_freq) > 0:
if tools_freq.up_or_down(i.freq, longest_freq) > 0:
raise ValueError(
f"Peak periods can only be calculated for indices with frequency of {longest_freq} or shorter."
)
Expand Down Expand Up @@ -145,7 +145,7 @@ def peak_duration(i: pd.DatetimeIndex, peak_fn: PeakFunction) -> pd.Series:
"""
eval_i = i # index to evaluate if peak or offpeak
for eval_freq in ("D", "H", "15T"):
if tools_freq.up_or_down2(eval_i.freq, eval_freq) > 0: # upsampling necessary
if tools_freq.up_or_down(eval_i.freq, eval_freq) > 0: # upsampling necessary
eval_i = tools_changefreq.index(eval_i, eval_freq)
try:
eval_bool = peak_fn(eval_i) # boolean series
Expand Down
2 changes: 1 addition & 1 deletion portfolyo/tools/right.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def stamp(ts: pd.Timestamp, freq: str = None) -> pd.Timestamp:
----------
ts : pd.Timestamp
Timestamp for which to calculate the right-bound timestamp.
freq : {{{tools_freq.ALLOWED_FREQUENCIES_DOCS}}}
freq : {tools_freq.ALLOWED_FREQUENCIES_DOCS}
Frequency to use in determining the right-bound timestamp.
Returns
Expand Down
6 changes: 3 additions & 3 deletions portfolyo/tools/round.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def stamp_general(
fn : {'floor', 'ceil'}
ts : pd.Timestamp
Timestamp for which to do the rounding.
freq : {{{tools_freq.ALLOWED_FREQUENCIES_DOCS}}}
freq : {tools_freq.ALLOWED_FREQUENCIES_DOCS}
Frequency for which to round the timestamp.
future : int, optional (default: 0)
0 to round to current period. 1 (-1) to round to period after (before) that, etc.
Expand All @@ -48,7 +48,7 @@ def stamp_current(
fn : {'floor', 'ceil'}
ts : pd.Timestamp
Timestamp for which to do the rounding.
freq : {{{tools_freq.ALLOWED_FREQUENCIES_DOCS}}}
freq : {tools_freq.ALLOWED_FREQUENCIES_DOCS}
Frequency for which to round the timestamp.
start_of_day : dt.time, optional (default: midnight)
Time of day at which daily-or-longer delivery periods start. E.g. if
Expand All @@ -67,7 +67,7 @@ def stamp_current(
# If we land here, the timestamp is not on a boundary.

# Fixed-duration frequency (= (quarter)hour): simply floor/ceil.
if tools_freq.up_or_down2(freq, "D") < 0:
if tools_freq.up_or_down(freq, "D") < 0:
if fn == "floor":
return ts.floor(freq, nonexistent="shift_backward")
else:
Expand Down
6 changes: 3 additions & 3 deletions portfolyo/tools/standardize.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ def assert_index_standardized(i: pd.DatetimeIndex, __right: bool = False):
raise AssertionError("Index must have values; got empty index.")

# Check hour and minute.
if tools_freq.up_or_down2(freq, "15T") <= 0: # quarterhour
if tools_freq.up_or_down(freq, "15T") <= 0: # quarterhour
startminute = 15 if __right else 0
if i[0].minute != startminute:
err = ("right-bound", "15 min past the") if __right else ("", "at a full")
Expand All @@ -203,7 +203,7 @@ def assert_index_standardized(i: pd.DatetimeIndex, __right: bool = False):
)

# Check time-of-day.
if tools_freq.up_or_down2(freq, "H") <= 0: # hour or shorter
if tools_freq.up_or_down(freq, "H") <= 0: # hour or shorter
if not __right:
start = i[0]
end = tools_right.stamp(i[-1], i.freq)
Expand All @@ -224,7 +224,7 @@ def assert_index_standardized(i: pd.DatetimeIndex, __right: bool = False):
)

# Check day-of-X.
if tools_freq.up_or_down2(freq, "D") > 0:
if tools_freq.up_or_down(freq, "D") > 0:
if freq == "MS":
period, not_ok = "month", ~i.is_month_start
elif freq == "QS":
Expand Down
2 changes: 1 addition & 1 deletion portfolyo/tools/startofday.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def set(i: pd.DatetimeIndex, start_of_day: dt.time) -> pd.DatetimeIndex:
if start_of_day.second != 0 or start_of_day.minute % 15 != 0:
raise ValueError("Start of day must coincide with a full quarterhour.")

if tools_freq.up_or_down2(i.freq, "D") >= 0:
if tools_freq.up_or_down(i.freq, "D") >= 0:
return _set_to_longfreq(i, start_of_day)
else:
return _set_to_shortfreq(i, start_of_day)
Expand Down
4 changes: 2 additions & 2 deletions portfolyo/tools/trim.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def index(i: pd.DatetimeIndex, freq: str) -> pd.DatetimeIndex:
----------
i : pd.DatetimeIndex
The (untrimmed) DatetimeIndex
freq : {{{tools_freq.ALLOWED_FREQUENCIES_DOCS}}}
freq : {tools_freq.ALLOWED_FREQUENCIES_DOCS}
Frequency to trim to. E.g. 'MS' to only keep full months.
Returns
Expand Down Expand Up @@ -64,7 +64,7 @@ def frame(fr: pd.Series | pd.DataFrame, freq: str) -> pd.Series | pd.DataFrame:
----------
fr : Series or DataFrame
The (untrimmed) pandas series or dataframe.
freq : {{{tools_freq.ALLOWED_FREQUENCIES_DOCS}}}
freq : {tools_freq.ALLOWED_FREQUENCIES_DOCS}
Frequency to trim to. E.g. 'MS' to only keep full months.
Returns
Expand Down
2 changes: 1 addition & 1 deletion portfolyo/tools/visualize/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ def get_portfolyo_attr(ax, name, default_val=None):

def is_categorical(s: pd.Series) -> bool:
"""The function checks whether frequency of panda Series falls into continous or categorical group"""
return tools_freq.up_or_down2(s.index.freq, "D") == 1
return tools_freq.up_or_down(s.index.freq, "D") == 1


def prepare_ax_and_s(ax: plt.Axes, s: pd.Series, unit=None) -> pd.Series:
Expand Down
5 changes: 3 additions & 2 deletions tests/tools/test_freq.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ def test_freq_sufficiently_short(
("MS", "MS", 0),
("QS", "QS", 0),
("QS", "QS-APR", 0),
("QS", "QS-JAN", 0),
# ValueError
("QS", "QS-FEB", ValueError),
("QS", "AS-FEB", ValueError),
Expand All @@ -327,7 +328,7 @@ def test_freq_sufficiently_short(
def test_up_pr_down2(source_freq: str, ref_freq: str, expected: int | Exception):
if isinstance(expected, type) and issubclass(expected, Exception):
with pytest.raises(expected):
tools.freq.up_or_down2(source_freq, ref_freq)
tools.freq.up_or_down(source_freq, ref_freq)
else:
result = tools.freq.up_or_down2(source_freq, ref_freq)
result = tools.freq.up_or_down(source_freq, ref_freq)
assert result == expected

0 comments on commit 383e11d

Please sign in to comment.