import logging import numpy as np import pandas as pd from technical import qtpylib from pandas import DataFrame from datetime import datetime, timezone from typing import Optional from functools import reduce import talib.abstract as ta import pandas_ta as pta from freqtrade.strategy import BooleanParameter, CategoricalParameter, DecimalParameter, IStrategy, IntParameter, RealParameter, merge_informative_pair import freqtrade.vendor.qtpylib.indicators as qtpylib from freqtrade.persistence import Trade from technical import qtpylib, pivots_points class CTIBS(IStrategy): INTERFACE_VERSION = 3 stoploss = -0.2 timeframe = '15m' use_custom_stoploss = True trailing_stop = True ignore_roi_if_entry_signal = True use_exit_signal = True minimal_roi = {'0': 0.1} # DCA settings exit_profit_only = True position_adjustment_enable = True max_entry_position_adjustment = 0 max_dca_multiplier = 1 ## Optional order time in force. order_time_in_force = {'entry': 'gtc', 'exit': 'ioc'} # Number of candles the strategy requires before producing valid signals startup_candle_count: int = 100 ### ------------------ HYPER-OPT PARAMETERS ----------------------- ### ### protections #### # CooldownPeriod cooldown_lookback = IntParameter(0, 48, default=5, space='protection', optimize=True) # StoplossGuard use_stop_protection = BooleanParameter(default=True, space='protection', optimize=True) stop_duration = IntParameter(12, 200, default=5, space='protection', optimize=True) stop_protection_only_per_pair = BooleanParameter(default=False, space='protection', optimize=True) stop_protection_only_per_side = BooleanParameter(default=False, space='protection', optimize=True) stop_protection_trade_limit = IntParameter(1, 10, default=4, space='protection', optimize=True) stop_protection_required_profit = DecimalParameter(-1.0, 3.0, default=0.0, space='protection', optimize=True) # LowProfitPairs use_lowprofit_protection = BooleanParameter(default=True, space='protection', optimize=True) lowprofit_protection_lookback = IntParameter(1, 10, default=6, space='protection', optimize=True) lowprofit_trade_limit = IntParameter(1, 10, default=4, space='protection', optimize=True) lowprofit_stop_duration = IntParameter(1, 100, default=60, space='protection', optimize=True) lowprofit_required_profit = DecimalParameter(-1.0, 3.0, default=0.0, space='protection', optimize=True) lowprofit_only_per_pair = BooleanParameter(default=False, space='protection', optimize=True) # MaxDrawdown use_maxdrawdown_protection = BooleanParameter(default=True, space='protection', optimize=True) maxdrawdown_protection_lookback = IntParameter(1, 10, default=6, space='protection', optimize=True) maxdrawdown_trade_limit = IntParameter(1, 20, default=10, space='protection', optimize=True) maxdrawdown_stop_duration = IntParameter(1, 100, default=6, space='protection', optimize=True) maxdrawdown_allowed_drawdown = DecimalParameter(0.01, 0.1, default=0.0, space='protection', optimize=True) ### DCA ### # max_epa = CategoricalParameter([0, 1, 2, 3], default=0, space="entry", optimize=True) ### trailing stop loss optimiziation ### tsl_target5 = DecimalParameter(low=0.2, high=0.4, decimals=1, default=0.3, space='exit', optimize=True, load=True) ts5 = DecimalParameter(low=0.04, high=0.06, default=0.05, decimals=2, space='exit', optimize=True, load=True) tsl_target4 = DecimalParameter(low=0.15, high=0.2, default=0.2, decimals=2, space='exit', optimize=True, load=True) ts4 = DecimalParameter(low=0.03, high=0.05, default=0.045, decimals=2, space='exit', optimize=True, load=True) tsl_target3 = DecimalParameter(low=0.1, high=0.15, default=0.15, decimals=2, space='exit', optimize=True, load=True) ts3 = DecimalParameter(low=0.025, high=0.04, default=0.035, decimals=3, space='exit', optimize=True, load=True) tsl_target2 = DecimalParameter(low=0.08, high=0.1, default=0.1, decimals=3, space='exit', optimize=True, load=True) ts2 = DecimalParameter(low=0.015, high=0.03, default=0.02, decimals=3, space='exit', optimize=True, load=True) tsl_target1 = DecimalParameter(low=0.05, high=0.08, default=0.06, decimals=3, space='exit', optimize=True, load=True) ts1 = DecimalParameter(low=0.01, high=0.016, default=0.013, decimals=3, space='exit', optimize=True, load=True) tsl_target0 = DecimalParameter(low=0.02, high=0.045, default=0.03, decimals=3, space='exit', optimize=True, load=True) ts0 = DecimalParameter(low=0.008, high=0.015, default=0.013, decimals=3, space='exit', optimize=True, load=True) ### indicators ### #entry reference_ma_length = IntParameter(185, 195, default=200, space='entry', optimize=True) smoothing_length = IntParameter(15, 30, default=30, space='entry', optimize=True) entry_offset1 = DecimalParameter(low=0.97, high=0.99, decimals=2, default=0.98, space='entry', optimize=True, load=True) entry_offset2 = DecimalParameter(low=0.92, high=0.97, decimals=2, default=0.96, space='entry', optimize=True, load=True) entry_change = DecimalParameter(1.2, 2.0, default=1.5, decimals=1, space='entry', optimize=True) exit_change = DecimalParameter(1.2, 2.0, default=1.5, decimals=1, space='exit', optimize=True) max_length = CategoricalParameter([24, 48, 72, 96, 144, 192, 240], default=48, space='entry') # exiting filterlength = IntParameter(low=30, high=40, default=35, space='exit', optimize=True) exit_offset1 = DecimalParameter(low=1.01, high=1.05, decimals=2, default=1.03, space='exit', optimize=True, load=True) exit_change = DecimalParameter(1.2, 2.0, default=1.5, decimals=1, space='exit', optimize=True) ### entrying values ### entry_change = DecimalParameter(1.2, 2.0, default=1.5, decimals=1, space='entry', optimize=True) ### exiting values ### exit_slope = DecimalParameter(-0.05, 0.1, default=0.04, decimals=2, space='exit', optimize=True) ### I.B.S. ### # Reference Ma - Long Term Direction ref_bull = DecimalParameter(0.075, 0.125, default=0.01, decimals=3, space='entry', optimize=True) ref_up = DecimalParameter(0.01, 0.075, default=0.01, decimals=3, space='entry', optimize=True) ref_down = DecimalParameter(-0.075, -0.01, default=-0.01, decimals=3, space='entry', optimize=True) ref_bear = DecimalParameter(-0.125, -0.075, default=-0.1, decimals=3, space='entry', optimize=True) # Smooth Change Ma - Short Term Direction smooth_bull = DecimalParameter(0.075, 0.125, default=0.01, decimals=3, space='entry', optimize=True) smooth_up = DecimalParameter(0.01, 0.075, default=0.02, decimals=3, space='entry', optimize=True) smooth_down = DecimalParameter(-0.075, -0.01, default=-0.02, decimals=3, space='entry', optimize=True) smooth_bear = DecimalParameter(-0.125, -0.075, default=-0.1, decimals=3, space='entry', optimize=True) # Distance from Long Term High from_bull = DecimalParameter(-5, -1, default=-1, decimals=1, space='entry', optimize=True) from_up = DecimalParameter(-5, -2, default=-3.5, decimals=1, space='entry', optimize=True) from_ranging = DecimalParameter(-6.5, -2, default=-6.5, decimals=1, space='entry', optimize=True) from_down = DecimalParameter(-7.5, -5.0, default=-7.5, decimals=1, space='entry', optimize=True) from_bear = DecimalParameter(-12.5, -7.5, default=-10.0, decimals=1, space='entry', optimize=True) # Selecting what works entry01 = CategoricalParameter([True, False], default=True, space='entry') entry02 = CategoricalParameter([True, False], default=True, space='entry') entry03 = CategoricalParameter([True, False], default=True, space='entry') entry04 = CategoricalParameter([True, False], default=True, space='entry') entry05 = CategoricalParameter([True, False], default=True, space='entry') entry06 = CategoricalParameter([True, False], default=True, space='entry') entry07 = CategoricalParameter([True, False], default=True, space='entry') entry08 = CategoricalParameter([True, False], default=True, space='entry') entry09 = CategoricalParameter([True, False], default=True, space='entry') entry10 = CategoricalParameter([True, False], default=True, space='entry') entry11 = CategoricalParameter([True, False], default=True, space='entry') entry12 = CategoricalParameter([True, False], default=True, space='entry') entry13 = CategoricalParameter([True, False], default=True, space='entry') entry14 = CategoricalParameter([True, False], default=True, space='entry') entry15 = CategoricalParameter([True, False], default=True, space='entry') entry16 = CategoricalParameter([True, False], default=True, space='entry') entry17 = CategoricalParameter([True, False], default=True, space='entry') entry18 = CategoricalParameter([True, False], default=True, space='entry') entry19 = CategoricalParameter([True, False], default=True, space='entry') entry20 = CategoricalParameter([True, False], default=True, space='entry') entry21 = CategoricalParameter([True, False], default=True, space='entry') entry22 = CategoricalParameter([True, False], default=True, space='entry') entry23 = CategoricalParameter([True, False], default=True, space='entry') entry24 = CategoricalParameter([True, False], default=True, space='entry') entry25 = CategoricalParameter([True, False], default=True, space='entry') entry26 = CategoricalParameter([True, False], default=True, space='entry') entry27 = CategoricalParameter([True, False], default=True, space='entry') entry28 = CategoricalParameter([True, False], default=True, space='entry') entry29 = CategoricalParameter([True, False], default=True, space='entry') entry30 = CategoricalParameter([True, False], default=True, space='entry') exit01 = CategoricalParameter([True, False], default=True, space='exit') exit02 = CategoricalParameter([True, False], default=True, space='exit') exit03 = CategoricalParameter([True, False], default=True, space='exit') exit04 = CategoricalParameter([True, False], default=True, space='exit') exit05 = CategoricalParameter([True, False], default=True, space='exit') exit06 = CategoricalParameter([True, False], default=True, space='exit') exit07 = CategoricalParameter([True, False], default=True, space='exit') exit08 = CategoricalParameter([True, False], default=True, space='exit') exit09 = CategoricalParameter([True, False], default=True, space='exit') exit10 = CategoricalParameter([True, False], default=True, space='exit') #----------------------- END OF HYPER-OPT PARAMETERS -------------------------# @property def protections(self): prot = [] prot.append({'method': 'CooldownPeriod', 'stop_duration_candles': self.cooldown_lookback.value}) if self.use_stop_protection.value: prot.append({'method': 'StoplossGuard', 'lookback_period_candles': 24 * 3, 'trade_limit': self.stop_protection_trade_limit.value, 'stop_duration_candles': self.stop_duration.value, 'only_per_pair': self.stop_protection_only_per_pair.value, 'required_profit': self.stop_protection_required_profit.value, 'only_per_side': self.stop_protection_only_per_side.value}) if self.use_lowprofit_protection.value: prot.append({'method': 'LowProfitPairs', 'lookback_period_candles': self.lowprofit_protection_lookback.value, 'trade_limit': self.lowprofit_trade_limit.value, 'stop_duration_candles': self.lowprofit_stop_duration.value, 'required_profit': self.lowprofit_required_profit.value, 'only_per_pair': self.lowprofit_only_per_pair.value}) if self.use_maxdrawdown_protection.value: prot.append({'method': 'MaxDrawdown', 'lookback_period_candles': self.maxdrawdown_protection_lookback.value, 'trade_limit': self.maxdrawdown_trade_limit.value, 'stop_duration_candles': self.maxdrawdown_stop_duration.value, 'max_allowed_drawdown': self.maxdrawdown_allowed_drawdown.value}) return prot # @property # def max_entry_position_adjustment(self): # return self.max_epa.value ### Dollar Cost Averaging ### This can be Turned on ### # This is called when placing the initial order (opening trade) def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, proposed_stake: float, min_stake: Optional[float], max_stake: float, leverage: float, entry_tag: Optional[str], side: str, **kwargs) -> float: # We need to leave most of the funds for possible further DCA orders # This also applies to fixed stakes return proposed_stake / self.max_dca_multiplier def adjust_trade_position(self, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, min_stake: Optional[float], max_stake: float, current_entry_rate: float, current_exit_rate: float, current_entry_profit: float, current_exit_profit: float, **kwargs) -> Optional[float]: if current_profit > 0.1 and current_profit < 0.15 and (trade.nr_of_successful_exits == 0): # Take 50% of the profit at +10% return -(trade.stake_amount / 2) if current_profit > -0.03 and trade.nr_of_successful_entries == 1: return None if current_profit > -0.1 and trade.nr_of_successful_entries == 2: return None if current_profit > -0.16 and trade.nr_of_successful_entries == 3: return None filled_entries = trade.select_filled_orders(trade.entry_side) count_of_entries = trade.nr_of_successful_entries # Allow up to 3 additional increasingly larger entrys (4 in total) # Initial entry is 1x # If that falls to -5% profit, we entry 1.25x more, average profit should increase to roughly -2.2% # If that falls down to -5% again, we entry 1.5x more # If that falls once again down to -5%, we entry 1.75x more # Total stake for this trade would be 1 + 1.25 + 1.5 + 1.75 = 5.5x of the initial allowed stake. # Total stake for this trade would be 1 + 1.5 + 2 + 2.5 = 5.5x of the initial allowed stake. # That is why max_dca_multiplier is 5.5 # Hope you have a deep wallet! try: # This returns first order stake size stake_amount = filled_entries[0].cost # This then calculates current safety order size stake_amount = stake_amount * (1 + count_of_entries * 0.5) return stake_amount except Exception as exception: return None return None ### Trailing Stop ### def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime, current_rate: float, current_profit: float, **kwargs) -> float: for stop5 in self.tsl_target5.range: if current_profit > stop5: for stop5a in self.ts5.range: self.dp.send_msg(f'*** {pair} *** Profit: {current_profit} - lvl5 {stop5}/{stop5a} activated') return stop5a for stop4 in self.tsl_target4.range: if current_profit > stop4: for stop4a in self.ts4.range: self.dp.send_msg(f'*** {pair} *** Profit {current_profit} - lvl4 {stop4}/{stop4a} activated') return stop4a for stop3 in self.tsl_target3.range: if current_profit > stop3: for stop3a in self.ts3.range: self.dp.send_msg(f'*** {pair} *** Profit {current_profit} - lvl3 {stop3}/{stop3a} activated') return stop3a for stop2 in self.tsl_target2.range: if current_profit > stop2: for stop2a in self.ts2.range: self.dp.send_msg(f'*** {pair} *** Profit {current_profit} - lvl2 {stop2}/{stop2a} activated') return stop2a for stop1 in self.tsl_target1.range: if current_profit > stop1: for stop1a in self.ts1.range: self.dp.send_msg(f'*** {pair} *** Profit {current_profit} - lvl1 {stop1}/{stop1a} activated') return stop1a for stop0 in self.tsl_target0.range: if current_profit > stop0: for stop0a in self.ts0.range: self.dp.send_msg(f'*** {pair} *** Profit {current_profit} - lvl0 {stop0}/{stop0a} activated') return stop0a return self.stoploss def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """Generate all indicators used by the strategy""" # Pivot Points pivots = pivots_points.pivots_points(dataframe, timeperiod=32, levels=5) #50 dataframe['pivot'] = pivots['pivot'] dataframe['s5'] = pivots['s5'] dataframe['r5'] = pivots['r5'] dataframe['s3'] = pivots['s3'] dataframe['r3'] = pivots['r3'] dataframe['s2'] = pivots['s2'] dataframe['r2'] = pivots['r2'] dataframe['r3-dif'] = (dataframe['r3'] - dataframe['r2']) / 4 dataframe['r2.25'] = dataframe['r2'] + dataframe['r3-dif'] dataframe['r2.50'] = dataframe['r2'] + dataframe['r3-dif'] * 2 dataframe['r2.75'] = dataframe['r2'] + dataframe['r3-dif'] * 3 # Filter ZEMA for exiting for length in self.filterlength.range: dataframe[f'ema_1{length}'] = ta.EMA(dataframe['close'], timeperiod=length) dataframe[f'ema_2{length}'] = ta.EMA(dataframe[f'ema_1{length}'], timeperiod=length) dataframe[f'ema_dif{length}'] = dataframe[f'ema_1{length}'] - dataframe[f'ema_2{length}'] dataframe[f'zema_{length}'] = dataframe[f'ema_1{length}'] + dataframe[f'ema_dif{length}'] # Reference MA and offsets for valma in self.reference_ma_length.range: dataframe[f'reference_ma_{valma}'] = ta.SMA(dataframe['close'], timeperiod=valma) dataframe['entry_offset1'] = dataframe[f'reference_ma_{valma}'] * self.entry_offset1.value dataframe['entry_offset2'] = dataframe[f'reference_ma_{valma}'] * self.entry_offset2.value dataframe['exit_offset1'] = dataframe[f'reference_ma_{valma}'] * self.exit_offset1.value dataframe['ref_slope'] = (dataframe[f'reference_ma_{valma}'] - dataframe[f'reference_ma_{valma}'].shift(1)) / dataframe[f'reference_ma_{valma}'].shift(1) dataframe['ref_slope_sma'] = ta.SMA(dataframe['ref_slope'] * 100, timeperiod=5) # distance from reference ma to current close dataframe['change'] = (dataframe['close'] - dataframe[f'reference_ma_{valma}']) / dataframe['close'] * 100 # smoothing the change and offsets for valsma in self.smoothing_length.range: dataframe[f'smooth_change_{valsma}'] = ta.SMA(dataframe['change'], timeperiod=valsma) dataframe['entry_offset3'] = dataframe[f'smooth_change_{valsma}'] - self.entry_change.value dataframe['exit_offset2'] = dataframe[f'smooth_change_{valsma}'] + self.exit_change.value dataframe['smooth_ma_slope'] = pta.momentum.slope(dataframe[f'smooth_change_{valsma}']) dataframe['smooth_slope_sma'] = ta.SMA(dataframe['smooth_ma_slope'], timeperiod=5) ### I.ntelligent B.uying S.ystem ### # 300 Candle Rolling Min-Max for l in self.max_length.range: dataframe['min'] = dataframe['open'].rolling(l).min() dataframe['max'] = dataframe['close'].rolling(l).max() # distance from the rolling max in percent dataframe['from_max'] = (dataframe['close'] - dataframe['max']) / dataframe['close'] * 100 # distance from the rolling min in percent dataframe['from_min'] = (dataframe['open'] - dataframe['max']) / dataframe['open'] * 100 return dataframe def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame: conditions = [] # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['smooth_slope_sma'], self.smooth_bull.value) & (df['ref_slope_sma'] > self.ref_bull.value) & (df['from_max'] > self.from_bull.value) & (self.entry01.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '1 Smooth Bull - Ref Bull') #not using # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['smooth_slope_sma'], self.smooth_up.value) & (df['smooth_slope_sma'] < self.smooth_bull.value) & (df['from_max'] < self.from_bull.value) & (df['ref_slope_sma'] > self.ref_bull.value) & (self.entry02.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '2 Smooth Up - Ref Bull') # (qtpylib.crossed_above(df['smooth_slope_sma'], -self.smooth_ranging.value)) & # Make sure Volume is not 0 df.loc[(df['smooth_slope_sma'] < self.smooth_up.value) & (df['smooth_slope_sma'] > self.smooth_down.value) & (df['from_max'] < self.from_ranging.value) & (df['ref_slope_sma'] > self.ref_bull.value) & (self.entry03.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '3 Smooth Range - Ref Bull') # Make sure Volume is not 0 df.loc[qtpylib.crossed_below(df['smooth_slope_sma'], self.smooth_down.value) & (df['smooth_slope_sma'] > self.smooth_bear.value) & (df['ref_slope_sma'] > self.ref_bull.value) & (df['from_max'] < self.from_down.value) & (self.entry04.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '4Smooth Down - Ref Bull') #not using # changed from 1 - 2 # Make sure Volume is not 0 df.loc[qtpylib.crossed_below(df['smooth_slope_sma'], self.smooth_bear.value) & (df['close'] < df['entry_offset2']) & (df['smooth_slope_sma'] < self.smooth_bear.value) & (df['ref_slope_sma'] > self.ref_bull.value) & (df['from_max'] < self.from_bear.value) & (self.entry05.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '5 Smooth Bear - Ref Bull') # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['smooth_slope_sma'], self.smooth_bull.value) & (df['ref_slope_sma'] < self.ref_bull.value) & (df['ref_slope_sma'] > self.ref_up.value) & (df['from_max'] < self.from_up.value) & (self.entry06.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '6 Smooth Bull - Ref Up') # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['smooth_slope_sma'], self.smooth_up.value) & (df['smooth_slope_sma'] < self.smooth_bull.value) & (df['ref_slope_sma'] < self.ref_bull.value) & (df['ref_slope_sma'] > self.ref_up.value) & (df['from_max'] < self.from_up.value) & (self.entry07.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '7 Smooth Up - Ref Up') # not using # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['smooth_slope_sma'], self.smooth_down.value) & (df['smooth_slope_sma'] < self.smooth_up.value) & (df['smooth_slope_sma'] > self.smooth_down.value) & (df['ref_slope_sma'] < self.ref_bull.value) & (df['ref_slope_sma'] > self.ref_up.value) & (df['from_max'] < self.from_ranging.value) & (self.entry08.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '8 Smooth Range - Ref Up') # not using # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['smooth_slope_sma'], self.smooth_down.value) & (df['smooth_slope_sma'] > self.smooth_bear.value) & (df['ref_slope_sma'] < self.ref_bull.value) & (df['ref_slope_sma'] > self.ref_up.value) & (df['from_max'] < self.from_down.value) & (self.entry09.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '9 Smooth Down - Ref Up') # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['smooth_slope_sma'], self.smooth_bear.value) & (df['close'] < df['entry_offset1']) & (df['smooth_slope_sma'] < self.smooth_bear.value) & (df['ref_slope_sma'] < self.ref_bull.value) & (df['ref_slope_sma'] > self.ref_up.value) & (df['from_max'] < self.from_bear.value) & (self.entry10.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '10 Smooth Bear - Ref Up') # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['smooth_slope_sma'], self.smooth_bull.value) & (df['ref_slope_sma'] < self.ref_up.value) & (df['ref_slope_sma'] > self.ref_down.value) & (df['from_max'] < self.from_ranging.value) & (self.entry11.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '11 Smooth Bull - Ref Range') # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['smooth_slope_sma'], self.smooth_up.value) & (df['smooth_slope_sma'] < self.smooth_bull.value) & (df['ref_slope_sma'] < self.ref_up.value) & (df['ref_slope_sma'] > self.ref_down.value) & (df['from_max'] < self.from_ranging.value) & (self.entry12.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '12 Smooth Up - Ref Range') # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['smooth_slope_sma'], self.smooth_down.value) & (df['smooth_slope_sma'] < self.smooth_up.value) & (df['smooth_slope_sma'] > self.smooth_down.value) & (df['ref_slope_sma'] < self.ref_up.value) & (df['ref_slope_sma'] > self.ref_down.value) & (df['from_max'] < self.from_ranging.value) & (self.entry13.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '13 Smooth Range - Ref Range') # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['smooth_slope_sma'], self.smooth_down.value) & (df['smooth_slope_sma'] > self.smooth_bear.value) & (df['ref_slope_sma'] < self.ref_up.value) & (df['ref_slope_sma'] > self.ref_down.value) & (df['from_max'] < self.from_down.value) & (self.entry14.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '14 Smooth Down - Ref Range') # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['smooth_slope_sma'], self.smooth_bear.value) & (df['close'] < df['entry_offset1']) & (df['smooth_slope_sma'] < self.smooth_bear.value) & (df['ref_slope_sma'] < self.ref_up.value) & (df['ref_slope_sma'] > self.ref_down.value) & (df['from_max'] < self.from_bear.value) & (self.entry15.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '15 Smooth Bear - Ref Range') # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['smooth_slope_sma'], self.smooth_bull.value) & (df['ref_slope_sma'] < self.ref_down.value) & (df['ref_slope_sma'] > self.ref_bear.value) & (df['from_max'] < self.from_down.value) & (self.entry16.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '16 Smooth Bull - Ref Down') # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['smooth_slope_sma'], self.smooth_up.value) & (df['smooth_slope_sma'] > self.smooth_bull.value) & (df['ref_slope_sma'] < self.ref_down.value) & (df['ref_slope_sma'] > self.ref_bear.value) & (df['from_max'] < self.from_down.value) & (self.entry17.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '17 Smooth Up - Ref Down') # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['change'], df[f'smooth_change_{self.smoothing_length.value}']) & (df['close'] < df['entry_offset1']) & (df['smooth_slope_sma'] < self.smooth_up.value) & (df['smooth_slope_sma'] > self.smooth_down.value) & (df['ref_slope_sma'] < self.ref_down.value) & (df['ref_slope_sma'] > self.ref_bear.value) & (df['from_max'] < self.from_down.value) & (self.entry18.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '18 Smooth Range - Ref Down') # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['change'], df[f'smooth_change_{self.smoothing_length.value}']) & (df['smooth_slope_sma'] > self.smooth_bear.value) & (df['ref_slope_sma'] < self.ref_down.value) & (df['ref_slope_sma'] > self.ref_bear.value) & (df['from_max'] < self.from_down.value) & (self.entry19.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '19 Smooth Down - Ref Down - % XO') # Make sure Volume is not 0 df.loc[(df['min'] > df['close']) & (df['smooth_slope_sma'] > self.smooth_bear.value) & (df['ref_slope_sma'] < self.ref_down.value) & (df['ref_slope_sma'] > self.ref_bear.value) & (df['from_max'] < self.from_down.value) & (self.entry20.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '20 Smooth Down - Ref Down - Open < Min') # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['smooth_slope_sma'], self.smooth_bear.value) & (df['smooth_slope_sma'] < self.smooth_bear.value) & (df['ref_slope_sma'] < self.ref_down.value) & (df['ref_slope_sma'] > self.ref_bear.value) & (df['from_max'] < self.from_down.value) & (self.entry21.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '21 Smooth Bear - Ref Down') # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['smooth_slope_sma'], self.smooth_bull.value) & (df['ref_slope_sma'] < self.ref_bear.value) & (df['from_max'] < self.from_bear.value) & (self.entry22.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '22 Smooth Bull - Ref Bear') # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['smooth_slope_sma'], self.smooth_up.value) & (df['smooth_slope_sma'] < self.smooth_bull.value) & (df['ref_slope_sma'] < self.ref_bear.value) & (df['from_max'] < self.from_bear.value) & (self.entry23.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '23 Smooth Up - Ref Bear') # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['smooth_slope_sma'], self.smooth_down.value) & (df['smooth_slope_sma'] < self.smooth_up.value) & (df['smooth_slope_sma'] > self.smooth_down.value) & (df['ref_slope_sma'] < self.ref_bear.value) & (df['from_max'] < self.from_bear.value) & (self.entry24.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '24 Smooth Range - Ref Bear') # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['smooth_slope_sma'], self.smooth_down.value) & (df['smooth_slope_sma'] > self.smooth_bear.value) & (df['ref_slope_sma'] < self.ref_bear.value) & (df['from_max'] < self.from_bear.value) & (self.entry25.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '25 Smooth Down - Ref Bear') # (df['close'] < df['entry_offset2']) & # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['smooth_slope_sma'], self.smooth_bear.value) & (df['smooth_slope_sma'] < self.smooth_bear.value) & (df['ref_slope_sma'] < self.ref_bear.value) & (df['from_max'] < self.from_bear.value) & (self.entry26.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '26 Smooth Bear - Ref Bear') # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['change'], df['entry_offset3']) & (df['pivot'] < df['exit_offset1']) & (df['close'] < df['entry_offset1']) & (df['smooth_slope_sma'] > self.smooth_down.value) & (df['from_max'] < self.from_ranging.value) & (self.entry27.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '27 XO above entry_offset3 | Range - Bull') # Make sure Volume is not 0 df.loc[(df['min'] < df['entry_offset1']) & (df['from_max'] - df['from_max'].shift(8) < self.from_down.value) & (df['close'] < df['entry_offset1']) & (self.entry28.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '28 Low XB Min < entry_offset1') # Make sure Volume is not 0 df.loc[qtpylib.crossed_above(df['change'], df['entry_offset3']) & (df['pivot'] < df['exit_offset1']) & (df['close'] < df['entry_offset1']) & (df['smooth_slope_sma'] < self.smooth_down.value) & (df['from_max'] < self.from_down.value) & (self.entry29.value == True) & (df['volume'] > 0), ['enter_long', 'enter_tag']] = (1, '29 XO above entry_offset3 | Down - Bear') # df.loc[ # ( # (qtpylib.crossed_above(df['pivot'], df[f'reference_ma_{self.reference_ma_length.value}'])) & # # (df['close'] < df[f'reference_ma_{self.reference_ma_length.value}']) & # # (df[f'reference_ma_{self.reference_ma_length.value}'] > df[f'reference_ma_{self.reference_ma_length.value}'].shift(1)) & # (df['smooth_ma_slope'] > df['ref_slope_sma']) & # (df['ref_slope_sma'] > 0) & # (self.entry30.value == True) & # (df['volume'] > 0) # Make sure Volume is not 0 # ), # ['enter_long', 'enter_tag']] = (1, '30 Golden XO') # df.loc[ # ( # (qtpylib.crossed_above(df['change'], df['entry_offset3'])) & # (df['smooth_ma_slope'] < 0) & # (df['close'] < df[f'reference_ma_{self.reference_ma_length.value}']) & # (df['volume'] > 0) # Make sure Volume is not 0 # ), # ['enter_long', 'enter_tag']] = (1, 'XO above entry_offset|slope down') # df.loc[ # ( # (qtpylib.crossed_above(df['change'], df['entry_offset3'])) & # (df['smooth_ma_slope'] > -0.005) & # (df['close'] < df[f'reference_ma_{self.reference_ma_length.value}']) & # (df['volume'] > 0) # Make sure Volume is not 0 # ), # ['enter_long', 'enter_tag']] = (1, 'XO above entry_offset|slope up') # df.loc[ # ( # (df['min'] < df['entry_offset1']) & # ((df['from_max'] - df['from_max'].shift(8)) < self.bear_from_max.value) & # (df['close'] < df['entry_offset1']) & # (df['volume'] > 0) # Make sure Volume is not 0 # ), # ['enter_long', 'enter_tag']] = (1, 'Low XB Min < entry_offset1') # df.loc[ # ( # (qtpylib.crossed_above(df['close'], df['entry_offset2'])) & # (df['change'] < df['entry_offset3']) & # (df['volume'] > 0) # Make sure Volume is not 0 # ), # ['enter_long', 'enter_tag']] = (1, 'XO above entry_offset2') # df.loc[ # ( # (qtpylib.crossed_above(df['change'], df[f'smooth_change_{self.smoothing_length.value}'])) & # (df['close'] < df[f'reference_ma_{self.reference_ma_length.value}']) & # (df[f'reference_ma_{self.reference_ma_length.value}'] > df[f'reference_ma_{self.reference_ma_length.value}'].shift(1)) & # (df['close'] > df['entry_offset1']) & # (df['smooth_ma_slope'] < 0) & # (df['volume'] > 0) # Make sure Volume is not 0 # ), # ['enter_long', 'enter_tag']] = (1, 'XO above Ref') return df def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame: # Make sure Volume is not 0 df.loc[qtpylib.crossed_below(df[f'zema_{self.filterlength.value}'], df['r5']) & (df['close'] > df[f'reference_ma_{self.reference_ma_length.value}'] * self.exit_offset1.value) & (self.exit01.value == True) & (df['volume'] > 0), ['exit_long', 'exit_tag']] = (1, 'R5 - XO') # Make sure Volume is not 0 df.loc[qtpylib.crossed_below(df[f'zema_{self.filterlength.value}'], df['r3']) & (df['smooth_ma_slope'] < self.exit_slope.value) & (self.exit02.value == True) & (df['volume'] > 0), ['exit_long', 'exit_tag']] = (1, 'R3 - XO') # Make sure Volume is not 0 df.loc[qtpylib.crossed_below(df[f'zema_{self.filterlength.value}'], df['r2.75']) & (df['smooth_ma_slope'] < self.exit_slope.value) & (self.exit03.value == True) & (df['volume'] > 0), ['exit_long', 'exit_tag']] = (1, 'R2.75 - XO') # Make sure Volume is not 0 df.loc[qtpylib.crossed_below(df[f'zema_{self.filterlength.value}'], df['r2.50']) & (df['smooth_ma_slope'] < self.exit_slope.value) & (self.exit04.value == True) & (df['volume'] > 0), ['exit_long', 'exit_tag']] = (1, 'R2.5 - XO') # Make sure Volume is not 0 df.loc[qtpylib.crossed_below(df[f'zema_{self.filterlength.value}'], df['r2.25']) & (df['smooth_ma_slope'] < self.exit_slope.value) & (self.exit05.value == True) & (df['volume'] > 0), ['exit_long', 'exit_tag']] = (1, 'R2.25 - XO') # Make sure Volume is not 0 df.loc[qtpylib.crossed_below(df[f'zema_{self.filterlength.value}'], df['r2']) & (df['smooth_ma_slope'] < self.exit_slope.value) & (self.exit06.value == True) & (df['volume'] > 0), ['exit_long', 'exit_tag']] = (1, 'R2 - XO') # Make sure Volume is not 0 df.loc[qtpylib.crossed_below(df[f'zema_{self.filterlength.value}'], df['pivot']) & (df['smooth_ma_slope'] < self.exit_slope.value) & (self.exit07.value == True) & (df['volume'] > 0), ['exit_long', 'exit_tag']] = (1, 'Pivot - XO') return df # Best result: # 585/1000: 279 trades. 259/0/20 Wins/Draws/Losses. Avg profit 2.54%. Median profit 3.90%. Total profit 2061.56810074 USDT ( 206.16%). Avg duration 1 day, 23:57:00 min. Objective: -2061.56810 # # Buy hyperspace params: # entry_params = { # "entry1": True, # value loaded from strategy # "entry10": True, # value loaded from strategy # "entry11": False, # value loaded from strategy # "entry12": False, # value loaded from strategy # "entry13": False, # value loaded from strategy # "entry14": False, # value loaded from strategy # "entry15": False, # value loaded from strategy # "entry16": True, # value loaded from strategy # "entry17": True, # value loaded from strategy # "entry18": True, # value loaded from strategy # "entry19": False, # value loaded from strategy # "entry2": False, # value loaded from strategy # "entry20": True, # value loaded from strategy # "entry21": True, # value loaded from strategy # "entry22": True, # value loaded from strategy # "entry23": True, # value loaded from strategy # "entry24": False, # value loaded from strategy # "entry25": True, # value loaded from strategy # "entry26": True, # value loaded from strategy # "entry27": True, # value loaded from strategy # "entry28": False, # value loaded from strategy # "entry29": True, # value loaded from strategy # "entry3": True, # value loaded from strategy # "entry4": True, # value loaded from strategy # "entry5": False, # value loaded from strategy # "entry6": True, # value loaded from strategy # "entry7": True, # value loaded from strategy # "entry8": False, # value loaded from strategy # "entry9": False, # value loaded from strategy # "entry_change": 1.6, # value loaded from strategy # "entry_offset1": 0.99, # value loaded from strategy # "entry_offset2": 0.92, # value loaded from strategy # "from_bear": -11.7, # value loaded from strategy # "from_bull": -3.1, # value loaded from strategy # "from_down": -5.4, # value loaded from strategy # "from_ranging": -3.5, # value loaded from strategy # "from_up": -4.7, # value loaded from strategy # "ref_bear": -0.113, # value loaded from strategy # "ref_bull": 0.098, # value loaded from strategy # "ref_down": -0.067, # value loaded from strategy # "ref_up": 0.027, # value loaded from strategy # "reference_ma_length": 192, # value loaded from strategy # "smooth_bear": -0.117, # value loaded from strategy # "smooth_bull": 0.086, # value loaded from strategy # "smooth_down": -0.013, # value loaded from strategy # "smooth_up": 0.073, # value loaded from strategy # "smoothing_length": 23, # value loaded from strategy # } # # Sell hyperspace params: # exit_params = { # "filterlength": 35, # "exit_change": 1.8, # "exit_offset1": 1.03, # "exit_slope": -0.04, # "ts0": 0.008, # "ts1": 0.011, # "ts2": 0.021, # "ts3": 0.031, # "ts4": 0.03, # "ts5": 0.05, # "tsl_target0": 0.044, # "tsl_target1": 0.055, # "tsl_target2": 0.083, # "tsl_target3": 0.12, # "tsl_target4": 0.2, # "tsl_target5": 0.4, # } # # Protection hyperspace params: # protection_params = { # "cooldown_lookback": 1, # "lowprofit_only_per_pair": True, # "lowprofit_protection_lookback": 1, # "lowprofit_required_profit": -0.829, # "lowprofit_stop_duration": 83, # "lowprofit_trade_limit": 1, # "maxdrawdown_allowed_drawdown": 0.1, # "maxdrawdown_protection_lookback": 3, # "maxdrawdown_stop_duration": 74, # "maxdrawdown_trade_limit": 1, # "stop_duration": 102, # "stop_protection_only_per_pair": True, # "stop_protection_only_per_side": True, # "stop_protection_required_profit": -0.924, # "stop_protection_trade_limit": 9, # "use_lowprofit_protection": False, # "use_maxdrawdown_protection": True, # "use_stop_protection": False, # } # # ROI table: # value loaded from strategy # minimal_roi = { # "0": 0.1 # } # # Stoploss: # stoploss = -0.2 # value loaded from strategy # # Trailing stop: # trailing_stop = True # value loaded from strategy # trailing_stop_positive = None # value loaded from strategy # trailing_stop_positive_offset = 0.0 # value loaded from strategy # trailing_only_offset_is_reached = False # value loaded from strategy # { # "strategy_name": "CTIBS", # "params": { # "roi": { # "0": 0.14300000000000002, # "736": 0.099, # "2369": 0.024, # "5731": 0 # }, # "stoploss": { # "stoploss": -0.28 # }, # "trailing": { # "trailing_stop": true, # "trailing_stop_positive": null, # "trailing_stop_positive_offset": 0.0, # "trailing_only_offset_is_reached": false # }, # "max_open_trades": { # "max_open_trades": 6 # }, # "entry": { # "entry1": true, # "entry10": false, # "entry11": true, # "entry12": false, # "entry13": false, # "entry14": true, # "entry15": false, # "entry16": true, # "entry17": false, # "entry18": false, # "entry19": false, # "entry2": false, # "entry20": false, # "entry21": false, # "entry22": false, # "entry23": true, # "entry24": false, # "entry25": true, # "entry26": false, # "entry27": true, # "entry28": true, # "entry29": true, # "entry3": true, # "entry4": false, # "entry5": false, # "entry6": true, # "entry7": false, # "entry8": false, # "entry9": true, # "entry_change": 1.5, # "entry_offset1": 0.98, # "entry_offset2": 0.94, # "from_bear": -12.4, # "from_bull": -3.1, # "from_down": -7.1, # "from_ranging": -2.7, # "from_up": -2.0, # "max_length": 48, # "ref_bear": -0.088, # "ref_bull": 0.087, # "ref_down": -0.075, # "ref_up": 0.062, # "reference_ma_length": 187, # "smooth_bear": -0.098, # "smooth_bull": 0.085, # "smooth_down": -0.058, # "smooth_up": 0.052, # "smoothing_length": 15 # }, # "exit": { # "filterlength": 40, # "exit_change": 1.5, # "exit_offset1": 1.04, # "exit_slope": 0.01, # "ts0": 0.008, # "ts1": 0.01, # "ts2": 0.018, # "ts3": 0.031, # "ts4": 0.05, # "ts5": 0.04, # "tsl_target0": 0.041, # "tsl_target1": 0.079, # "tsl_target2": 0.099, # "tsl_target3": 0.14, # "tsl_target4": 0.17, # "tsl_target5": 0.3 # }, # "protection": { # "cooldown_lookback": 48, # "lowprofit_only_per_pair": true, # "lowprofit_protection_lookback": 5, # "lowprofit_required_profit": -0.704, # "lowprofit_stop_duration": 100, # "lowprofit_trade_limit": 2, # "maxdrawdown_allowed_drawdown": 0.045, # "maxdrawdown_protection_lookback": 3, # "maxdrawdown_stop_duration": 15, # "maxdrawdown_trade_limit": 5, # "stop_duration": 19, # "stop_protection_only_per_pair": true, # "stop_protection_only_per_side": true, # "stop_protection_required_profit": -0.126, # "stop_protection_trade_limit": 9, # "use_lowprofit_protection": true, # "use_maxdrawdown_protection": false, # "use_stop_protection": false # } # }, # "ft_stratparam_v": 1, # "export_time": "2023-05-02 22:49:05.899725+00:00" # } # Best result: # 1425/1500: 365 trades. 318/20/27 Wins/Draws/Losses. Avg profit 2.60%. Median profit 3.93%. Total profit 3495.92254012 USDT ( 349.59%). Avg duration 1 day, 18:44:00 min. Objective: -3495.92254 # # Buy hyperspace params: # entry_params = { # "entry01": True, # "entry02": False, # "entry03": True, # "entry04": True, # "entry05": True, # "entry06": False, # "entry07": True, # "entry08": True, # "entry09": False, # "entry10": False, # "entry11": False, # "entry12": False, # "entry13": False, # "entry14": False, # "entry15": False, # "entry16": False, # "entry17": False, # "entry18": False, # "entry19": False, # "entry20": False, # "entry21": True, # "entry22": True, # "entry23": True, # "entry24": True, # "entry25": True, # "entry26": False, # "entry27": False, # "entry28": False, # "entry29": True, # "entry30": False, # "entry_change": 1.2, # "entry_offset1": 0.99, # "entry_offset2": 0.92, # "from_bear": -10.5, # "from_bull": -3.1, # "from_down": -6.3, # "from_ranging": -2.5, # "from_up": -2.2, # "max_length": 192, # "ref_bear": -0.097, # "ref_bull": 0.095, # "ref_down": -0.07, # "ref_up": 0.043, # "reference_ma_length": 191, # "smooth_bear": -0.095, # "smooth_bull": 0.076, # "smooth_down": -0.056, # "smooth_up": 0.04, # "smoothing_length": 23, # } # # Sell hyperspace params: # exit_params = { # "filterlength": 30, # "exit01": False, # "exit02": True, # "exit03": True, # "exit04": True, # "exit05": False, # "exit06": False, # "exit07": True, # "exit08": True, # "exit09": False, # "exit10": True, # "exit_change": 1.7, # "exit_offset1": 1.04, # "exit_slope": 0.0, # "ts0": 0.008, # "ts1": 0.01, # "ts2": 0.022, # "ts3": 0.038, # "ts4": 0.03, # "ts5": 0.04, # "tsl_target0": 0.044, # "tsl_target1": 0.065, # "tsl_target2": 0.097, # "tsl_target3": 0.12, # "tsl_target4": 0.16, # "tsl_target5": 0.3, # } # # Protection hyperspace params: # protection_params = { # "cooldown_lookback": 48, # value loaded from strategy # "lowprofit_only_per_pair": True, # value loaded from strategy # "lowprofit_protection_lookback": 5, # value loaded from strategy # "lowprofit_required_profit": -0.704, # value loaded from strategy # "lowprofit_stop_duration": 100, # value loaded from strategy # "lowprofit_trade_limit": 2, # value loaded from strategy # "maxdrawdown_allowed_drawdown": 0.045, # value loaded from strategy # "maxdrawdown_protection_lookback": 3, # value loaded from strategy # "maxdrawdown_stop_duration": 15, # value loaded from strategy # "maxdrawdown_trade_limit": 5, # value loaded from strategy # "stop_duration": 19, # value loaded from strategy # "stop_protection_only_per_pair": True, # value loaded from strategy # "stop_protection_only_per_side": True, # value loaded from strategy # "stop_protection_required_profit": -0.126, # value loaded from strategy # "stop_protection_trade_limit": 9, # value loaded from strategy # "use_lowprofit_protection": True, # value loaded from strategy # "use_maxdrawdown_protection": False, # value loaded from strategy # "use_stop_protection": False, # value loaded from strategy # } # # ROI table: # value loaded from strategy # minimal_roi = { # "0": 0.143, # "736": 0.099, # "2369": 0.024, # "5731": 0 # } # # Stoploss: # stoploss = -0.28 # value loaded from strategy # # Trailing stop: # trailing_stop = True # value loaded from strategy # trailing_stop_positive = None # value loaded from strategy # trailing_stop_positive_offset = 0.0 # value loaded from strategy # trailing_only_offset_is_reached = False # value loaded from strategy # # Max Open Trades: # max_open_trades = 6 # value loaded from strategy # Result for strategy CTIBS # ============================================================= BACKTESTING REPORT ============================================================= # | Pair | Entries | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% | # |------------+-----------+----------------+----------------+-------------------+----------------+------------------+-------------------------| # | OPUL/USDT | 30 | 4.64 | 139.20 | 708.395 | 70.84 | 14:03:00 | 28 1 1 93.3 | # | AGIX/USDT | 37 | 3.02 | 111.78 | 342.690 | 34.27 | 14:09:00 | 32 0 5 86.5 | # | INJ/USDT | 21 | 2.79 | 58.60 | 332.616 | 33.26 | 1 day, 16:47:00 | 18 1 2 85.7 | # | LDO/USDT | 20 | 5.12 | 102.36 | 302.659 | 30.27 | 23:04:00 | 19 1 0 100 | # | RNDR/USDT | 23 | 2.46 | 56.48 | 292.762 | 29.28 | 1 day, 1:40:00 | 22 0 1 95.7 | # | OP/USDT | 11 | 4.43 | 48.75 | 225.127 | 22.51 | 10:14:00 | 11 0 0 100 | # | IMX/USDT | 18 | 2.33 | 41.89 | 218.038 | 21.80 | 1 day, 13:00:00 | 17 0 1 94.4 | # | ORAI/USDT | 19 | 2.63 | 49.93 | 156.959 | 15.70 | 14:02:00 | 18 0 1 94.7 | # | APT/USDT | 10 | 4.28 | 42.77 | 144.811 | 14.48 | 1 day, 1:15:00 | 10 0 0 100 | # | KLAY/USDT | 6 | 3.28 | 19.71 | 132.670 | 13.27 | 1 day, 12:40:00 | 4 1 1 66.7 | # | DYDX/USDT | 16 | 2.16 | 34.52 | 125.692 | 12.57 | 2 days, 13:57:00 | 14 1 1 87.5 | # | FIL/USDT | 6 | 4.08 | 24.47 | 125.056 | 12.51 | 20:08:00 | 6 0 0 100 | # | ARB/USDT | 5 | 3.15 | 15.75 | 112.833 | 11.28 | 3 days, 16:30:00 | 4 1 0 100 | # | CSPR/USDT | 7 | 2.80 | 19.58 | 108.527 | 10.85 | 1 day, 7:24:00 | 7 0 0 100 | # | ROSE/USDT | 4 | 4.21 | 16.85 | 106.125 | 10.61 | 18:41:00 | 4 0 0 100 | # | FLR/USDT | 4 | 5.50 | 21.98 | 99.699 | 9.97 | 15:41:00 | 4 0 0 100 | # | GRT/USDT | 5 | 3.21 | 16.05 | 96.898 | 9.69 | 1 day, 0:21:00 | 5 0 0 100 | # | GALAX/USDT | 8 | 5.04 | 40.31 | 84.824 | 8.48 | 8:26:00 | 7 0 1 87.5 | # | HBAR/USDT | 6 | 2.17 | 13.02 | 80.588 | 8.06 | 9 days, 16:55:00 | 3 3 0 100 | # | JASMY/USDT | 11 | 2.85 | 31.36 | 78.855 | 7.89 | 2 days, 1:59:00 | 9 0 2 81.8 | # | CRO/USDT | 1 | 8.57 | 8.57 | 67.589 | 6.76 | 16:30:00 | 1 0 0 100 | # | EWT/USDT | 5 | 2.53 | 12.67 | 64.415 | 6.44 | 1 day, 3:06:00 | 5 0 0 100 | # | FET/USDT | 2 | 3.41 | 6.83 | 49.115 | 4.91 | 1 day, 2:38:00 | 2 0 0 100 | # | XRP/USDT | 2 | 3.26 | 6.53 | 41.612 | 4.16 | 17:22:00 | 2 0 0 100 | # | SAND/USDT | 3 | 4.62 | 13.86 | 38.537 | 3.85 | 12:20:00 | 3 0 0 100 | # | NEAR/USDT | 4 | 2.51 | 10.03 | 36.898 | 3.69 | 1 day, 3:08:00 | 4 0 0 100 | # | XLM/USDT | 2 | 3.03 | 6.07 | 28.982 | 2.90 | 16:08:00 | 2 0 0 100 | # | TRX/USDT | 2 | 4.11 | 8.23 | 27.729 | 2.77 | 12:08:00 | 2 0 0 100 | # | KAVA/USDT | 2 | 4.18 | 8.36 | 27.547 | 2.75 | 1 day, 1:38:00 | 2 0 0 100 | # | SOL/USDT | 7 | 1.90 | 13.32 | 27.384 | 2.74 | 2 days, 6:04:00 | 4 3 0 100 | # | QNT/USDT | 2 | 2.24 | 4.48 | 25.599 | 2.56 | 2 days, 8:00:00 | 2 0 0 100 | # | APE/USDT | 3 | 3.18 | 9.54 | 24.531 | 2.45 | 13:15:00 | 3 0 0 100 | # | ETC/USDT | 2 | 4.58 | 9.16 | 16.738 | 1.67 | 22:45:00 | 2 0 0 100 | # | ENJ/USDT | 2 | 2.21 | 4.42 | 14.311 | 1.43 | 2 days, 2:22:00 | 1 1 0 100 | # | BTC/USDT | 1 | 2.40 | 2.40 | 14.117 | 1.41 | 2 days, 6:45:00 | 1 0 0 100 | # | ZEC/USDT | 1 | 2.40 | 2.40 | 11.422 | 1.14 | 2 days, 8:00:00 | 1 0 0 100 | # | CRV/USDT | 3 | 1.03 | 3.09 | 10.368 | 1.04 | 2 days, 20:15:00 | 2 1 0 100 | # | ATOM/USDT | 3 | 0.65 | 1.94 | 8.839 | 0.88 | 3 days, 12:30:00 | 2 1 0 100 | # | XTZ/USDT | 1 | 1.79 | 1.79 | 8.540 | 0.85 | 2 days, 22:30:00 | 1 0 0 100 | # | KSM/USDT | 1 | 2.40 | 2.40 | 8.217 | 0.82 | 2 days, 14:15:00 | 1 0 0 100 | # | AVAX/USDT | 3 | 0.90 | 2.71 | 8.148 | 0.81 | 6 days, 15:15:00 | 2 1 0 100 | # | SCRT/USDT | 1 | 2.40 | 2.40 | 5.970 | 0.60 | 1 day, 21:45:00 | 1 0 0 100 | # | THETA/USDT | 2 | 0.65 | 1.29 | 4.826 | 0.48 | 9 days, 15:52:00 | 1 1 0 100 | # | IOTA/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 | # | OSMO/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 | # | ETH/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 | # | XDC/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 | # | LINK/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 | # | DOT/USDT | 1 | 0.00 | 0.00 | 0.000 | 0.00 | 6 days, 8:00:00 | 0 1 0 0 | # | UNI/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 | # | VET/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 | # | EOS/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 | # | DASH/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 | # | OCEAN/USDT | 12 | 1.49 | 17.92 | -8.904 | -0.89 | 2 days, 18:38:00 | 10 1 1 83.3 | # | DOGE/USDT | 2 | -1.34 | -2.68 | -21.435 | -2.14 | 12 days, 9:15:00 | 1 0 1 50.0 | # | ADA/USDT | 2 | -1.69 | -3.39 | -28.639 | -2.86 | 5 days, 17:38:00 | 1 0 1 50.0 | # | EGLD/USDT | 2 | -2.38 | -4.76 | -47.439 | -4.74 | 1 day, 2:45:00 | 1 0 1 50.0 | # | AKT/USDT | 7 | -1.86 | -13.02 | -113.644 | -11.36 | 2 days, 7:26:00 | 6 0 1 85.7 | # | LUNC/USDT | 2 | -12.83 | -25.66 | -140.852 | -14.09 | 17 days, 5:38:00 | 0 1 1 0 | # | MATIC/USDT | 3 | -6.91 | -20.73 | -158.044 | -15.80 | 5 days, 14:05:00 | 2 0 1 66.7 | # | ALGO/USDT | 2 | -12.97 | -25.95 | -182.961 | -18.30 | 8 days, 4:00:00 | 1 0 1 50.0 | # | ANKR/USDT | 10 | -2.20 | -21.96 | -249.415 | -24.94 | 1 day, 19:15:00 | 7 0 3 70.0 | # | TOTAL | 365 | 2.60 | 947.62 | 3495.923 | 349.59 | 1 day, 18:44:00 | 318 20 27 87.1 | # =========================================================== LEFT OPEN TRADES REPORT =========================================================== # | Pair | Entries | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% | # |------------+-----------+----------------+----------------+-------------------+----------------+-------------------+-------------------------| # | INJ/USDT | 1 | -1.17 | -1.17 | -9.476 | -0.95 | 4:30:00 | 0 0 1 0 | # | ADA/USDT | 1 | -4.28 | -4.28 | -32.818 | -3.28 | 10 days, 12:15:00 | 0 0 1 0 | # | JASMY/USDT | 1 | -5.83 | -5.83 | -42.769 | -4.28 | 13 days, 20:45:00 | 0 0 1 0 | # | EGLD/USDT | 1 | -9.01 | -9.01 | -73.187 | -7.32 | 1 day, 19:15:00 | 0 0 1 0 | # | DOGE/USDT | 1 | -16.97 | -16.97 | -116.795 | -11.68 | 24 days, 18:15:00 | 0 0 1 0 | # | AKT/USDT | 1 | -19.49 | -19.49 | -148.353 | -14.84 | 11 days, 4:30:00 | 0 0 1 0 | # | TOTAL | 6 | -9.46 | -56.73 | -423.397 | -42.34 | 10 days, 9:15:00 | 0 0 6 0 | # ============================================================================ ENTER TAG STATS ============================================================================ # | TAG | Entries | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% | # |---------------------------------------+-----------+----------------+----------------+-------------------+----------------+------------------+-------------------------| # | 8 Smooth Range - Ref Up | 71 | 3.87 | 275.08 | 1176.933 | 117.69 | 1 day, 10:28:00 | 66 4 1 93.0 | # | 1 Smooth Bull - Ref Bull | 62 | 3.90 | 241.71 | 1018.094 | 101.81 | 1 day, 3:00:00 | 57 2 3 91.9 | # | 3 Smooth Range - Ref Bull | 126 | 2.14 | 269.55 | 773.706 | 77.37 | 1 day, 13:27:00 | 107 6 13 84.9 | # | 29 XO above entry_offset3 | Down - Bear | 77 | 1.05 | 80.76 | 252.870 | 25.29 | 2 days, 19:45:00 | 64 6 7 83.1 | # | 7 Smooth Up - Ref Up | 27 | 2.81 | 75.83 | 246.711 | 24.67 | 2 days, 8:07:00 | 22 2 3 81.5 | # | 22 Smooth Bull - Ref Bear | 1 | 3.81 | 3.81 | 23.052 | 2.31 | 21:30:00 | 1 0 0 100 | # | 4Smooth Down - Ref Bull | 1 | 0.87 | 0.87 | 4.556 | 0.46 | 0:15:00 | 1 0 0 100 | # | TOTAL | 365 | 2.60 | 947.62 | 3495.923 | 349.59 | 1 day, 18:44:00 | 318 20 27 87.1 | # ======================================================= EXIT REASON STATS ======================================================== # | Exit Reason | Exits | Win Draws Loss Win% | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | # |--------------------+---------+--------------------------+----------------+----------------+-------------------+----------------| # | trailing_stop_loss | 249 | 228 0 21 91.6 | 3.09 | 770.24 | 2813.35 | 128.37 | # | roi | 74 | 54 20 0 100 | 2.71 | 200.51 | 922.846 | 33.42 | # | Pivot - XO | 21 | 21 0 0 100 | 0.8 | 16.75 | 99.357 | 2.79 | # | R2.5 - XO | 8 | 8 0 0 100 | 1.3 | 10.37 | 54.745 | 1.73 | # | force_exit | 6 | 0 0 6 0 | -9.46 | -56.73 | -423.397 | -9.46 | # | R2.75 - XO | 4 | 4 0 0 100 | 1 | 4.01 | 17.628 | 0.67 | # | R3 - XO | 3 | 3 0 0 100 | 0.82 | 2.47 | 11.393 | 0.41 | # ================== SUMMARY METRICS ================== # | Metric | Value | # |-----------------------------+---------------------| # | Backtesting from | 2023-01-01 00:00:00 | # | Backtesting to | 2023-04-30 00:00:00 | # | Max open trades | 6 | # | | | # | Total/Daily Avg Trades | 365 / 3.07 | # | Starting balance | 1000 USDT | # | Final balance | 4495.923 USDT | # | Absolute profit | 3495.923 USDT | # | Total profit % | 349.59% | # | CAGR % | 9954.11% | # | Sortino | 7.32 | # | Sharpe | 14.53 | # | Calmar | 185.66 | # | Profit factor | 2.33 | # | Expectancy | 0.04 | # | Trades per day | 3.07 | # | Avg. daily profit % | 2.94% | # | Avg. stake amount | 486.735 USDT | # | Total trade volume | 177658.245 USDT | # | | | # | Best Pair | OPUL/USDT 139.20% | # | Worst Pair | ALGO/USDT -25.95% | # | Best trade | LDO/USDT 14.29% | # | Worst trade | MATIC/USDT -27.97% | # | Best day | 316.573 USDT | # | Worst day | -423.397 USDT | # | Days win/draw/lose | 87 / 23 / 9 | # | Avg. Duration Winners | 18:38:00 | # | Avg. Duration Loser | 6 days, 21:24:00 | # | Rejected Entry signals | 455976 | # | Entry/Exit Timeouts | 0 / 0 | # | | | # | Min balance | 1001.773 USDT | # | Max balance | 4919.32 USDT | # | Max % of account underwater | 30.23% | # | Absolute Drawdown (Account) | 30.23% | # | Absolute Drawdown | 1316.127 USDT | # | Drawdown high | 3353.592 USDT | # | Drawdown low | 2037.465 USDT | # | Drawdown Start | 2023-02-23 01:45:00 | # | Drawdown End | 2023-03-10 10:00:00 | # | Market change | 84.63% | # =====================================================