# source: https://raw.githubusercontent.com/PeetCrypto/freqtrade-stuff/f6c38def0b2fe01d8d42e47740cdeab53511527b/TrainCatBoostStrategy.py
from freqtrade.strategy import IStrategy, IntParameter, DecimalParameter
import logging
from pandas import DataFrame
from freqtrade.resolvers import StrategyResolver
from itertools import combinations
from functools import reduce
import catboost
import pandas as pd
import numpy as np
from catboost import CatBoostClassifier, Pool, sum_models

logger = logging.getLogger(__name__)

STRATEGIES = [
    "CombinedBinHAndClucV8",
    "CombinedBinHClucAndMADV6",
    "SMAOffset",
    "SMAOffsetV2",
    "SMAOffsetProtectOptV0",
    "SMAOffsetProtectOptV1",
    "NostalgiaForInfinityV4",
]


class Github_PeetCrypto_freqtrade_stuff__TrainCatBoostStrategy__20220218_165353(IStrategy):
    loaded_strategies = {}

    def informative_pairs(self):
        pairs = self.dp.current_whitelist()
        informative_pairs = [(pair, self.informative_timeframe) for pair in pairs]
        return informative_pairs

    def get_strategy(self, strategy_name):
        cached_strategy = self.loaded_strategies.get(strategy_name)
        if cached_strategy:
            return cached_strategy

        config = self.config
        config["strategy"] = strategy_name
        strategy = StrategyResolver.load_strategy(config)
        strategy.dp = self.dp
        self.loaded_strategies[strategy_name] = strategy
        return strategy

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        return dataframe

    def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        strategies = STRATEGIES
        populated_dataframe = dataframe
        populated_dataframe["pair"] = metadata.get("pair")

        for strategy_name in strategies:
            strategy = self.get_strategy(strategy_name)
            populated_dataframe = strategy.advise_indicators(populated_dataframe, metadata)

        for strategy_name in strategies:
            strategy = self.get_strategy(strategy_name)
            strategy_indicators = strategy.advise_indicators(dataframe, metadata)
            dataframe[f"strat_buy_signal_{strategy_name}"] = strategy.advise_buy(
                strategy_indicators, metadata
            )["buy"]
            y = dataframe[f"strat_buy_signal_{strategy_name}"]
            x = populated_dataframe[[col for col in populated_dataframe.columns if "date" not in col]].fillna(-1)
            # remove duplicated columns
            x = x.loc[:, ~x.columns.duplicated()]
            cat_features = [i for i in x.columns if x.dtypes[i] == "object"]
            dataset = Pool(data=x, label=y, cat_features=cat_features)
            baseline_model = CatBoostClassifier(iterations=10)
            try:
                baseline_model = baseline_model.load_model("/freqtrade/user_data/buy_model")
            except:
                # first run
                pass

            model = CatBoostClassifier(iterations=10)
            try:
                model.fit(dataset, use_best_model=True, eval_set=dataset)
            except:
                #  target contains only one value
                pass
            final_model = sum_models(
                [baseline_model, model], weights=None, ctr_merge_policy="IntersectingCountersAverage"
            )
            final_model.save_model("/freqtrade/user_data/buy_model")

        preds = final_model.predict(dataset, prediction_type="Probability")
        dataframe["buy_proba"] = preds[:, 1]

        dataframe["buy"] = dataframe['buy_proba'].apply(lambda x: 1 if x > 0.7 else 0)

        return dataframe

    def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        strategies = STRATEGIES
        populated_dataframe = dataframe
        populated_dataframe["pair"] = metadata.get("pair")

        for strategy_name in strategies:
            strategy = self.get_strategy(strategy_name)
            populated_dataframe = strategy.advise_indicators(populated_dataframe, metadata)

        for strategy_name in strategies:
            strategy = self.get_strategy(strategy_name)
            strategy_indicators = strategy.advise_indicators(dataframe, metadata)
            dataframe[f"strat_sell_signal_{strategy_name}"] = strategy.advise_sell(
                strategy_indicators, metadata
            )["sell"]

            y = dataframe[f"strat_sell_signal_{strategy_name}"]
            x = populated_dataframe[[col for col in populated_dataframe.columns if "date" not in col]].fillna(-1)
            # remove duplicated columns
            x = x.loc[:, ~x.columns.duplicated()]
            cat_features = [i for i in x.columns if x.dtypes[i] == "object"]
            dataset = Pool(data=x, label=y, cat_features=cat_features)
            baseline_model = CatBoostClassifier(iterations=10)
            try:
                baseline_model = baseline_model.load_model("/freqtrade/user_data/sell_model")
            except:
                # first run
                pass

            model = CatBoostClassifier(iterations=10)
            try:
                model.fit(dataset, use_best_model=True, eval_set=dataset)
            except:
                #  target contains only one value
                pass
            final_model = sum_models(
                [baseline_model, model], weights=None, ctr_merge_policy="IntersectingCountersAverage"
            )
            final_model.save_model("/freqtrade/user_data/sell_model")

        preds = final_model.predict(dataset, prediction_type="Probability")
        dataframe["sell_proba"] = preds[:, 1]

        dataframe["sell"] = dataframe['sell_proba'].apply(lambda x: 1 if x > 0.7 else 0)

        return dataframe
