stable/freqtrade/freqai/prediction_models/LightGBMPredictionModel.py

126 lines
4.8 KiB
Python
Raw Normal View History

import logging
from typing import Any, Dict, Tuple
from lightgbm import LGBMRegressor
from pandas import DataFrame
from freqtrade.freqai.data_kitchen import FreqaiDataKitchen
from freqtrade.freqai.freqai_interface import IFreqaiModel
logger = logging.getLogger(__name__)
class LightGBMPredictionModel(IFreqaiModel):
"""
User created prediction model. The class needs to override three necessary
functions, predict(), train(), fit(). The class inherits ModelHandler which
has its own DataHandler where data is held, saved, loaded, and managed.
"""
2022-07-02 16:09:38 +00:00
def return_values(self, dataframe: DataFrame, dk: FreqaiDataKitchen) -> DataFrame:
"""
2022-07-02 16:09:38 +00:00
User uses this function to add any additional return values to the dataframe.
e.g.
dataframe['volatility'] = dk.volatility_values
"""
2022-07-02 16:09:38 +00:00
return dataframe
2022-07-03 08:59:38 +00:00
def train(
self, unfiltered_dataframe: DataFrame, pair: str, dk: FreqaiDataKitchen
) -> Tuple[DataFrame, DataFrame]:
"""
Filter the training data and train a model to it. Train makes heavy use of the datahkitchen
for storing, saving, loading, and analyzing the data.
:params:
:unfiltered_dataframe: Full dataframe for the current training period
:metadata: pair metadata from strategy.
:returns:
:model: Trained model which can be used to inference (self.predict)
"""
2022-07-03 08:59:38 +00:00
logger.info("--------------------Starting training " f"{pair} --------------------")
2022-07-02 16:09:38 +00:00
# unfiltered_labels = self.make_labels(unfiltered_dataframe, dk)
# filter the features requested by user in the configuration file and elegantly handle NaNs
2022-07-02 16:09:38 +00:00
features_filtered, labels_filtered = dk.filter_features(
unfiltered_dataframe,
2022-07-02 16:09:38 +00:00
dk.training_features_list,
dk.label_list,
training_filter=True,
)
# split data into train/test data.
2022-07-02 16:09:38 +00:00
data_dictionary = dk.make_train_test_datasets(features_filtered, labels_filtered)
dk.fit_labels() # fit labels to a cauchy distribution so we know what to expect in strategy
# normalize all data based on train_dataset only
2022-07-02 16:09:38 +00:00
data_dictionary = dk.normalize_data(data_dictionary)
# optional additional data cleaning/analysis
2022-07-02 16:09:38 +00:00
self.data_cleaning_train(dk)
2022-07-03 08:59:38 +00:00
logger.info(
f'Training model on {len(dk.data_dictionary["train_features"].columns)}' " features"
)
logger.info(f'Training model on {len(data_dictionary["train_features"])} data points')
model = self.fit(data_dictionary)
2022-07-03 08:59:38 +00:00
logger.info(f"--------------------done training {pair}--------------------")
return model
def fit(self, data_dictionary: Dict) -> Any:
"""
Most regressors use the same function names and arguments e.g. user
can drop in LGBMRegressor in place of CatBoostRegressor and all data
management will be properly handled by Freqai.
:params:
:data_dictionary: the dictionary constructed by DataHandler to hold
all the training and test data/labels.
"""
eval_set = (data_dictionary["test_features"], data_dictionary["test_labels"])
X = data_dictionary["train_features"]
y = data_dictionary["train_labels"]
model = LGBMRegressor(**self.model_training_parameters)
model.fit(X=X, y=y, eval_set=eval_set)
return model
2022-07-03 08:59:38 +00:00
def predict(
self, unfiltered_dataframe: DataFrame, dk: FreqaiDataKitchen, first: bool = False
2022-07-03 08:59:38 +00:00
) -> Tuple[DataFrame, DataFrame]:
"""
Filter the prediction features data and predict with it.
:param: unfiltered_dataframe: Full dataframe for the current backtest period.
:return:
2022-07-10 09:06:18 +00:00
:pred_df: dataframe containing the predictions
:do_predict: np.array of 1s and 0s to indicate places where freqai needed to remove
data (NaNs) or felt uncertain about data (PCA and DI index)
"""
2022-07-09 08:21:42 +00:00
dk.find_features(unfiltered_dataframe)
2022-07-02 16:09:38 +00:00
filtered_dataframe, _ = dk.filter_features(
2022-07-09 08:21:42 +00:00
unfiltered_dataframe, dk.training_features_list, training_filter=False
)
2022-07-02 16:09:38 +00:00
filtered_dataframe = dk.normalize_data_from_metadata(filtered_dataframe)
dk.data_dictionary["prediction_features"] = filtered_dataframe
# optional additional data cleaning/analysis
2022-07-02 16:09:38 +00:00
self.data_cleaning_predict(dk, filtered_dataframe)
2022-07-02 16:09:38 +00:00
predictions = self.model.predict(dk.data_dictionary["prediction_features"])
pred_df = DataFrame(predictions, columns=dk.label_list)
2022-07-02 16:09:38 +00:00
for label in dk.label_list:
2022-07-03 08:59:38 +00:00
pred_df[label] = (
(pred_df[label] + 1)
* (dk.data["labels_max"][label] - dk.data["labels_min"][label])
/ 2
) + dk.data["labels_min"][label]
2022-07-02 16:09:38 +00:00
return (pred_df, dk.do_predict)