# source: https://raw.githubusercontent.com/remiotore/freqtrade/44beaeb6a420cd8e9f2e4ea93e11d6cfa192ee03/strategies/EnsembleStrategyV1.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

logger = logging.getLogger(__name__)

"""
Hyperoptimizedd using OnlyProfitHyperOptLoss
======================================================= SELL REASON STATS ========================================================
|        Sell Reason |   Sells |   Win  Draws  Loss  Win% |   Avg Profit % |   Cum Profit % |   Tot Profit USDT |   Tot Profit % |
|--------------------+---------+--------------------------+----------------+----------------+-------------------+----------------|
|        sell_signal |     507 |    333     0   174  65.7 |           0.13 |          67.95 |           253.527 |          16.99 |
| trailing_stop_loss |     103 |    103     0     0   100 |           4.88 |         502.33 |          2764.21  |         125.58 |
|                roi |      37 |     35     2     0   100 |           7.93 |         293.51 |          1247.71  |          73.38 |
|          stop_loss |      12 |      0     0    12     0 |         -20.46 |        -245.51 |         -1139.88  |         -61.38 |
====================================================== LEFT OPEN TRADES REPORT ======================================================
|   Pair |   Buys |   Avg Profit % |   Cum Profit % |   Tot Profit USDT |   Tot Profit % |   Avg Duration |   Win  Draw  Loss  Win% |
|--------+--------+----------------+----------------+-------------------+----------------+----------------+-------------------------|
|  TOTAL |      0 |           0.00 |           0.00 |             0.000 |           0.00 |           0:00 |     0     0     0     0 |
=============== SUMMARY METRICS ===============
| Metric                | Value               |
|-----------------------+---------------------|
| Backtesting from      | 2021-05-01 00:00:00 |
| Backtesting to        | 2021-05-31 15:30:00 |
| Max open trades       | 4                   |
|                       |                     |
| Total trades          | 659                 |
| Starting balance      | 1000.000 USDT       |
| Final balance         | 4125.571 USDT       |
| Absolute profit       | 3125.571 USDT       |
| Total profit %        | 312.56%             |
| Trades per day        | 21.97               |
| Avg. stake amount     | 533.922 USDT        |
| Total trade volume    | 351854.681 USDT     |
|                       |                     |
| Best Pair             | MATIC/USDT 180.8%   |
| Worst Pair            | STORJ/USDT -20.27%  |
| Best trade            | DOT/USDT 24.18%     |
| Worst trade           | ZEC/USDT -20.46%    |
| Best day              | 793.247 USDT        |
| Worst day             | -198.590 USDT       |
| Days win/draw/lose    | 26 / 0 / 5          |
| Avg. Duration Winners | 0:41:00             |
| Avg. Duration Loser   | 1:52:00             |
| Zero Duration Trades  | 3.64% (24)          |
| Rejected Buy signals  | 45400               |
|                       |                     |
| Min balance           | 1011.385 USDT       |
| Max balance           | 4125.571 USDT       |
| Drawdown              | 186.4%              |
| Drawdown              | 824.540 USDT        |
| Drawdown high         | 1100.474 USDT       |
| Drawdown low          | 275.934 USDT        |
| Drawdown Start        | 2021-05-19 01:20:00 |
| Drawdown End          | 2021-05-19 12:50:00 |
| Market change         | -28.01%             |
===============================================
"""



STRATEGIES = [
    "CombinedBinHAndCluc",
    "CombinedBinHAndClucV2",
    "CombinedBinHAndClucV5",
    "CombinedBinHAndClucV6H",
    "CombinedBinHAndClucV7",
    "CombinedBinHAndClucV8",
    "CombinedBinHAndClucV8Hyper",
    "SMAOffset",
    "SMAOffsetV2",
    "NostalgiaForInfinityV1",
    "NostalgiaForInfinityV2",
]

STRAT_COMBINATIONS = reduce(
    lambda x, y: list(combinations(STRATEGIES, y)) + x, range(len(STRATEGIES)+1), []
)


class Github_remiotore_freqtrade__EnsembleStrategyV1__20260111_210550(IStrategy):
    loaded_strategies = {}
    buy_mean_threshold = DecimalParameter(0.0, 1, default=0.5, load=True)
    sell_mean_threshold = DecimalParameter(0.0, 1, default=0.5, load=True)
    buy_strategies = IntParameter(0, len(STRAT_COMBINATIONS), default=0, load=True)
    sell_strategies = IntParameter(0, len(STRAT_COMBINATIONS), default=0, load=True)

    buy_params = {
        "buy_mean_threshold": 0.124,
        "buy_strategies": 1440,
    }

    sell_params = {
        "sell_mean_threshold": 0.791,
        "sell_strategies": 1654,
    }

    minimal_roi = {
        "0": 0.242,
        "28": 0.046,
        "68": 0.035,
        "137": 0
    }

    stoploss = -0.203

    trailing_stop = True
    trailing_stop_positive = 0.01
    trailing_stop_positive_offset = 0.041
    trailing_only_offset_is_reached = True

    process_only_new_candles = True
    informative_timeframe = '1h'

    def __init__(self, config: dict) -> None:
        super().__init__(config)
        logger.info(f"Buy stratrategies: {STRAT_COMBINATIONS[self.buy_strategies.value]}")
        logger.info(f"Sell stratrategies: {STRAT_COMBINATIONS[self.sell_strategies.value]}")

    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:
            cached_strategy.dp = self.dp
            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 = STRAT_COMBINATIONS[self.buy_strategies.value]
        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"]

        dataframe['buy'] = (
            dataframe.filter(like='strat_buy_signal_').mean(axis=1) > self.buy_mean_threshold.value
        ).astype(int)
        return dataframe

    def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        strategies = STRAT_COMBINATIONS[self.sell_strategies.value]
        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"]

        dataframe['sell'] = (
            dataframe.filter(like='strat_sell_signal_').mean(axis=1) > self.sell_mean_threshold.value
        ).astype(int)
        return dataframe
