Skip to content

Commit

Permalink
better features
Browse files Browse the repository at this point in the history
  • Loading branch information
jbaron committed Aug 9, 2024
1 parent 4195820 commit 20383d2
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 41 deletions.
2 changes: 1 addition & 1 deletion roboquant/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "0.8.0"
__version__ = "0.8.1"

import logging

Expand Down
42 changes: 4 additions & 38 deletions roboquant/ml/features.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def cache(self, validate=False) -> "Feature[T]":

def returns(self, period=1) -> "Feature[T]":
if period == 1:
return ReturnsFeature(self) # type: ignore
return ReturnFeature(self) # type: ignore
return LongReturnsFeature(self, period) # type: ignore

def normalize(self, min_period=3) -> "Feature[T]":
Expand Down Expand Up @@ -359,7 +359,7 @@ def size(self) -> int:
return len(self.assets)


class ReturnsFeature(Feature):
class ReturnFeature(Feature):

def __init__(self, feature: Feature) -> None:
super().__init__()
Expand Down Expand Up @@ -421,13 +421,12 @@ def __init__(self, feature: Feature, period: int) -> None:
def calc(self, value):
values = self.feature.calc(value)
h = self.history
h.append(values)

if len(h) < h.maxlen: # type: ignore
h.append(values)
return self._full_nan()

r = max(h) / h[0] - 1.0
h.append(values)
return r

def size(self) -> int:
Expand All @@ -438,38 +437,6 @@ def reset(self):
self.feature.reset()


class MaxReturnFeature2(Feature):
"""Calculate the maximum return over a certain period."""

def __init__(self, feature: Feature, period: int) -> None:
super().__init__()
self.feature: Feature = feature
self.history = np.full((period, self.size()), float("nan"), dtype=np.float32)
self.idx = -1

def calc(self, value):
self.idx += 1
values = self.feature.calc(value)
h = self.history
h[self.idx] = values

hist_len = len(h)
if self.idx < hist_len:
return self._full_nan()

root_idx = self.idx % hist_len + 1
root_idx = root_idx if root_idx < hist_len else 0
r = np.max(h) / h[root_idx] - 1.0
return r

def size(self) -> int:
return self.feature.size()

def reset(self):
self.idx = -1
self.feature.reset()


class MinReturnFeature(Feature):
"""Calculate the minimum return over a certain period.
This will only work on features that return a single value.
Expand All @@ -483,13 +450,12 @@ def __init__(self, feature: Feature, period: int) -> None:
def calc(self, value):
values = self.feature.calc(value)
h = self.history
h.append(values)

if len(h) < h.maxlen: # type: ignore
h.append(values)
return self._full_nan()

r = min(h) / h[0] - 1.0
h.append(values)
return r

def size(self) -> int:
Expand Down
7 changes: 5 additions & 2 deletions tests/unit/test_features.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@
NormalizeFeature,
PriceFeature,
SMAFeature,
ReturnsFeature,
ReturnFeature,
VolumeFeature,
FixedValueFeature,
DayOfWeekFeature,
MaxReturnFeature
)
from tests.common import get_feed

Expand All @@ -31,11 +32,13 @@ def test_all_features(self):
PriceFeature(symbol1, price_type="OPEN"),
SMAFeature(FixedValueFeature(np.ones((3,))), 8),
SMAFeature(PriceFeature(symbol2, price_type="CLOSE"), 10),
ReturnsFeature(PriceFeature(symbol1, price_type="OPEN")),
ReturnFeature(PriceFeature(symbol1, price_type="OPEN")),
MaxReturnFeature(PriceFeature(symbol1, price_type="CLOSE"), 4),
VolumeFeature(symbol2),
DayOfWeekFeature(),
)
channel = feed.play_background()
result = None
while evt := channel.get():
result = feature.calc(evt)
self.assertTrue(len(result) == feature.size())
Expand Down

0 comments on commit 20383d2

Please sign in to comment.