# source: https://raw.githubusercontent.com/wtriantis/freqtrade_user_data/e9c782a77ca9b6b9beb5869992e388a688f51205/strategies/glassnodePolyStrat.py
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
# flake8: noqa: F401
# isort: skip_file
import numpy as np  # noqa
import pandas as pd  # noqa
from pandas import DataFrame
from functools import reduce

from freqtrade.strategy import (
    DecimalParameter,
    IStrategy,
    IntParameter,
)

import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
import logging

logger = logging.getLogger(__name__)

class Github_wtriantis_freqtrade_user_data__glassnodePolyStrat__20240717_202658(IStrategy):
    INTERFACE_VERSION = 3
    timeframe = "1d"
    minimal_roi = {"0": 1}
    stoploss = -1
    can_short = False
    trailing_stop = False
    process_only_new_candles = True
    startup_candle_count: int = 30

    # Hyperparameters for weights
    buy_weight_mvrv = DecimalParameter(0, 1, default=0.5, space="buy")
    buy_weight_spss = DecimalParameter(0, 1, default=0.5, space="buy")
    buy_weight_nupl = DecimalParameter(0, 1, default=0.5, space="buy")
    buy_weight_realized = DecimalParameter(0, 1, default=0.5, space="buy")
    buy_weight_short_term_activity = DecimalParameter(0, 1, default=0.5, space="buy")
    buy_weight_short_term_ratio = DecimalParameter(0, 1, default=0.5, space="buy")
    buy_weight_miners = DecimalParameter(0, 1, default=0.5, space="buy")
    buy_weight_holder_spending = DecimalParameter(0, 1, default=0.5, space="buy")
    buy_weight_holder_mvrv = DecimalParameter(0, 1, default=0.5, space="buy")
    buy_weight_exchange_volume = DecimalParameter(0, 1, default=0.5, space="buy")

    buy_exponent_mvrv = DecimalParameter(0.1, 2, default=1, space="buy")
    buy_exponent_spss = DecimalParameter(0.1, 2, default=1, space="buy")
    buy_exponent_nupl = DecimalParameter(0.1, 2, default=1, space="buy")
    buy_exponent_realized = DecimalParameter(0.1, 2, default=1, space="buy")
    buy_exponent_short_term_activity = DecimalParameter(0.1, 2, default=1, space="buy")
    buy_exponent_short_term_ratio = DecimalParameter(0.1, 2, default=1, space="buy")
    buy_exponent_miners = DecimalParameter(0.1, 2, default=1, space="buy")
    buy_exponent_holder_spending = DecimalParameter(0.1, 2, default=1, space="buy")
    buy_exponent_holder_mvrv = DecimalParameter(0.1, 2, default=1, space="buy")
    buy_exponent_exchange_volume = DecimalParameter(0.1, 2, default=1, space="buy")

    sell_weight_mvrv = DecimalParameter(0, 1, default=0.5, space="sell")
    sell_weight_spss = DecimalParameter(0, 1, default=0.5, space="sell")
    sell_weight_nupl = DecimalParameter(0, 1, default=0.5, space="sell")
    sell_weight_realized = DecimalParameter(0, 1, default=0.5, space="sell")
    sell_weight_short_term_activity = DecimalParameter(0, 1, default=0.5, space="sell")
    sell_weight_short_term_ratio = DecimalParameter(0, 1, default=0.5, space="sell")
    sell_weight_miners = DecimalParameter(0, 1, default=0.5, space="sell")
    sell_weight_holder_spending = DecimalParameter(0, 1, default=0.5, space="sell")
    sell_weight_holder_mvrv = DecimalParameter(0, 1, default=0.5, space="sell")
    sell_weight_exchange_volume = DecimalParameter(0, 1, default=0.5, space="sell")

    sell_exponent_mvrv = DecimalParameter(0.1, 2, default=1, space="sell")
    sell_exponent_spss = DecimalParameter(0.1, 2, default=1, space="sell")
    sell_exponent_nupl = DecimalParameter(0.1, 2, default=1, space="sell")
    sell_exponent_realized = DecimalParameter(0.1, 2, default=1, space="sell")
    sell_exponent_short_term_activity = DecimalParameter(0.1, 2, default=1, space="sell")
    sell_exponent_short_term_ratio = DecimalParameter(0.1, 2, default=1, space="sell")
    sell_exponent_miners = DecimalParameter(0.1, 2, default=1, space="sell")
    sell_exponent_holder_spending = DecimalParameter(0.1, 2, default=1, space="sell")
    sell_exponent_holder_mvrv = DecimalParameter(0.1, 2, default=1, space="sell")
    sell_exponent_exchange_volume = DecimalParameter(0.1, 2, default=1, space="sell")

    def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        mvrv_url = 'https://raw.githubusercontent.com/wtriantis/FreqData/main/bitcoin-mvrv-and-mayer-multiple-pricing-models-signal.csv'
        spss_url = 'https://raw.githubusercontent.com/wtriantis/FreqData/main/bitcoin-supply-profitability-state-signal.csv'
        nupl_url = 'https://raw.githubusercontent.com/wtriantis/FreqData/main/bitcoin-net-unrealized-profit-loss-signal.csv'
        realized_url = 'https://raw.githubusercontent.com/wtriantis/FreqData/main/bitcoin-realized-profit-loss-ratio-14d-ma-signal.csv'
        short_term_activity_url = 'https://raw.githubusercontent.com/wtriantis/FreqData/main/bitcoin-short-term-holder-activity-in-profit-loss-signal.csv'
        short_term_ratio_url = 'https://raw.githubusercontent.com/wtriantis/FreqData/main/bitcoin-short-term-holder-supply-profit-loss-ratio-signal.csv'
        miners_url = 'https://raw.githubusercontent.com/wtriantis/FreqData/main/bitcoin-miners-fee-revenue-binary-indicator-signal.csv'
        holder_spending_url = 'https://raw.githubusercontent.com/wtriantis/FreqData/main/bitcoin-long-term-holder-spending-binary-indicator-7d-signal.csv'
        holder_mvrv_url = 'https://raw.githubusercontent.com/wtriantis/FreqData/main/bitcoin-long-term-holder-mvrv-signal.csv'
        exchange_volume_url = 'https://raw.githubusercontent.com/wtriantis/FreqData/main/bitcoin-exchange-volume-momentum-signal.csv'

        def load_and_clean_data(url, prefix):
            additional_data = pd.read_csv(url)
            logger.info(f"Columns in additional data from {url}: {additional_data.columns}")

            for col in additional_data.columns:
                if 'timestamp' in col:
                    additional_data[col] = pd.to_datetime(additional_data[col], errors='coerce')

            additional_data['timestamp'] = additional_data.apply(lambda row: next((row[col] for col in additional_data.columns if 'timestamp' in col and pd.notnull(row[col])), pd.NaT), axis=1)

            additional_data = additional_data.drop(columns=[col for col in additional_data.columns if 'timestamp' in col and col != 'timestamp'])

            additional_data.set_index('timestamp', inplace=True)

            additional_data = additional_data.add_prefix(prefix + '_')

            return additional_data

        mvrv_data = load_and_clean_data(mvrv_url, 'mvrv')
        spss_data = load_and_clean_data(spss_url, 'spss')
        nupl_data = load_and_clean_data(nupl_url, 'nupl')
        realized_data = load_and_clean_data(realized_url, 'realized')
        short_term_activity_data = load_and_clean_data(short_term_activity_url, 'short_term_activity')
        short_term_ratio_data = load_and_clean_data(short_term_ratio_url, 'short_term_ratio')
        miners_data = load_and_clean_data(miners_url, 'miners')
        holder_spending_data = load_and_clean_data(holder_spending_url, 'holder_spending')
        holder_mvrv_data = load_and_clean_data(holder_mvrv_url, 'holder_mvrv')
        exchange_volume_data = load_and_clean_data(exchange_volume_url, 'exchange_volume')

        additional_data = (
            mvrv_data
            .join(spss_data, how='outer')
            .join(nupl_data, how='outer')
            .join(realized_data, how='outer')
            .join(short_term_activity_data, how='outer')
            .join(short_term_ratio_data, how='outer')
            .join(miners_data, how='outer')
            .join(holder_spending_data, how='outer')
            .join(holder_mvrv_data, how='outer')
            .join(exchange_volume_data, how='outer')
        )

        additional_data = additional_data.resample(self.timeframe).ffill()

        dataframe.set_index('date', inplace=True)
        dataframe = dataframe.join(additional_data, how='left').fillna(method='ffill')
        dataframe.reset_index(inplace=True)

        return dataframe

    def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe['enter_long'] = (
            self.buy_weight_mvrv.value * np.power(dataframe.get('mvrv_Very Low Risk', 0), self.buy_exponent_mvrv.value) +
            self.buy_weight_spss.value * np.power(dataframe.get('spss_Very Low Risk', 0), self.buy_exponent_spss.value) +
            self.buy_weight_nupl.value * np.power(dataframe.get('nupl_Very Low Risk', 0), self.buy_exponent_nupl.value) +
            self.buy_weight_realized.value * np.power(dataframe.get('realized_Very Low Risk', 0), self.buy_exponent_realized.value) +
            self.buy_weight_short_term_activity.value * np.power(dataframe.get('short_term_activity_Very Low Risk', 0), self.buy_exponent_short_term_activity.value) +
            self.buy_weight_short_term_ratio.value * np.power(dataframe.get('short_term_ratio_Very Low Risk', 0), self.buy_exponent_short_term_ratio.value) +
            self.buy_weight_miners.value * np.power(dataframe.get('miners_Very Low Risk', 0), self.buy_exponent_miners.value) +
            self.buy_weight_holder_spending.value * np.power(dataframe.get('holder_spending_Very Low Risk', 0), self.buy_exponent_holder_spending.value) +
            self.buy_weight_holder_mvrv.value * np.power(dataframe.get('holder_mvrv_Very Low Risk', 0), self.buy_exponent_holder_mvrv.value) +
            self.buy_weight_exchange_volume.value * np.power(dataframe.get('exchange_volume_Very Low Risk', 0), self.buy_exponent_exchange_volume.value)
        )

        dataframe['enter_long'] = dataframe['enter_long'] > 0.5

        return dataframe

    def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
        dataframe['exit_long'] = (
            self.sell_weight_mvrv.value * np.power(dataframe.get('mvrv_Very High Risk', 0), self.sell_exponent_mvrv.value) +
            self.sell_weight_spss.value * np.power(dataframe.get('spss_Very High Risk', 0), self.sell_exponent_spss.value) +
            self.sell_weight_nupl.value * np.power(dataframe.get('nupl_Very High Risk', 0), self.sell_exponent_nupl.value) +
            self.sell_weight_realized.value * np.power(dataframe.get('realized_Very High Risk', 0), self.sell_exponent_realized.value) +
            self.sell_weight_short_term_activity.value * np.power(dataframe.get('short_term_activity_Very High Risk', 0), self.sell_exponent_short_term_activity.value) +
            self.sell_weight_short_term_ratio.value * np.power(dataframe.get('short_term_ratio_Very High Risk', 0), self.sell_exponent_short_term_ratio.value) +
            self.sell_weight_miners.value * np.power(dataframe.get('miners_Very High Risk', 0), self.sell_exponent_miners.value) +
            self.sell_weight_holder_spending.value * np.power(dataframe.get('holder_spending_Very High Risk', 0), self.sell_exponent_holder_spending.value) +
            self.sell_weight_holder_mvrv.value * np.power(dataframe.get('holder_mvrv_Very High Risk', 0), self.sell_exponent_holder_mvrv.value) +
            self.sell_weight_exchange_volume.value * np.power(dataframe.get('exchange_volume_Very High Risk', 0), self.sell_exponent_exchange_volume.value)
        )

        dataframe['exit_long'] = dataframe['exit_long'] > 0.5

        return dataframe
