Timeframe
N/A
Direction
Long Only
Stoploss
-99.0%
Trailing Stop
No
ROI
0m: 10000.0%
Interface Version
3
Startup Candles
500
Indicators
3
freqtrade/freqtrade-strategies
Strategy 003 author@: Gerald Lonlas github@: https://github.com/freqtrade/freqtrade-strategies
# BelieveInCoin
# This strategy is for people who believe in a coin. Best for 1 pair and 1 max open trade.
# Author: @ntsd (Jirawat Boonkumnerd)
# Github: https://github.com/ntsd
# freqtrade download-data --exchange binanceusdm -t 5m 15m 1h 4h --days 500
# freqtrade download-data --exchange binanceusdm -t 1d --days 1000
# ProfitDrawDownHyperOptLoss, ShortTradeDurHyperOptLoss, OnlyProfitHyperOptLoss, SharpeHyperOptLoss, SharpeHyperOptLossDaily, SortinoHyperOptLoss, SortinoHyperOptLossDaily
# freqtrade hyperopt --hyperopt-loss OnlyProfitHyperOptLoss --spaces buy sell --timeframe 5m -e 10000 --print-all --strategy BelieveInCoin -j 12
# freqtrade backtesting --timeframe 5m --strategy BelieveInCoin --timerange=20220101-
# freqtrade backtesting --timeframe 5m --strategy-list BelieveInCoin NostalgiaForInfinityX --timerange=20220101-
from freqtrade.strategy import IStrategy, CategoricalParameter, IntParameter, merge_informative_pair
from freqtrade.enums import SignalType
from pandas import DataFrame, Series
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
from functools import reduce
import numpy as np
########################### Static Parameters ###########################
IS_HYPEROPT = True
INDICATORS = ("EMA", "SMA")
# Timeframes available for the exchange `Binance`: 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M
BASE_TIMEFRAME = "5m"
BUY_TIMEFRAMES = ("5m", "15m", "1h", "1d")
BUY_MAX_CONDITIONS = len(BUY_TIMEFRAMES)
SELL_TIMEFRAMES = ("5m", "15m", "1h", "1d")
SELL_MAX_CONDITIONS = len(SELL_TIMEFRAMES)
INFO_TIMEFRAMES = set(BUY_TIMEFRAMES + SELL_TIMEFRAMES) - {"5m"}
BTC_TIMEFRAMES = ("1h", "1d")
PERIODS = []
n = 5
for i in range(1, 15):
PERIODS.append(n)
n += i
PERIODS_LEN = len(PERIODS)
########################### Default hyperopt parameter ###########################
# Buy hyperspace params:
buy_params = {
"buy_fperiod_0": 6,
"buy_fperiod_1": 11,
"buy_fperiod_2": 9,
"buy_fperiod_3": 10,
"buy_indicator_0": "EMA",
"buy_indicator_1": "EMA",
"buy_indicator_2": "SMA",
"buy_indicator_3": "SMA",
"buy_speriod_0": 9,
"buy_speriod_1": 10,
"buy_speriod_2": 12,
"buy_speriod_3": 13,
}
# Sell hyperspace params:
sell_params = {
"sell_fperiod_0": 9,
"sell_fperiod_1": 1,
"sell_fperiod_2": 3,
"sell_fperiod_3": 7,
"sell_indicator_0": "EMA",
"sell_indicator_1": "EMA",
"sell_indicator_2": "SMA",
"sell_indicator_3": "EMA",
"sell_speriod_0": 13,
"sell_speriod_1": 13,
"sell_speriod_2": 5,
"sell_speriod_3": 1,
}
########################### Indicator ###########################
def normalize(df):
df = (df - df.min()) / (df.max() - df.min())
return df
def apply_indicator(dataframe: DataFrame, key: str, indicator: str, period: int):
if key in dataframe.keys():
return
result = getattr(ta, indicator)(dataframe, timeperiod=period)
# dataframe[key] = normalize(result)
dataframe[key] = result
########################### Operators ###########################
def greater_operator(dataframe: DataFrame, main_indicator: str, crossed_indicator: str):
return dataframe[main_indicator] > dataframe[crossed_indicator]
def lower_operator(dataframe: DataFrame, main_indicator: str, crossed_indicator: str):
return dataframe[main_indicator] < dataframe[crossed_indicator]
def true_operator(dataframe: DataFrame, main_indicator: str, crossed_indicator: str):
return dataframe["volume"] > 10
def close_operator(dataframe: DataFrame, main_indicator: str, crossed_indicator: str):
return np.isclose(dataframe[main_indicator], dataframe[crossed_indicator])
def crossed_operator(dataframe: DataFrame, main_indicator: str, crossed_indicator: str):
return (qtpylib.crossed_below(dataframe[main_indicator], dataframe[crossed_indicator])) | (
qtpylib.crossed_above(dataframe[main_indicator], dataframe[crossed_indicator])
)
def crossed_above_operator(dataframe: DataFrame, main_indicator: str, crossed_indicator: str):
return qtpylib.crossed_above(dataframe[main_indicator], dataframe[crossed_indicator])
def crossed_below_operator(dataframe: DataFrame, main_indicator: str, crossed_indicator: str):
return qtpylib.crossed_below(dataframe[main_indicator], dataframe[crossed_indicator])
OPERATORS = {
"D": true_operator,
">": greater_operator,
"<": lower_operator,
"=": close_operator,
"C": crossed_operator,
"CA": crossed_above_operator,
"CB": crossed_below_operator,
}
def apply_operator(dataframe: DataFrame, main_indicator, crossed_indicator, operator) -> tuple[Series, DataFrame]:
condition = OPERATORS[operator](dataframe, main_indicator, crossed_indicator)
return condition, dataframe
########################### HyperOpt Parameters ###########################
class DefaultValue:
def __init__(self, value) -> None:
self.value = value
def get_hyperopt_parameter_keys(trend: str, condition_idx: int):
k_1 = f"{trend}_indicator_{condition_idx}"
k_2 = f"{trend}_fperiod_{condition_idx}"
k_3 = f"{trend}_speriod_{condition_idx}"
return k_1, k_2, k_3
def set_hyperopt_parameters(self):
trend = "buy"
for condition_idx in range(BUY_MAX_CONDITIONS):
k_1, k_2, k_3 = get_hyperopt_parameter_keys(trend, condition_idx)
if IS_HYPEROPT:
setattr(self, k_1, CategoricalParameter(INDICATORS, space=trend, default=buy_params[k_1]))
setattr(self, k_2, IntParameter(0, PERIODS_LEN - 1, space=trend, default=buy_params[k_2]))
setattr(self, k_3, IntParameter(0, PERIODS_LEN - 1, space=trend, default=buy_params[k_3]))
else:
setattr(self, k_1, DefaultValue(buy_params[k_1]))
setattr(self, k_2, DefaultValue(buy_params[k_2]))
setattr(self, k_3, DefaultValue(buy_params[k_3]))
trend = "sell"
for condition_idx in range(SELL_MAX_CONDITIONS):
k_1, k_2, k_3 = get_hyperopt_parameter_keys(trend, condition_idx)
if IS_HYPEROPT:
setattr(self, k_1, CategoricalParameter(INDICATORS, space=trend, default=sell_params[k_1]))
setattr(self, k_2, IntParameter(0, PERIODS_LEN - 1, space=trend, default=sell_params[k_2]))
setattr(self, k_3, IntParameter(0, PERIODS_LEN - 1, space=trend, default=sell_params[k_3]))
else:
setattr(self, k_1, DefaultValue(sell_params[k_1]))
setattr(self, k_2, DefaultValue(sell_params[k_2]))
setattr(self, k_3, DefaultValue(sell_params[k_3]))
return self
########################### Strategy ###########################
@set_hyperopt_parameters
class BelieveInCoin(IStrategy):
def leverage(self, pair: str, current_time, current_rate: float, proposed_leverage: float, max_leverage: float, side: str, **kwargs) -> float:
return 5.0
INTERFACE_VERSION = 3
# ROI table:
minimal_roi = {"0": 100.0}
# Trailing stop:
trailing_stop = False
trailing_stop_positive = 0.03
trailing_stop_positive_offset = 0.05
trailing_only_offset_is_reached = False
# Stoploss
stoploss = -0.99
# Timeframe
timeframe = BASE_TIMEFRAME
# Run "populate_indicators()" only for new candle.
process_only_new_candles = True
# These values can be overridden in the "ask_strategy" section in the config.
use_sell_signal = True
sell_profit_only = False
ignore_roi_if_buy_signal = True
# Number of candles the strategy requires before producing valid signals
startup_candle_count = 500
def __init__(self, config: dict) -> None:
super().__init__(config)
print("Self:", self.__dict__)
########################### Populate Indicators ###########################
def drop_timeframe_data(self, dataframe: DataFrame, timeframe: str) -> DataFrame:
drop_columns = [f"{s}_{timeframe}" for s in ["date", "open", "high", "low", "close", "volume"]]
dataframe.drop(columns=dataframe.columns.intersection(drop_columns), inplace=True)
return dataframe
def info_tf_btc_indicators(self, dataframe: DataFrame) -> DataFrame:
dataframe["btc_rsi_14"] = ta.RSI(dataframe, timeperiod=14)
dataframe["btc_not_downtrend"] = (dataframe["close"] > dataframe["close"].shift(2)) | (dataframe["btc_rsi_14"] > 50)
return dataframe
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# BTC informative (1h)
btc_info_pair = "BTC/USDT"
for btc_timeframe in BTC_TIMEFRAMES: # btc_not_downtrend_1h, btc_not_downtrend_1d
btc_info_tf = self.dp.get_pair_dataframe(btc_info_pair, btc_timeframe)
btc_info_tf = self.info_tf_btc_indicators(btc_info_tf)
dataframe = merge_informative_pair(dataframe, btc_info_tf, self.timeframe, btc_timeframe, ffill=True)
dataframe = self.drop_timeframe_data(dataframe, btc_timeframe)
# Get available parameters
available_indicators = set()
available_info_timeframes = set()
available_periods = set()
run_mode = self.dp.runmode.value
if run_mode in ("backtest", "live", "dry_run"): # for these run mode shoud add only available parameters
for condition_idx in range(BUY_MAX_CONDITIONS):
indicator, fperiod, speriod = self.get_hyperopt_parameters("buy", condition_idx)
available_indicators.add(indicator)
available_info_timeframes.add(BUY_TIMEFRAMES[condition_idx])
available_periods.add(PERIODS[fperiod])
available_periods.add(PERIODS[speriod])
for condition_idx in range(SELL_MAX_CONDITIONS):
indicator, fperiod, speriod = self.get_hyperopt_parameters("sell", condition_idx)
available_indicators.add(indicator)
available_info_timeframes.add(SELL_TIMEFRAMES[condition_idx])
available_periods.add(PERIODS[fperiod])
available_periods.add(PERIODS[speriod])
else:
available_indicators = INDICATORS
available_info_timeframes = INFO_TIMEFRAMES
available_periods = PERIODS
# apply info timeframe indicator
for info_timeframe in available_info_timeframes:
info_dataframe = self.dp.get_pair_dataframe(pair=metadata["pair"], timeframe=info_timeframe, candle_type="futures")
for indicator in available_indicators:
for period in available_periods:
apply_indicator(info_dataframe, f"{indicator}_{period}", indicator, period)
dataframe = merge_informative_pair(dataframe, info_dataframe, self.timeframe, info_timeframe, ffill=True)
# apply base timeframe indicator
for indicator in available_indicators:
for period in available_periods:
apply_indicator(dataframe, f"{indicator}_{period}_{BASE_TIMEFRAME}", indicator, period)
# print(list(dataframe.keys()))
return dataframe
########################### Strategy Logic ###########################
def get_hyperopt_parameters(self, trend: str, condition_idx: int):
k_1, k_2, k_3 = get_hyperopt_parameter_keys(trend, condition_idx)
indicator = getattr(self, k_1).value
fperiod = getattr(self, k_2).value
speriod = getattr(self, k_3).value
return indicator, fperiod, speriod
def get_indicators_pair(self, trend: str, condition_idx: int) -> tuple[str, str, str]:
indicator, fperiod, speriod = self.get_hyperopt_parameters(trend, condition_idx)
if fperiod == speriod:
return None, None, None
if trend == "sell":
operator = "CB" if condition_idx == 0 else "<"
main_indicator = f"{indicator}_{PERIODS[fperiod]}_{SELL_TIMEFRAMES[condition_idx]}"
crossed_indicator = f"{indicator}_{PERIODS[speriod]}_{SELL_TIMEFRAMES[condition_idx]}"
else:
operator = "CA" if condition_idx == 0 else ">"
main_indicator = f"{indicator}_{PERIODS[fperiod]}_{BUY_TIMEFRAMES[condition_idx]}"
crossed_indicator = f"{indicator}_{PERIODS[speriod]}_{BUY_TIMEFRAMES[condition_idx]}"
return main_indicator, crossed_indicator, operator
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
trend = "buy"
conditions = list()
# BTC Condition TODO: Add crsi_1h
for btc_timframe in BTC_TIMEFRAMES:
conditions.append(dataframe[f"btc_not_downtrend_{btc_timframe}"] == True)
for condition_idx in range(BUY_MAX_CONDITIONS):
main_indicator, crossed_indicator, operator = self.get_indicators_pair(trend, condition_idx)
if not operator:
continue
condition, dataframe = apply_operator(dataframe, main_indicator, crossed_indicator, operator)
conditions.append(condition)
if conditions:
dataframe.loc[:, SignalType.ENTER_LONG.value] = reduce(lambda x, y: x & y, conditions)
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
trend = "sell"
conditions = list()
# BTC Condition TODO: Add crsi_1h
for btc_timframe in BTC_TIMEFRAMES:
conditions.append(dataframe[f"btc_not_downtrend_{btc_timframe}"] == False)
for condition_idx in range(BUY_MAX_CONDITIONS):
main_indicator, crossed_indicator, operator = self.get_indicators_pair(trend, condition_idx)
if not operator:
continue
if operator:
condition, dataframe = apply_operator(dataframe, main_indicator, crossed_indicator, operator)
conditions.append(condition)
if conditions:
dataframe.loc[:, SignalType.EXIT_LONG.value] = reduce(lambda x, y: x & y, conditions)
return dataframe