# Zeus Strategy: First Generation of GodStra Strategy with maximum # AVG/MID profit in USDT # Author: @Mablue (Masoud Azizi) # github: https://github.com/mablue/ # IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta) # freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi --strategy Zeus # --- Do not remove these libs --- from datetime import timedelta, datetime from typing import Optional from freqtrade import data from freqtrade.persistence import Trade from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter from numpy.lib import math from freqtrade.strategy.interface import IStrategy import pandas from pandas import DataFrame import time import logging import calendar from freqtrade.loggers import setup_logging from freqtrade.strategy.strategy_helper import merge_informative_pair # -------------------------------- # Add your lib to import here import ta from functools import reduce import numpy as np import talib.abstract as talib from freqtrade.strategy.strategy_helper import merge_informative_pair import freqtrade.vendor.qtpylib.indicators as qtpylib from random import shuffle logger = logging.getLogger(__name__) operators = [ "D", # Disabled gene ">", # Indicator, bigger than cross indicator "<", # Indicator, smaller than cross indicator "=", # Indicator, equal with cross indicator "C", # Indicator, crossed the cross indicator "CA", # Indicator, crossed above the cross indicator "CB", # Indicator, crossed below the cross indicator ">R", # Normalized indicator, bigger than real number "=R", # Normalized indicator, equal with real number "R", # Normalized indicator devided to cross indicator, bigger than real number "/=R", # Normalized indicator devided to cross indicator, equal with real number "/ 10) # TODO : it ill callculated in populate indicators. dataframe[indicator] = gene_calculator(dataframe, indicator) dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator) indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}" if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]: dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma) if operator == ">": condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage)) elif operator == "=": condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) elif operator == "<": condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage)) elif operator == "C": condition = ( (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) | (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) ) elif operator == "CA": condition = ( qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) elif operator == "CB": condition = ( qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) elif operator == ">R": condition = (dataframe[indicator].shift(decalage) > real_num) elif operator == "=R": condition = (np.isclose(dataframe[indicator].shift(decalage), real_num)) elif operator == "R": condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num) elif operator == "/=R": condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num)) elif operator == "/ dataframe[indicator_trend_sma].shift(decalage)) elif operator == "DT": condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)) elif operator == "OT": condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))) elif operator == "CUT": condition = ( ( qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) ) & ( dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage) ) ) elif operator == "CDT": condition = ( ( qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) ) & ( dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage) ) ) elif operator == "COT": condition = ( ( ( qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) ) | ( qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) ) ) & ( np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)) ) ) return condition, dataframe class Zeus_AI(IStrategy): # * 1/43: 86 trades. 72/6/8 Wins/Draws/Losses. Avg profit 12.66%. Median profit 11.99%. Total profit 0.10894395 BTC ( 108.94Σ%). Avg duration 3 days, 0:31:00 min. Objective: -48.48793 # "max_open_trades": 10, # "stake_currency": "BTC", # "stake_amount": 0.01, # "tradable_balance_ratio": 0.99, # "timeframe": "4h", # "dry_run_wallet": 0.1, # Buy hyperspace params: buy_b_params = { "buy_b_cat": "R", "=R", "R", "=R", "R", "=R", " -0.03): # self.stop_buy_for_all = True # return "btc_fall" # bb_width_lim = last_candle['bb_width'] / 4 # bb_width_up = last_candle['bb_upperband'] * (1 - last_candle['bb_width'] / 5) if (last_candle['mrsi3_1h'] <= 0): #(self.market_overview_pct5 < 0) | (last_candle['pct_change_1_4h'] < 0): max_percent = 0.004 # last_candle['bb_width'] / 3.5 # 0.005 max_profit = 0.004 # last_candle['bb_width'] * 3 / 4 # 0.015 if (current_profit > 0.01) & \ (last_candle['percent10'] < -0.005) & ((current_time - trade.open_date_utc).seconds >= 3600): return 'b_percent10' if (current_profit > max_profit) & \ ((last_candle['percent'] < - max_percent) | (last_candle['percent3'] < -max_percent) | ( last_candle['percent5'] < -max_percent)): return 'b_percent_quick' if (current_profit >= - self.sell_b_too_old_percent.value) & (days >= self.sell_b_too_old_day.value)\ & (days < self.sell_b_too_old_day.value * 2)\ & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): return "b_too_old_0.01" if (current_profit >= - self.sell_b_too_old_percent.value * 2) & (days >= self.sell_b_too_old_day.value * 2)\ & (days < self.sell_b_too_old_day.value * 3) \ & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): return "b_too_old_0.02" if (current_profit >= - self.sell_b_too_old_percent.value * 3) & (days >= self.sell_b_too_old_day.value * 3) \ & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): return "b_too_old_0.03" if self.profit_b_quick_lost.value and (current_profit >= max_profit) & ( last_candle['percent3'] < -max_percent): return "b_quick_lost" if self.profit_b_no_change.value and (current_profit > self.sell_b_profit_no_change.value) \ & (last_candle['percent10'] < self.sell_b_profit_percent10.value) & (last_candle['percent5'] < 0) \ & ((current_time - trade.open_date_utc).seconds >= 3600): return "b_no_change" if (current_profit > self.sell_b_percent.value) & (last_candle['percent3'] < - self.sell_b_percent3.value) \ & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_b_candels.value): return "b_quick_gain_param" if self.profit_b_sma5.value: if (current_profit > expected_profit) \ & ((previous_5_candle['sma5'] > last_candle['sma5']) \ | (last_candle['percent3'] < -expected_profit) | ( last_candle['percent5'] < -expected_profit)) \ & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'b_sma5' if self.profit_b_sma10.value: if (current_profit > expected_profit) \ & ((previous_5_candle['sma10'] > last_candle['sma10']) \ | (last_candle['percent3'] < -expected_profit) | ( last_candle['percent5'] < -expected_profit)) \ & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'b_sma10' if self.profit_b_sma20.value: if (current_profit > max_percent) \ & (previous_last_candle['sma10'] > last_candle['sma10']) \ & ((current_time - trade.open_date_utc).seconds >= 3600) \ & ((previous_last_candle['sma20'] > last_candle['sma20']) & ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( last_candle['percent20'] < 0))): # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'b_sma20' if self.profit_b_over_rsi.value: if (current_profit > 0) & (previous_last_candle[ 'rsi'] > self.sell_b_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'b_over_rsi' if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI2.value) & \ (last_candle[ 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'b_over_rsi_2' if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_b_RSI3.value) & \ (last_candle['close'] >= last_candle['max200']) & (last_candle[ 'percent'] < - self.sell_b_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'b_over_rsi_max' if self.profit_b_short_loss.value: if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( last_candle['percent'] < 0) \ & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'b_short_lost' else: max_percent = 0.005 # last_candle['bb_width'] / 3.5 # 0.005 max_profit = 0.01 # last_candle['bb_width'] * 3 / 4 # 0.015 if (current_profit > max_profit) & ( (last_candle['percent'] < -max_percent) | (last_candle['percent3'] < -max_percent) | ( last_candle['percent5'] < -max_percent)): return 'h_percent_quick' # if (last_candle['bb_width'] < 0.02) & (current_profit > 0) & (last_candle['close'] > bb_width_up) & \ # ((last_candle['percent'] < - bb_width_lim) | (last_candle['percent3'] < - bb_width_lim) | (last_candle['percent5'] < - bb_width_lim)): # return 'h_bb_width_max' if (current_profit >= - self.sell_h_too_old_percent.value) & (days >= self.sell_h_too_old_day.value)\ & (days < self.sell_h_too_old_day.value * 2)\ & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): return "h_too_old_0.01" if (current_profit >= - self.sell_h_too_old_percent.value * 2) & (days >= self.sell_h_too_old_day.value * 2)\ & (days < self.sell_h_too_old_day.value * 3) \ & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): return "h_too_old_0.02" if (current_profit >= - self.sell_h_too_old_percent.value * 3) & (days >= self.sell_h_too_old_day.value * 3) \ & (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0): return "h_too_old_0.03" if self.profit_h_quick_lost.value and (current_profit >= max_profit) & ( last_candle['percent3'] < -max_percent): return "h_quick_lost" if self.profit_h_no_change.value and (current_profit > self.sell_h_profit_no_change.value) \ & (last_candle['percent10'] < self.sell_h_profit_percent10.value) & (last_candle['percent5'] < 0) \ & ((current_time - trade.open_date_utc).seconds >= 3600): return "h_no_change" if (current_profit > self.sell_h_percent.value) & (last_candle['percent3'] < - self.sell_h_percent3.value) \ & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_h_candels.value): return "h_quick_gain_param" if self.profit_h_sma5.value: if (current_profit > expected_profit) \ & ((previous_5_candle['sma5'] > last_candle['sma5']) \ | (last_candle['percent3'] < -expected_profit) | ( last_candle['percent5'] < -expected_profit)) \ & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'h_sma5' if self.profit_h_sma10.value: if (current_profit > expected_profit) \ & ((previous_5_candle['sma10'] > last_candle['sma10']) \ | (last_candle['percent3'] < -expected_profit) | ( last_candle['percent5'] < -expected_profit)) \ & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)): # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'h_sma10' if self.profit_h_sma20.value: if (current_profit > max_percent) \ & (previous_last_candle['sma10'] > last_candle['sma10']) \ & ((current_time - trade.open_date_utc).seconds >= 3600) \ & ((previous_last_candle['sma20'] > last_candle['sma20']) & ((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | ( last_candle['percent20'] < 0))): # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'h_sma20' if self.profit_h_over_rsi.value: if (current_profit > 0) & (previous_last_candle[ 'rsi'] > self.sell_h_RSI.value): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'h_over_rsi' if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI2.value) & \ (last_candle[ 'percent'] < - self.sell_h_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'h_over_rsi_2' if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_h_RSI3.value) & \ (last_candle['close'] >= last_candle[ 'max200']): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'h_over_rsi_max' if self.profit_h_short_loss.value: if (current_profit > -expected_profit) & (previous_last_candle['percent10'] > 0.04) & ( last_candle['percent'] < 0) \ & (days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)): # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate) return 'h_short_lost' def informative_pairs(self): # get access to all pairs available in whitelist. pairs = self.dp.current_whitelist() informative_pairs = [(pair, '1d') for pair in pairs] informative_pairs += [(pair, '4h') for pair in pairs] informative_pairs += [(pair, '1h') for pair in pairs] corr_pairs = self.config["freqai"]["feature_parameters"]["include_corr_pairlist"] for tf in self.config["freqai"]["feature_parameters"]["include_timeframes"]: for pair in pairs: informative_pairs.append((pair, tf)) for pair in corr_pairs: if pair in pairs: continue # avoid duplication informative_pairs.append((pair, tf)) return informative_pairs def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: # Add all ta features dataframe = self.freqai.start(dataframe, metadata, self) return dataframe def populate_any_indicators(self, pair, dataframe, tf, informative=None, set_generalized_indicators=False): dataframe['trend_ichimoku_base'] = ta.trend.ichimoku_base_line( dataframe['high'], dataframe['low'], window1=9, window2=26, visual=False, fillna=False ) KST = ta.trend.KSTIndicator( close=dataframe['close'], roc1=10, roc2=15, roc3=20, roc4=30, window1=10, window2=10, window3=10, window4=15, nsig=9, fillna=False ) dataframe['trend_kst_diff'] = KST.kst_diff() dataframe['pct_change'] = dataframe['close'].pct_change(5) dataframe['min'] = talib.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value) dataframe['min10'] = talib.MIN(dataframe['close'], timeperiod=10) dataframe['min20'] = talib.MIN(dataframe['close'], timeperiod=20) dataframe['min50'] = talib.MIN(dataframe['close'], timeperiod=50) dataframe['min200'] = talib.MIN(dataframe['close'], timeperiod=200) dataframe['min200_1'] = dataframe['min200'] * 1.005 dataframe['moy200_12'] = dataframe['min200'].rolling(12).mean() dataframe['max50'] = talib.MAX(dataframe['close'], timeperiod=50) dataframe['max200'] = talib.MAX(dataframe['close'], timeperiod=200) dataframe['min_max200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['min200'] dataframe['min_n'] = talib.MIN(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) dataframe['max_n'] = talib.MAX(dataframe['close'], timeperiod=12 * self.buy_min_max_nh.value) dataframe['min_max_n'] = (dataframe['max_n'] - dataframe['min_n']) / dataframe['min_n'] dataframe['rsi'] = talib.RSI(dataframe) dataframe['rsi5'] = talib.RSI(dataframe, timeperiod=5) dataframe['sma5'] = talib.SMA(dataframe, timeperiod=5) dataframe['sma10'] = talib.SMA(dataframe, timeperiod=10) dataframe['sma20'] = talib.SMA(dataframe, timeperiod=20) dataframe['sma50'] = talib.SMA(dataframe, timeperiod=50) dataframe['sma100'] = talib.SMA(dataframe, timeperiod=100) dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"] dataframe["percent5"] = dataframe["percent"].rolling(5).sum() dataframe["percent3"] = dataframe["percent"].rolling(3).sum() dataframe["percent10"] = dataframe["percent"].rolling(10).sum() dataframe["percent20"] = dataframe["percent"].rolling(20).sum() dataframe["percent50"] = dataframe["percent"].rolling(50).sum() # dataframe['percent_lost_n'] = dataframe["percent"].rolling(self.protection_lost_candles.value).sum() dataframe["volume10"] = dataframe["volume"].rolling(10).mean() # Bollinger Bands bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2) dataframe['bb_lowerband'] = bollinger['lower'] dataframe['bb_middleband'] = bollinger['mid'] dataframe['bb_upperband'] = bollinger['upper'] dataframe["bb_percent"] = ( (dataframe["close"] - dataframe["bb_lowerband"]) / (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) ) dataframe["bb_width"] = ( (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] ) dataframe['bb_lower_var_5'] = (dataframe['bb_lowerband'] - dataframe['min50']).rolling(5).var() dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1) dataframe['bb_lower_width_5'] = (dataframe['bb_lowerband'] * (1 + dataframe['bb_width'] / self.buy_bb_width_n.value)) # dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36) dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close'] dataframe['min1.1'] = 1.01 * dataframe['min'] dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean()) # dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var() # dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var() dataframe['min_max_close'] = ( (dataframe['max200'] - dataframe['close']) / (dataframe['close'] - dataframe['min200'])) dataframe['sar'] = talib.SAR(dataframe) # Normalization tib = dataframe['trend_ichimoku_base'] dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min()) tkd = dataframe['trend_kst_diff'] dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min()) dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0) dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1) dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2) dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0) dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1) dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2) dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0]) dataframe['atr'] = talib.ATR(dataframe, timeperiod=14) ################### INFORMATIVE 1D informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d") informative["rsi"] = talib.RSI(informative) informative["max3"] = talib.MAX(informative['close'], timeperiod=3) informative["min3"] = talib.MIN(informative['close'], timeperiod=3) informative['pct_change_1'] = informative['close'].pct_change(1) informative['pct_change_3'] = informative['close'].pct_change(3) informative['pct_change_5'] = informative['close'].pct_change(5) informative['sma3'] = talib.SMA(informative, timeperiod=3) informative['sma5'] = talib.SMA(informative, timeperiod=5) informative['sma10'] = talib.SMA(informative, timeperiod=10) informative['sar'] = talib.SAR(informative) bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2) informative['bb_lowerband'] = bollinger['lower'] informative['bb_middleband'] = bollinger['mid'] informative['bb_upperband'] = bollinger['upper'] informative["bb_percent"] = ( (informative["close"] - informative["bb_lowerband"]) / (informative["bb_upperband"] - informative["bb_lowerband"]) ) informative["bb_width"] = ( (informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"] ) dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True) ######################## INFORMATIVE 4h informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h") informative["rsi"] = talib.RSI(informative) informative['pct_change_1'] = informative['close'].pct_change(1) informative['pct_change_3'] = informative['close'].pct_change(3) informative['pct_change_5'] = informative['close'].pct_change(5) informative['sma3'] = talib.SMA(informative, timeperiod=3) informative['sma5'] = talib.SMA(informative, timeperiod=5) informative['sma10'] = talib.SMA(informative, timeperiod=10) dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", ffill=True) ######################## INFORMATIVE 1h informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1h") informative["rsi"] = talib.RSI(informative) informative["mrsi3"] = informative["rsi"].rolling(3).mean() informative['pct_change_1'] = informative['close'].pct_change(1) informative['pct_change_3'] = informative['close'].pct_change(3) informative['pct_change_5'] = informative['close'].pct_change(5) informative['sma3'] = talib.SMA(informative, timeperiod=3) informative['sma5'] = talib.SMA(informative, timeperiod=5) informative['sma10'] = talib.SMA(informative, timeperiod=10) dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1h", ffill=True) """ Function designed to automatically generate, name and merge features from user indicated timeframes in the configuration file. User controls the indicators passed to the training/prediction by prepending indicators with `'%-' + coin ` (see convention below). I.e. user should not prepend any supporting metrics (e.g. bb_lowerband below) with % unless they explicitly want to pass that metric to the model. :param pair: pair to be used as informative :param df: strategy dataframe which will receive merges from informatives :param tf: timeframe of the dataframe which will modify the feature names :param informative: the dataframe associated with the informative pair :param coin: the name of the coin which will modify the feature names. """ coin = pair.split('/')[0] if informative is None: informative = self.dp.get_pair_dataframe(pair, tf) # first loop is automatically duplicating indicators for time periods for t in self.freqai_info["feature_parameters"]["indicator_periods_candles"]: t = int(t) informative[f"%-{coin}rsi-period_{t}"] = ta.RSI(informative, timeperiod=t) informative[f"%-{coin}mfi-period_{t}"] = ta.MFI(informative, timeperiod=t) informative[f"%-{coin}adx-period_{t}"] = ta.ADX(informative, window=t) indicators = [col for col in informative if col.startswith("%")] # This loop duplicates and shifts all indicators to add a sense of recency to data for n in range(self.freqai_info["feature_parameters"]["include_shifted_candles"] + 1): if n == 0: continue informative_shift = informative[indicators].shift(n) informative_shift = informative_shift.add_suffix("_shift-" + str(n)) informative = pandas.concat((informative, informative_shift), axis=1) dataframe = merge_informative_pair(dataframe, informative, self.config["timeframe"], tf, ffill=True) skip_columns = [ (s + "_" + tf) for s in ["date", "open", "high", "low", "close", "volume"] ] dataframe = dataframe.drop(columns=skip_columns) # Add generalized indicators here (because in live, it will call this # function to populate indicators during training). Notice how we ensure not to # add them multiple times if set_generalized_indicators: # user adds targets here by prepending them with &- (see convention below) # If user wishes to use multiple targets, a multioutput prediction model # needs to be used such as templates/CatboostPredictionMultiModel.py dataframe["&-s_close"] = ( dataframe["close"] .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) .mean() / dataframe["close"] - 1 ) return dataframe def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe.loc[ ( (dataframe['trend_ichimoku_base'] <= self.buy_base.value) & (dataframe['rsi'] < self.buy_rsi.value) & (dataframe['close'] < dataframe['sma10']) & (dataframe['close'] < dataframe['bb_lower_width_5']) # & (dataframe['min50'] == dataframe['min50'].shift(3)) # & (dataframe['min50'].shift(2) == dataframe['min50']) # & (dataframe['close'] <= dataframe['close_1d']) & (dataframe['close'] <= dataframe['close_1h']) ), ['buy', 'buy_tag']] = (1, 'buy_ichimoku') dataframe.loc[ ( (dataframe['min_max_n'] >= self.buy_min_max_n.value) & (dataframe['cond1'].shift(self.buy_min_max_decalage.value) <= self.buy_min_max_cond1.value) & (dataframe['rsi'] < self.buy_min_max_rsi.value) & (dataframe['close'] < dataframe['min_n'] * self.buy_min_max_coef.value) & (dataframe['min_n'].shift(self.buy_min_max_decalage.value) == dataframe['min_n']) & (dataframe['pct_change_1_1d'] > 0) # & (dataframe['min50'] == dataframe['min50'].shift(3)) # & (dataframe['close'] <= dataframe['close_1d']) & (dataframe['close'] <= dataframe['close_1h']) ), ['buy', 'buy_tag']] = (1, 'buy_min_max') return dataframe def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: return dataframe def adjust_trade_position(self, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, min_stake: float, max_stake: float, **kwargs): dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) if (len(dataframe) < 1): return None last_candle = dataframe.iloc[-1].squeeze() last_candle_5 = dataframe.iloc[-3].squeeze() min_d = min(last_candle['sma3_4h'], last_candle['close_1d']) filled_buys = trade.select_filled_orders('buy') count_of_buys = len(filled_buys) days = (current_time - trade.open_date_utc).days minutes = (current_time - trade.open_date_utc).seconds / 60 # condition = (last_candle['cond1'] <= 0.75) & (last_candle['bb_width'] > 0.018) & ( # last_candle['rsi'] < 72) & (last_candle['close'] < last_candle['min50'] * 1.006)# & (last_candle['min_max_close'] > 2) condition = (last_candle['min50'] == last_candle_5['min50']) & (last_candle['close'] <= last_candle['close_1h']) p = self.protection_percent_buy_lost.value percents = [p, p * 2, p * 3, p * 4, p * 5, p * 6, p * 7, p * 8, p * 9] if (0 < count_of_buys <= self.protection_nb_buy_lost.value) \ & (current_profit < - (percents[count_of_buys - 1] / 100)) & (condition): try: p = self.config['stake_amount'] factors = [p, p, p, p, 2 * p, 4 * p, 5 * p, 6 * p] stake_amount = factors[count_of_buys - 1]# filled_buys[0].cost # This then calculates current safety order size # stake_amount = stake_amount * pow(1.5, count_of_buys) print("-----------" + trade.pair + " " + str(current_profit) + " " + str(count_of_buys) + " " + str(stake_amount) + "---------------------") return stake_amount except Exception as exception: print(exception) return None return None