mirror of
https://github.com/webclinic017/drift.git
synced 2026-08-21 14:58:11 +00:00
feat(Config): feature extractors are enabled one-by-one with a bool, added previous model to model.fit() (#77)
* feat(Config): feature extractors are enabled one-by-one with a bool, added previous model to model.fit() * fix(Sweep): removed unused `other_features` parameter that fails sweep * feat(Config): using preset names for defining feature extractors again * fix(Tests): fixed model stub classes
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
|
from collections import defaultdict
|
||||||
from utils.load_data import get_crypto_assets
|
from utils.load_data import get_crypto_assets
|
||||||
import feature_extractors.feature_extractor_presets as feature_extractor_presets
|
from feature_extractors.feature_extractor_presets import presets
|
||||||
from models.model_map import model_names_classification, model_names_regression
|
from models.model_map import model_names_classification, model_names_regression
|
||||||
|
|
||||||
def get_default_config() -> tuple[dict, dict, dict]:
|
def get_default_config() -> tuple[dict, dict, dict]:
|
||||||
@@ -18,8 +19,8 @@ def get_default_config() -> tuple[dict, dict, dict]:
|
|||||||
load_other_assets= False,
|
load_other_assets= False,
|
||||||
log_returns= True,
|
log_returns= True,
|
||||||
forecasting_horizon = 1,
|
forecasting_horizon = 1,
|
||||||
own_features= feature_extractor_presets.date + feature_extractor_presets.level1,
|
own_features = ['level_1', 'date_days'],
|
||||||
other_features= [],
|
other_features = [],
|
||||||
index_column= 'int',
|
index_column= 'int',
|
||||||
method= 'classification',
|
method= 'classification',
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,24 +1,49 @@
|
|||||||
from feature_extractors.feature_extractors import feature_lag, feature_mom, feature_ROC, feature_RSI, feature_STOD, feature_STOK, feature_vol, feature_day_of_month, feature_day_of_week, feature_month, feature_debug_future_lookahead
|
from feature_extractors.feature_extractors import feature_lag, feature_mom, feature_ROC, feature_RSI, feature_STOD, feature_STOK, feature_vol, feature_day_of_month, feature_day_of_week, feature_month, feature_debug_future_lookahead
|
||||||
|
from utils.typing import FeatureExtractorConfig
|
||||||
|
from utils.helpers import flatten
|
||||||
|
|
||||||
debug_future_lookahead = [('debug_future', feature_debug_future_lookahead, [1])]
|
__presets = dict(
|
||||||
|
debug_future_lookahead = [('debug_future', feature_debug_future_lookahead, [1])],
|
||||||
|
single_mom = [('mom', feature_mom, [30])],
|
||||||
|
single_vol = [('vol', feature_vol, [30])],
|
||||||
|
mom = [('mom', feature_mom, [10, 20, 30, 60, 90])],
|
||||||
|
vol = [('vol', feature_vol, [10, 20, 30, 60])],
|
||||||
|
lags_up_to_5 = [('lag', feature_lag, [1,2,3,4,5])],
|
||||||
|
lags_up_to_10 = [('lag', feature_lag, [1,2,3,4,5,6,7,8,9,10])],
|
||||||
|
date_all = [
|
||||||
|
('day_of_week', feature_day_of_week, [0]),
|
||||||
|
('day_of_month', feature_day_of_month, [0]),
|
||||||
|
('month', feature_month, [0])],
|
||||||
|
date_days = [
|
||||||
|
('day_of_week', feature_day_of_week, [0]),
|
||||||
|
('day_of_month', feature_day_of_month, [0]),
|
||||||
|
],
|
||||||
|
roc = [('roc', feature_ROC, [10, 30])],
|
||||||
|
rsi = [('rsi', feature_ROC, [10, 30, 100])],
|
||||||
|
stod = [('stod', feature_STOD, [10, 30, 200])],
|
||||||
|
stok = [('stok', feature_STOK, [10, 30, 200])],
|
||||||
|
)
|
||||||
|
|
||||||
lags = [('lag', feature_lag, [1,2,3,4,5,6,7,8,9])]
|
presets = __presets | dict(
|
||||||
|
level_1 = __presets["mom"] + __presets["vol"],
|
||||||
|
level_2 = __presets["mom"] + __presets["vol"] + __presets["roc"] + __presets["rsi"] + __presets["stod"] + __presets["stok"],
|
||||||
|
)
|
||||||
|
|
||||||
only_mom = [('mom', feature_mom, [30])]
|
def preprocess_feature_extractors_config(data_dict: dict) -> dict:
|
||||||
|
keys = ['own_features', 'other_features']
|
||||||
|
for key in keys:
|
||||||
|
preset_names = data_dict[key]
|
||||||
|
data_dict[key] = flatten([presets[preset_name] for preset_name in preset_names])
|
||||||
|
return data_dict
|
||||||
|
|
||||||
date = [
|
|
||||||
('day_of_week', feature_day_of_week, [0]),
|
|
||||||
('day_of_month', feature_day_of_month, [0]),
|
|
||||||
('month', feature_month, [0])]
|
|
||||||
|
|
||||||
level1 = [
|
# Use this if ever we want to create an independent boolean for each featureextractor
|
||||||
('mom', feature_mom, [10, 20, 30, 60, 90]),
|
# def preprocess_feature_extractors_config(data_dict: dict) -> dict:
|
||||||
('vol', feature_vol, [10, 20, 30, 60]),
|
# prefixes = ['own_features', 'other_features']
|
||||||
]
|
# features_dict = dict()
|
||||||
|
# for prefix in prefixes:
|
||||||
|
# features_to_include = [key.replace(prefix + "_", "") for key, value in data_dict.items() if key.startswith(prefix) and value == True]
|
||||||
|
# features_dict[prefix] = flatten([presets[feature_name] for feature_name in features_to_include])
|
||||||
|
|
||||||
level2 = level1 + [
|
# data_dict = {k: v for k, v in data_dict.items() if not (k.startswith(prefixes[0]) or k.startswith(prefixes[1]))}
|
||||||
('roc', feature_ROC, [10, 30]),
|
# return (data_dict | features_dict)
|
||||||
('rsi', feature_RSI, [10, 30, 100]),
|
|
||||||
('stod', feature_STOD, [10, 30, 200]),
|
|
||||||
('stok', feature_STOK, [10, 30, 200]),
|
|
||||||
]
|
|
||||||
+1
-1
@@ -10,7 +10,7 @@ class StaticAverageModel(Model):
|
|||||||
data_scaling = 'unscaled'
|
data_scaling = 'unscaled'
|
||||||
only_column = 'model_'
|
only_column = 'model_'
|
||||||
|
|
||||||
def fit(self, X, y):
|
def fit(self, X, y, prev_model):
|
||||||
# This is a static model, it can' learn anything
|
# This is a static model, it can' learn anything
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -11,7 +11,7 @@ class Model(ABC):
|
|||||||
only_column: Optional[str]
|
only_column: Optional[str]
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def fit(self, X, y):
|
def fit(self, X, y, prev_model):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
@@ -32,7 +32,7 @@ class SKLearnModel(Model):
|
|||||||
def __init__(self, model):
|
def __init__(self, model):
|
||||||
self.model = model
|
self.model = model
|
||||||
|
|
||||||
def fit(self, X, y):
|
def fit(self, X, y, prev_model):
|
||||||
self.model.fit(X, y)
|
self.model.fit(X, y)
|
||||||
|
|
||||||
def predict(self, X):
|
def predict(self, X):
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ class StaticMomentumModel(Model):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
self.allow_short = allow_short
|
self.allow_short = allow_short
|
||||||
|
|
||||||
def fit(self, X, y):
|
def fit(self, X, y, prev_model):
|
||||||
# This is a static model, it can' learn anything
|
# This is a static model, it can' learn anything
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -10,7 +10,7 @@ class StaticNaiveModel(Model):
|
|||||||
data_scaling = 'unscaled'
|
data_scaling = 'unscaled'
|
||||||
only_column = None
|
only_column = None
|
||||||
|
|
||||||
def fit(self, X, y):
|
def fit(self, X, y, prev_model):
|
||||||
# This is a static model, it can' learn anything
|
# This is a static model, it can' learn anything
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
+7
-6
@@ -15,15 +15,16 @@ def launch_wandb(project_name:str, default_config:dict, sweep:bool=False):
|
|||||||
return wandb
|
return wandb
|
||||||
|
|
||||||
|
|
||||||
def seperate_configs(wandb: Optional[object], model_config:dict, training_config:dict, data_config:dict) -> tuple[dict,dict,dict]:
|
def register_config_with_wandb(wandb: Optional[object], model_config:dict, training_config:dict, data_config:dict):
|
||||||
config: dict = wandb.config
|
config: dict = wandb.config
|
||||||
|
|
||||||
if type(wandb) is not type(None):
|
if type(wandb) is not type(None):
|
||||||
for k in training_config: training_config[k] = config[k]
|
for k in training_config:
|
||||||
for k in model_config: model_config[k] = config[k]
|
training_config[k] = config[k]
|
||||||
# for k in data_config: data_config[k] = config[k]
|
for k in model_config:
|
||||||
|
model_config[k] = config[k]
|
||||||
return model_config, training_config, data_config
|
for k in data_config:
|
||||||
|
data_config[k] = config[k]
|
||||||
|
|
||||||
|
|
||||||
def send_report_to_wandb(results: pd.DataFrame, wandb:Optional[object], project_name: str, model_name: str):
|
def send_report_to_wandb(results: pd.DataFrame, wandb:Optional[object], project_name: str, model_name: str):
|
||||||
|
|||||||
+4
-2
@@ -1,8 +1,9 @@
|
|||||||
from utils.load_data import load_data
|
from utils.load_data import load_data
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from training.training import run_single_asset_trainig
|
from training.training import run_single_asset_trainig
|
||||||
from reporting.wandb import launch_wandb, send_report_to_wandb, seperate_configs
|
from reporting.wandb import launch_wandb, send_report_to_wandb, register_config_with_wandb
|
||||||
from models.model_map import map_model_name_to_function
|
from models.model_map import map_model_name_to_function
|
||||||
|
from feature_extractors.feature_extractor_presets import preprocess_feature_extractors_config
|
||||||
from config import get_default_config, validate_config, get_model_name
|
from config import get_default_config, validate_config, get_model_name
|
||||||
|
|
||||||
def setup_pipeline(project_name:str, with_wandb: bool, sweep: bool):
|
def setup_pipeline(project_name:str, with_wandb: bool, sweep: bool):
|
||||||
@@ -11,9 +12,10 @@ def setup_pipeline(project_name:str, with_wandb: bool, sweep: bool):
|
|||||||
wandb = None
|
wandb = None
|
||||||
if with_wandb:
|
if with_wandb:
|
||||||
wandb = launch_wandb(project_name=project_name, default_config=dict(**model_config, **training_config, **data_config), sweep=sweep)
|
wandb = launch_wandb(project_name=project_name, default_config=dict(**model_config, **training_config, **data_config), sweep=sweep)
|
||||||
model_config, training_config, data_config = seperate_configs(wandb, model_config, training_config, data_config)
|
register_config_with_wandb(wandb, model_config, training_config, data_config)
|
||||||
|
|
||||||
model_config = map_model_name_to_function(model_config, data_config['method'])
|
model_config = map_model_name_to_function(model_config, data_config['method'])
|
||||||
|
data_config = preprocess_feature_extractors_config(data_config)
|
||||||
pipeline(project_name, wandb, sweep, model_config, training_config, data_config)
|
pipeline(project_name, wandb, sweep, model_config, training_config, data_config)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+7
-7
@@ -15,10 +15,10 @@ parameters:
|
|||||||
values: [True, False]
|
values: [True, False]
|
||||||
distribution: categorical
|
distribution: categorical
|
||||||
sliding_window_size:
|
sliding_window_size:
|
||||||
values: [90, 130, 160, 180, 280, 380]
|
values: [180, 280, 380]
|
||||||
distribution: categorical
|
distribution: categorical
|
||||||
retrain_every:
|
retrain_every:
|
||||||
values: [14, 30, 60, 100]
|
values: [10, 20, 30]
|
||||||
distribution: categorical
|
distribution: categorical
|
||||||
scaler:
|
scaler:
|
||||||
values: ['minmax', 'normalize', 'minmax', 'standardize', 'none']
|
values: ['minmax', 'normalize', 'minmax', 'standardize', 'none']
|
||||||
@@ -37,10 +37,6 @@ parameters:
|
|||||||
log_returns:
|
log_returns:
|
||||||
values: [True, False]
|
values: [True, False]
|
||||||
distribution: categorical
|
distribution: categorical
|
||||||
own_features:
|
|
||||||
value: []
|
|
||||||
other_features:
|
|
||||||
value: []
|
|
||||||
index_column:
|
index_column:
|
||||||
value: 'int'
|
value: 'int'
|
||||||
level_1_models:
|
level_1_models:
|
||||||
@@ -49,4 +45,8 @@ parameters:
|
|||||||
level_2_models:
|
level_2_models:
|
||||||
value: []
|
value: []
|
||||||
distribution: constant
|
distribution: constant
|
||||||
|
own_features:
|
||||||
|
values: [['only_mom', 'date_days'], [], ['level_1', 'date_days'], ['level_1', 'date_days', 'level_2']]
|
||||||
|
distribution: categorical
|
||||||
|
other_features:
|
||||||
|
value: []
|
||||||
@@ -42,7 +42,7 @@ class EvenOddStubModel(Model):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
self.window_length = window_length
|
self.window_length = window_length
|
||||||
|
|
||||||
def fit(self, X, y):
|
def fit(self, X, y, prev_model):
|
||||||
assert len(X) == self.window_length
|
assert len(X) == self.window_length
|
||||||
for i in range(len(X)):
|
for i in range(len(X)):
|
||||||
assert y[i] == -1 if X[i][0] == 1 else 1
|
assert y[i] == -1 if X[i][0] == 1 else 1
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ class IncrementingStubModel(Model):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
self.window_length = window_length
|
self.window_length = window_length
|
||||||
|
|
||||||
def fit(self, X, y):
|
def fit(self, X, y, prev_model):
|
||||||
assert len(X) == self.window_length
|
assert len(X) == self.window_length
|
||||||
for i in range(len(X)):
|
for i in range(len(X)):
|
||||||
assert X[i][0] + 1 == y[i]
|
assert X[i][0] + 1 == y[i]
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ def walk_forward_train_test(
|
|||||||
X_slice = X_slice.to_numpy()
|
X_slice = X_slice.to_numpy()
|
||||||
|
|
||||||
current_model = model.clone()
|
current_model = model.clone()
|
||||||
current_model.fit(X_slice, y_slice.to_numpy())
|
current_model.fit(X_slice, y_slice.to_numpy(), models[index-1])
|
||||||
iterations_before_retrain = retrain_every
|
iterations_before_retrain = retrain_every
|
||||||
else:
|
else:
|
||||||
current_model = models[index-1]
|
current_model = models[index-1]
|
||||||
|
|||||||
@@ -4,3 +4,6 @@ import numpy as np
|
|||||||
|
|
||||||
def get_first_valid_return_index(series: pd.Series) -> int:
|
def get_first_valid_return_index(series: pd.Series) -> int:
|
||||||
return np.where(np.logical_and(series != 0, np.logical_not(np.isnan(series))))[0][0]
|
return np.where(np.logical_and(series != 0, np.logical_not(np.isnan(series))))[0][0]
|
||||||
|
|
||||||
|
def flatten(list_of_lists: list) -> list:
|
||||||
|
return [item for sublist in list_of_lists for item in sublist]
|
||||||
+3
-1
@@ -4,4 +4,6 @@ import pandas as pd
|
|||||||
|
|
||||||
Period = int
|
Period = int
|
||||||
IsLogReturn = bool
|
IsLogReturn = bool
|
||||||
FeatureExtractor = Callable[[pd.DataFrame, Period, IsLogReturn], Union[pd.DataFrame, pd.Series]]
|
FeatureExtractor = Callable[[pd.DataFrame, Period, IsLogReturn], Union[pd.DataFrame, pd.Series]]
|
||||||
|
Name = str
|
||||||
|
FeatureExtractorConfig = tuple[Name, FeatureExtractor, list[Period]]
|
||||||
Reference in New Issue
Block a user