┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┓
┃ Strategy ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDC ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃ Drawdown ┃ ┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━┩ │ Empty │ 45 │ 3.05 │ 903.533 │ 90.35 │ 15 days, 1:43:00 │ 44 0 1 97.8 │ 1300.8 USDC 40.60% │ └──────────┴────────┴──────────────┴─────────────────┴──────────────┴──────────────────┴────────────────────────┴─────────────────────┘
This commit is contained in:
38
Empty.json
38
Empty.json
@@ -4,6 +4,15 @@
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": null,
|
||||
"trailing_stop_positive_offset": 0.0,
|
||||
"trailing_only_offset_is_reached": false
|
||||
},
|
||||
"max_open_trades": {
|
||||
"max_open_trades": 20
|
||||
},
|
||||
@@ -21,30 +30,15 @@
|
||||
"buy_real_num1": 1.0,
|
||||
"buy_real_num2": -0.4
|
||||
},
|
||||
"protection": {
|
||||
"stop_buying_indicator": "stop_buying12_1d",
|
||||
"stoploss_indicator": "stop_buying12_1d",
|
||||
"stoploss_timeperiod": "12"
|
||||
},
|
||||
"sell": {
|
||||
"sell_crossed_indicator0": "sma24_deriv2",
|
||||
"sell_crossed_indicator1": "sma48_score",
|
||||
"sell_crossed_indicator2": "sma24_score",
|
||||
"sell_indicator0": "sma5_deriv2",
|
||||
"sell_indicator1": "sma60_score",
|
||||
"sell_indicator2": "sma60_score",
|
||||
"sell_operator0": "<",
|
||||
"sell_operator1": ">",
|
||||
"sell_operator2": "CB",
|
||||
"sell_real_num0": 0.7,
|
||||
"sell_real_num1": 0.5,
|
||||
"sell_real_num2": 0.9
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.055,
|
||||
"trailing_stop_positive_offset": 0.106,
|
||||
"trailing_only_offset_is_reached": false
|
||||
"sell_score_indicator": "sma48_score"
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2026-02-19 19:14:20.539321+00:00"
|
||||
"export_time": "2026-02-20 20:19:59.741160+00:00"
|
||||
}
|
||||
466
Empty.py
466
Empty.py
@@ -25,6 +25,8 @@ from random import shuffle
|
||||
|
||||
timeperiods = [3, 5, 12, 24, 48, 60]
|
||||
|
||||
score_indicators = list()
|
||||
stoploss_indicators = list()
|
||||
god_genes_with_timeperiod = list()
|
||||
for timeperiod in timeperiods:
|
||||
# god_genes_with_timeperiod.append(f'max{timeperiod}')
|
||||
@@ -34,11 +36,20 @@ for timeperiod in timeperiods:
|
||||
god_genes_with_timeperiod.append(f"sma{timeperiod}_deriv1")
|
||||
god_genes_with_timeperiod.append(f"sma{timeperiod}_deriv2")
|
||||
god_genes_with_timeperiod.append(f"sma{timeperiod}_score")
|
||||
|
||||
# stoploss_indicators.append(f"stop_buying{timeperiod}")
|
||||
stoploss_indicators.append(f"stop_buying{timeperiod}_1d")
|
||||
|
||||
score_indicators.append(f"sma{timeperiod}_score")
|
||||
# score_indicators.append(f"sma{timeperiod}_score_1d")
|
||||
|
||||
# god_genes_with_timeperiod.append(f"sma{timeperiod}_trend_up")
|
||||
# god_genes_with_timeperiod.append(f"sma{timeperiod}_trend_down")
|
||||
# god_genes_with_timeperiod.append(f"sma{timeperiod}_trend_change_up")
|
||||
# god_genes_with_timeperiod.append(f"sma{timeperiod}_trend_change_down")
|
||||
|
||||
print(stoploss_indicators)
|
||||
|
||||
operators = [
|
||||
"D", # Disabled gene
|
||||
">", # Indicator, bigger than cross indicator
|
||||
@@ -249,14 +260,13 @@ class Empty(IStrategy):
|
||||
|
||||
# Stoploss:
|
||||
stoploss = -1
|
||||
trailing_stop = True
|
||||
trailing_stop_positive = 0.15
|
||||
trailing_stop_positive_offset = 0.20
|
||||
trailing_only_offset_is_reached = True
|
||||
trailing_stop = False
|
||||
# trailing_stop_positive = 0.15
|
||||
# trailing_stop_positive_offset = 0.20
|
||||
# trailing_only_offset_is_reached = False
|
||||
|
||||
position_adjustment_enable = True
|
||||
use_custom_stoploss = True
|
||||
|
||||
use_custom_stoploss = False
|
||||
|
||||
#max_open_trades = 3
|
||||
|
||||
@@ -295,6 +305,7 @@ class Empty(IStrategy):
|
||||
'last_date': 0,
|
||||
'stop': False,
|
||||
'max_profit': 0,
|
||||
'last_profit': 0,
|
||||
'total_amount': 0,
|
||||
'has_gain': 0,
|
||||
'force_sell': False,
|
||||
@@ -356,22 +367,27 @@ class Empty(IStrategy):
|
||||
buy_real_num2 = DecimalParameter(-1, 1, decimals=DECIMALS, default=0, space='buy')
|
||||
|
||||
# Sell Hyperoptable Parameters/Spaces.
|
||||
sell_crossed_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="CDLSHOOTINGSTAR-150", space='sell')
|
||||
sell_crossed_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="MAMA-1-100", space='sell')
|
||||
sell_crossed_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLMATHOLD-6", space='sell')
|
||||
# sell_crossed_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="CDLSHOOTINGSTAR-150", space='sell')
|
||||
# sell_crossed_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="MAMA-1-100", space='sell')
|
||||
# sell_crossed_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLMATHOLD-6", space='sell')
|
||||
#
|
||||
# sell_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="CDLUPSIDEGAP2CROWS-5", space='sell')
|
||||
# sell_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="CDLHARAMICROSS-150", space='sell')
|
||||
# sell_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDL2CROWS-5", space='sell')
|
||||
#
|
||||
# sell_operator0 = CategoricalParameter(operators, default="<R", space='sell')
|
||||
# sell_operator1 = CategoricalParameter(operators, default="D", space='sell')
|
||||
# sell_operator2 = CategoricalParameter(operators, default="/>R", space='sell')
|
||||
#
|
||||
# sell_real_num0 = DecimalParameter(-1, 1, decimals=DECIMALS, default=0, space='sell')
|
||||
# sell_real_num1 = DecimalParameter(-1, 1, decimals=DECIMALS, default=0, space='sell')
|
||||
# sell_real_num2 = DecimalParameter(-1, 1, decimals=DECIMALS, default=0, space='sell')
|
||||
|
||||
sell_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="CDLUPSIDEGAP2CROWS-5", space='sell')
|
||||
sell_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="CDLHARAMICROSS-150", space='sell')
|
||||
sell_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDL2CROWS-5", space='sell')
|
||||
|
||||
sell_operator0 = CategoricalParameter(operators, default="<R", space='sell')
|
||||
sell_operator1 = CategoricalParameter(operators, default="D", space='sell')
|
||||
sell_operator2 = CategoricalParameter(operators, default="/>R", space='sell')
|
||||
|
||||
sell_real_num0 = DecimalParameter(-1, 1, decimals=DECIMALS, default=0, space='sell')
|
||||
sell_real_num1 = DecimalParameter(-1, 1, decimals=DECIMALS, default=0, space='sell')
|
||||
sell_real_num2 = DecimalParameter(-1, 1, decimals=DECIMALS, default=0, space='sell')
|
||||
sell_score_indicator = CategoricalParameter(score_indicators, default="sma24_score", space='sell')
|
||||
|
||||
stoploss_indicator = CategoricalParameter(stoploss_indicators, default="stop_buying12_1d", space='protection')
|
||||
stop_buying_indicator = CategoricalParameter(stoploss_indicators, default="stop_buying12_1d", space='protection')
|
||||
stoploss_timeperiod = CategoricalParameter(timeperiods, default="12", space='protection')
|
||||
|
||||
def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float,
|
||||
proposed_stake: float, min_stake: float, max_stake: float,
|
||||
@@ -384,7 +400,21 @@ class Empty(IStrategy):
|
||||
if (self.pairs[pair]['first_amount'] > 0):
|
||||
amount = min(self.wallets.get_available_stake_amount(), self.pairs[pair]['first_amount'])
|
||||
else:
|
||||
amount = self.wallets.get_available_stake_amount() / 4
|
||||
# range_min = last_candle[f"min{self.stoploss_timeperiod.value}_1d"]
|
||||
# range_max = last_candle[f"max{self.stoploss_timeperiod.value}_1d"]
|
||||
#
|
||||
# if range_max == range_min:
|
||||
# return -0.1 # sécurité
|
||||
#
|
||||
# range_pos = (last_candle['close'] - range_min) / (range_max - range_min)
|
||||
|
||||
range_pos = last_candle[f"range_pos"]
|
||||
sl_min = self.wallets.get_available_stake_amount() / 2
|
||||
sl_max = self.wallets.get_available_stake_amount() / 6
|
||||
|
||||
amount = sl_min + (1 - range_pos) * (sl_max - sl_min)
|
||||
# amount = self.wallets.get_available_stake_amount() / 8
|
||||
|
||||
return min(amount, self.wallets.get_available_stake_amount())
|
||||
|
||||
def adjust_trade_position(self, trade: Trade, current_time: datetime,
|
||||
@@ -442,7 +472,7 @@ class Empty(IStrategy):
|
||||
|
||||
drop_from_last_entry = (current_rate - last_entry_price) / last_entry_price
|
||||
|
||||
if drop_from_last_entry <= -0.05:
|
||||
if drop_from_last_entry <= -0.025 and last_candle['min60'] == last_candle_3['min60']:
|
||||
# stake_amount = trade.stake_amount
|
||||
print(f"adjust {current_time} {stake_amount}")
|
||||
print(f"adjust {pair} {current_time} dispo={dispo} amount={stake_amount} rate={current_rate}")
|
||||
@@ -462,7 +492,19 @@ class Empty(IStrategy):
|
||||
last_candle_2 = dataframe.iloc[-2].squeeze()
|
||||
last_candle_3 = dataframe.iloc[-3].squeeze()
|
||||
|
||||
condition = True #(last_candle[f"{indic_5m}_deriv1"] >= indic_deriv1_5m) and (last_candle[f"{indic_5m}_deriv2"] >= indic_deriv2_5m)
|
||||
condition = True
|
||||
|
||||
if self.pairs[pair]['last_trade'] and self.pairs[pair]['last_trade'].close_date:
|
||||
# base cooldown = n bougies / cooldown proportionnel au profit
|
||||
# bougies de plus par %
|
||||
cooldown_candles = 12 + 6 * (int(self.pairs[pair]['last_profit'] / 0.01)) # réglable
|
||||
|
||||
# temps depuis la fermeture
|
||||
candles_since_close = ((current_time - self.pairs[pair]['last_trade'].close_date).total_seconds() / 3600) # seconds / heure
|
||||
|
||||
condition = (candles_since_close >= cooldown_candles)
|
||||
|
||||
print(f"Cool down {round(self.pairs[pair]['last_profit'], 3)} {cooldown_candles} {candles_since_close}")
|
||||
|
||||
# self.should_enter_trade(pair, last_candle, current_time)
|
||||
allow_to_buy = (condition and not self.pairs[pair]['stop']) | (entry_tag == 'force_entry')
|
||||
@@ -482,6 +524,8 @@ class Empty(IStrategy):
|
||||
self.pairs[pair]['last_candle'] = last_candle
|
||||
self.pairs[pair]['count_of_buys'] = 1
|
||||
self.pairs[pair]['current_profit'] = 0
|
||||
self.pairs[pair]['last_profit'] = 0
|
||||
self.pairs[pair]['last_trade'] = None
|
||||
self.pairs[pair]['last_max'] = max(last_candle['close'], self.pairs[pair]['last_max'])
|
||||
self.pairs[pair]['last_min'] = min(last_candle['close'], self.pairs[pair]['last_min'])
|
||||
self.pairs[pair]['last_date'] = current_time
|
||||
@@ -492,7 +536,7 @@ class Empty(IStrategy):
|
||||
stake_amount = self.adjust_stake_amount(pair, last_candle)
|
||||
self.pairs[pair]['first_amount'] = stake_amount
|
||||
self.pairs[pair]['total_amount'] = stake_amount
|
||||
print(f"Buy {pair} {current_time} {entry_tag} dispo={dispo} amount={amount} rate={rate} rate={rate}")
|
||||
print(f"Buy {pair} {current_time} {entry_tag} dispo={dispo} amount={stake_amount} rate={rate} rate={rate}")
|
||||
|
||||
# self.log_trade(
|
||||
# last_candle=last_candle,
|
||||
@@ -519,7 +563,7 @@ class Empty(IStrategy):
|
||||
|
||||
profit = trade.calc_profit(rate)
|
||||
force = self.pairs[pair]['force_sell']
|
||||
allow_to_sell = (last_candle['hapercent'] < 0 and profit > 0) or force or (exit_reason == 'force_exit') or (exit_reason == 'stop_loss')
|
||||
allow_to_sell = (last_candle['hapercent'] < 0 and profit > 0) or force or (exit_reason == 'force_exit') or (exit_reason == 'stop_loss') or (exit_reason == 'trailing_stop_loss')
|
||||
|
||||
minutes = int(round((current_time - trade.date_last_filled_utc).total_seconds() / 60, 0))
|
||||
|
||||
@@ -530,7 +574,7 @@ class Empty(IStrategy):
|
||||
profit = trade.calc_profit(rate)
|
||||
self.pairs[pair]['previous_profit'] = profit
|
||||
dispo = round(self.wallets.get_available_stake_amount())
|
||||
print(f"Sell {pair} {current_time} {exit_reason} dispo={dispo} amount={amount} rate={rate} open_rate={trade.open_rate} profit={profit}")
|
||||
print(f"Sell {pair} {current_time} {exit_reason} dispo={dispo} rate={rate} open_rate={trade.open_rate} profit={profit}")
|
||||
# self.log_trade(
|
||||
# last_candle=last_candle,
|
||||
# date=current_time,
|
||||
@@ -541,6 +585,7 @@ class Empty(IStrategy):
|
||||
# dispo=dispo,
|
||||
# profit=round(profit, 2)
|
||||
# )
|
||||
self.pairs[pair]['first_amount'] = 0
|
||||
self.pairs[pair]['force_sell'] = False
|
||||
self.pairs[pair]['has_gain'] = 0
|
||||
self.pairs[pair]['current_profit'] = 0
|
||||
@@ -551,42 +596,71 @@ class Empty(IStrategy):
|
||||
self.pairs[pair]['last_date'] = current_time
|
||||
self.pairs[pair]['last_trade'] = self.pairs[pair]['current_trade']
|
||||
self.pairs[pair]['current_trade'] = None
|
||||
# else:
|
||||
# print(f"STOP triggered for {pair} ({exit_reason}) but condition blocked", "warning")
|
||||
else:
|
||||
print(f"{current_time} STOP triggered for {pair} ({exit_reason}) but condition blocked", "warning")
|
||||
return (allow_to_sell) | (exit_reason == 'force_exit') | (exit_reason == 'stop_loss') | force
|
||||
|
||||
def custom_exit(self, pair, trade, current_time,
|
||||
current_rate, current_profit, **kwargs):
|
||||
def custom_exit(self, pair, trade, current_time, current_rate, current_profit, **kwargs):
|
||||
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
last_row = dataframe.iloc[-1]
|
||||
last_candle = dataframe.iloc[-1]
|
||||
before_last_candle = dataframe.iloc[-2]
|
||||
self.pairs[pair]['current_trade'] = trade
|
||||
momentum = last_row["sma24_score"]
|
||||
momentum = last_candle[self.sell_score_indicator.value]
|
||||
|
||||
# Si momentum fort → on laisse courir
|
||||
if momentum > 1:
|
||||
return None
|
||||
|
||||
# Si momentum faiblit → on prend profit plus tôt
|
||||
if momentum < 0 and current_profit > 0.02:
|
||||
if momentum < 0 and current_profit > 0.02 and last_candle[self.sell_score_indicator.value] < before_last_candle[self.sell_score_indicator.value]\
|
||||
and last_candle['close'] < last_candle['sma5']:
|
||||
self.pairs[pair]['last_profit'] = current_profit
|
||||
return "momentum_drop"
|
||||
|
||||
return None
|
||||
|
||||
def custom_stoploss(self, pair, trade, current_time,
|
||||
current_rate, current_profit, **kwargs):
|
||||
|
||||
if current_profit < - 0.1 and self.wallets.get_available_stake_amount():
|
||||
return -0.1
|
||||
|
||||
return -1
|
||||
# def custom_stoploss(self, pair, trade, current_time, current_rate, current_profit, **kwargs):
|
||||
# dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
# last_candle = dataframe.iloc[-1]
|
||||
# profit = trade.calc_profit(current_rate)
|
||||
#
|
||||
# # print(f'test stop loss {self.stoploss} {last_candle["stop_buying12_1d"]}')
|
||||
# if last_candle[self.stoploss_indicator.value] and (trade.nr_of_successful_entries >= 4 or self.wallets.get_available_stake_amount() < 300): # and profit < - 30 :
|
||||
# range_min = last_candle[f"min{self.stoploss_timeperiod.value}_1d"]
|
||||
# range_max = last_candle[f"max{self.stoploss_timeperiod.value}_1d"]
|
||||
#
|
||||
# if range_max == range_min:
|
||||
# print(f'ranges={range_min}')
|
||||
# return -0.1 # sécurité
|
||||
#
|
||||
# range_pos = (current_rate - range_min) / (range_max - range_min)
|
||||
#
|
||||
# if (range_pos > 1):
|
||||
# return -1
|
||||
#
|
||||
# sl_min = -0.02
|
||||
# sl_max = -0.1 #self.stoploss
|
||||
#
|
||||
# dynamic_sl = (sl_min + (1 - range_pos) * (sl_max - sl_min))
|
||||
#
|
||||
# print(f'{current_time} Loss ranges={round(range_min,0)} {round(range_max, 0)} range_pos={round(range_pos, 3)} dynamic_sl={round(dynamic_sl, 3)} '
|
||||
# f'profit={profit} current={current_profit} {self.stoploss_indicator.value} {self.stoploss_timeperiod.value} {last_candle[self.stoploss_indicator.value]}')
|
||||
#
|
||||
# return dynamic_sl
|
||||
#
|
||||
# return -1
|
||||
|
||||
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, '1h') for pair in pairs]
|
||||
|
||||
return []
|
||||
return informative_pairs
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
pair = metadata['pair']
|
||||
dataframe = dataframe.copy()
|
||||
heikinashi = qtpylib.heikinashi(dataframe)
|
||||
dataframe['haopen'] = heikinashi['open']
|
||||
@@ -602,19 +676,64 @@ class Empty(IStrategy):
|
||||
dataframe[f"sma{timeperiod}"] = dataframe['mid'].ewm(span=timeperiod, adjust=False).mean()
|
||||
self.calculeDerivees(dataframe, f"sma{timeperiod}", timeframe=self.timeframe, ema_period=timeperiod)
|
||||
|
||||
# ######################################################################################################
|
||||
dataframe['stop_buying_deb'] = (dataframe['sma60_trend_change_down'] == 1)
|
||||
dataframe['stop_buying_end'] = (dataframe['sma60_trend_change_up'] == 1)
|
||||
latched = np.zeros(len(dataframe), dtype=bool)
|
||||
dataframe[f'stop_buying{timeperiod}_deb'] = (dataframe[f'sma{timeperiod}_trend_change_down'] == 1)
|
||||
dataframe[f'stop_buying{timeperiod}_end'] = (dataframe[f'sma{timeperiod}_trend_change_up'] == 1)
|
||||
latched = np.zeros(len(dataframe), dtype=bool)
|
||||
|
||||
for i in range(1, len(dataframe)):
|
||||
if dataframe['stop_buying_deb'].iloc[i]:
|
||||
latched[i] = True
|
||||
elif dataframe['stop_buying_end'].iloc[i]:
|
||||
latched[i] = False
|
||||
else:
|
||||
latched[i] = latched[i - 1]
|
||||
dataframe['stop_buying'] = latched
|
||||
for i in range(1, len(dataframe)):
|
||||
if dataframe[f'stop_buying{timeperiod}_deb'].iloc[i]:
|
||||
latched[i] = True
|
||||
elif dataframe[f'stop_buying{timeperiod}_end'].iloc[i]:
|
||||
latched[i] = False
|
||||
else:
|
||||
latched[i] = latched[i - 1]
|
||||
dataframe[f'stop_buying{timeperiod}'] = latched
|
||||
|
||||
# ######################################################################################################
|
||||
################### INFORMATIVE 1d
|
||||
informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d")
|
||||
# informative = self.populateDataframe(informative, timeframe='1d')
|
||||
# heikinashi = qtpylib.heikinashi(informative)
|
||||
# informative['haopen'] = heikinashi['open']
|
||||
# informative['haclose'] = heikinashi['close']
|
||||
# informative['hapercent'] = (informative['haclose'] - informative['haopen']) / informative['haclose']
|
||||
informative['mid'] = informative['open'] + (informative['close'] - informative['open']) / 2
|
||||
for timeperiod in timeperiods:
|
||||
informative[f'max{timeperiod}'] = talib.MAX(informative['close'], timeperiod=timeperiod)
|
||||
informative[f'min{timeperiod}'] = talib.MIN(informative['close'], timeperiod=timeperiod)
|
||||
# informative[f"range{timeperiod}"] = ((informative["close"] - informative[f'min{timeperiod}']) / (informative[f'max{timeperiod}'] - informative[f'min{timeperiod}']))
|
||||
# informative[f"percent{timeperiod}"] = informative['close'].pct_change(timeperiod)
|
||||
informative[f"sma{timeperiod}"] = informative['mid'].ewm(span=timeperiod, adjust=False).mean()
|
||||
self.calculeDerivees(informative, f"sma{timeperiod}", timeframe=self.timeframe, ema_period=timeperiod)
|
||||
|
||||
informative[f'stop_buying_deb{timeperiod}'] = (informative[f'sma{timeperiod}_trend_change_down'] == 1)
|
||||
informative[f'stop_buying_end{timeperiod}'] = (informative[f'sma{timeperiod}_trend_change_up'] == 1)
|
||||
latched = np.zeros(len(informative), dtype=bool)
|
||||
|
||||
for i in range(1, len(informative)):
|
||||
if informative[f'stop_buying_deb{timeperiod}'].iloc[i]:
|
||||
latched[i] = True
|
||||
elif informative[f'stop_buying_end{timeperiod}'].iloc[i]:
|
||||
latched[i] = False
|
||||
else:
|
||||
latched[i] = latched[i - 1]
|
||||
informative[f'stop_buying{timeperiod}'] = latched
|
||||
|
||||
dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True)
|
||||
# ######################################################################################################
|
||||
|
||||
range_min = dataframe[f"min12_1d"]
|
||||
range_max = dataframe[f"max48"]
|
||||
|
||||
dataframe[f"range_pos"] = (dataframe['close'] - range_min) / (range_max - range_min)
|
||||
|
||||
|
||||
# récupérer le dernier trade fermé
|
||||
trades = Trade.get_trades_proxy(pair=pair,is_open=False)
|
||||
if trades:
|
||||
last_trade = trades[-1]
|
||||
self.pairs[pair]['last_profit'] = last_trade.close_profit # ex: 0.12 = +12%
|
||||
self.pairs[pair]['last_trade'] = last_trade
|
||||
|
||||
return dataframe
|
||||
|
||||
@@ -631,51 +750,52 @@ class Empty(IStrategy):
|
||||
|
||||
conditions = list()
|
||||
|
||||
# print(dataframe.columns)
|
||||
# # print(dataframe.columns)
|
||||
#
|
||||
# buy_indicator = self.buy_indicator0.value
|
||||
# buy_crossed_indicator = self.buy_crossed_indicator0.value
|
||||
# buy_operator = self.buy_operator0.value
|
||||
# buy_real_num = self.buy_real_num0.value
|
||||
# condition, dataframe = condition_generator(
|
||||
# dataframe,
|
||||
# buy_operator,
|
||||
# buy_indicator,
|
||||
# buy_crossed_indicator,
|
||||
# buy_real_num
|
||||
# )
|
||||
# conditions.append(condition)
|
||||
# # backup
|
||||
# buy_indicator = self.buy_indicator1.value
|
||||
# buy_crossed_indicator = self.buy_crossed_indicator1.value
|
||||
# buy_operator = self.buy_operator1.value
|
||||
# buy_real_num = self.buy_real_num1.value
|
||||
#
|
||||
# condition, dataframe = condition_generator(
|
||||
# dataframe,
|
||||
# buy_operator,
|
||||
# buy_indicator,
|
||||
# buy_crossed_indicator,
|
||||
# buy_real_num
|
||||
# )
|
||||
# conditions.append(condition)
|
||||
#
|
||||
# buy_indicator = self.buy_indicator2.value
|
||||
# buy_crossed_indicator = self.buy_crossed_indicator2.value
|
||||
# buy_operator = self.buy_operator2.value
|
||||
# buy_real_num = self.buy_real_num2.value
|
||||
# condition, dataframe = condition_generator(
|
||||
# dataframe,
|
||||
# buy_operator,
|
||||
# buy_indicator,
|
||||
# buy_crossed_indicator,
|
||||
# buy_real_num
|
||||
# )
|
||||
# conditions.append(condition)
|
||||
conditions.append((dataframe[self.stop_buying_indicator.value] == False))
|
||||
|
||||
buy_indicator = self.buy_indicator0.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator0.value
|
||||
buy_operator = self.buy_operator0.value
|
||||
buy_real_num = self.buy_real_num0.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
# backup
|
||||
buy_indicator = self.buy_indicator1.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator1.value
|
||||
buy_operator = self.buy_operator1.value
|
||||
buy_real_num = self.buy_real_num1.value
|
||||
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
buy_indicator = self.buy_indicator2.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator2.value
|
||||
buy_operator = self.buy_operator2.value
|
||||
buy_real_num = self.buy_real_num2.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
conditions.append((dataframe['stop_buying'] == False))
|
||||
|
||||
# conditions.append((dataframe['min60'].shift(5) == dataframe['min60']))
|
||||
# conditions.append((dataframe['low'] < dataframe['min60']))
|
||||
# conditions.append(dataframe['hapercent'] > 0)
|
||||
# # conditions.append(dataframe[f"range_pos"] <= 0.5)
|
||||
# conditions.append(dataframe[f"sma5_deriv1"] > 0)
|
||||
|
||||
print(f"BUY indicators tested \n"
|
||||
f"{self.buy_indicator0.value} {self.buy_crossed_indicator0.value} {self.buy_operator0.value} {self.buy_real_num0.value} \n"
|
||||
@@ -692,57 +812,57 @@ class Empty(IStrategy):
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
conditions = list()
|
||||
# TODO: Its not dry code!
|
||||
sell_indicator = self.sell_indicator0.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator0.value
|
||||
sell_operator = self.sell_operator0.value
|
||||
sell_real_num = self.sell_real_num0.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
sell_indicator = self.sell_indicator1.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator1.value
|
||||
sell_operator = self.sell_operator1.value
|
||||
sell_real_num = self.sell_real_num1.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
sell_indicator = self.sell_indicator2.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator2.value
|
||||
sell_operator = self.sell_operator2.value
|
||||
sell_real_num = self.sell_real_num2.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
|
||||
print(f"SELL indicators tested \n"
|
||||
f"{self.sell_indicator0.value} {self.sell_crossed_indicator0.value} {self.sell_operator0.value} {self.sell_real_num0.value} \n"
|
||||
f"{self.sell_indicator1.value} {self.sell_crossed_indicator1.value} {self.sell_operator1.value} {self.sell_real_num1.value} \n"
|
||||
f"{self.sell_indicator2.value} {self.sell_crossed_indicator2.value} {self.sell_operator2.value} {self.sell_real_num2.value} \n"
|
||||
)
|
||||
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[reduce(lambda x, y: x & y, conditions), ['exit_long', 'exit_tag']] = (1, 'god')
|
||||
# conditions = list()
|
||||
# # TODO: Its not dry code!
|
||||
# sell_indicator = self.sell_indicator0.value
|
||||
# sell_crossed_indicator = self.sell_crossed_indicator0.value
|
||||
# sell_operator = self.sell_operator0.value
|
||||
# sell_real_num = self.sell_real_num0.value
|
||||
# condition, dataframe = condition_generator(
|
||||
# dataframe,
|
||||
# sell_operator,
|
||||
# sell_indicator,
|
||||
# sell_crossed_indicator,
|
||||
# sell_real_num
|
||||
# )
|
||||
# conditions.append(condition)
|
||||
#
|
||||
# sell_indicator = self.sell_indicator1.value
|
||||
# sell_crossed_indicator = self.sell_crossed_indicator1.value
|
||||
# sell_operator = self.sell_operator1.value
|
||||
# sell_real_num = self.sell_real_num1.value
|
||||
# condition, dataframe = condition_generator(
|
||||
# dataframe,
|
||||
# sell_operator,
|
||||
# sell_indicator,
|
||||
# sell_crossed_indicator,
|
||||
# sell_real_num
|
||||
# )
|
||||
# conditions.append(condition)
|
||||
#
|
||||
# sell_indicator = self.sell_indicator2.value
|
||||
# sell_crossed_indicator = self.sell_crossed_indicator2.value
|
||||
# sell_operator = self.sell_operator2.value
|
||||
# sell_real_num = self.sell_real_num2.value
|
||||
# condition, dataframe = condition_generator(
|
||||
# dataframe,
|
||||
# sell_operator,
|
||||
# sell_indicator,
|
||||
# sell_crossed_indicator,
|
||||
# sell_real_num
|
||||
# )
|
||||
# conditions.append(condition)
|
||||
#
|
||||
#
|
||||
# print(f"SELL indicators tested \n"
|
||||
# f"{self.sell_indicator0.value} {self.sell_crossed_indicator0.value} {self.sell_operator0.value} {self.sell_real_num0.value} \n"
|
||||
# f"{self.sell_indicator1.value} {self.sell_crossed_indicator1.value} {self.sell_operator1.value} {self.sell_real_num1.value} \n"
|
||||
# f"{self.sell_indicator2.value} {self.sell_crossed_indicator2.value} {self.sell_operator2.value} {self.sell_real_num2.value} \n"
|
||||
# )
|
||||
#
|
||||
#
|
||||
# if conditions:
|
||||
# dataframe.loc[reduce(lambda x, y: x & y, conditions), ['exit_long', 'exit_tag']] = (1, 'god')
|
||||
return dataframe
|
||||
|
||||
def calculeDerivees(
|
||||
@@ -816,4 +936,50 @@ class Empty(IStrategy):
|
||||
(momentum_short < momentum_long)
|
||||
)
|
||||
|
||||
return dataframe
|
||||
return dataframe
|
||||
|
||||
@property
|
||||
def protections(self):
|
||||
return [
|
||||
{
|
||||
"method": "CooldownPeriod",
|
||||
"stop_duration_candles": 12
|
||||
},
|
||||
# {
|
||||
# "method": "MaxDrawdown",
|
||||
# "lookback_period_candles": 96,
|
||||
# "trade_limit": 4,
|
||||
# "max_allowed_drawdown": 0.1,
|
||||
# "stop_duration_candles": 24
|
||||
# },
|
||||
# {
|
||||
# "method": "StoplossGuard",
|
||||
# "lookback_period_candles": 96,
|
||||
# "trade_limit": 2,
|
||||
# "stop_duration_candles": 48,
|
||||
# "only_per_pair": False
|
||||
# },
|
||||
# {
|
||||
# "method": "LowProfitPairs",
|
||||
# "lookback_period_candles": 6,
|
||||
# "trade_limit": 2,
|
||||
# "stop_duration_candles": 60,
|
||||
# "required_profit": 0.02
|
||||
# },
|
||||
# {
|
||||
# "method": "LowProfitPairs",
|
||||
# "lookback_period_candles": 24,
|
||||
# "trade_limit": 4,
|
||||
# "stop_duration_candles": 2,
|
||||
# "required_profit": 0.01
|
||||
# }
|
||||
]
|
||||
|
||||
def printLog(self, str):
|
||||
if self.config.get('runmode') == 'hyperopt' or self.dp.runmode.value in ('hyperopt'):
|
||||
return;
|
||||
if not self.dp.runmode.value in ('backtest', 'hyperopt', 'lookahead-analysis'):
|
||||
logger.info(str)
|
||||
else:
|
||||
if not self.dp.runmode.value in ('hyperopt'):
|
||||
print(str)
|
||||
126
Empty.txt
Normal file
126
Empty.txt
Normal file
@@ -0,0 +1,126 @@
|
||||
|
||||
BACKTESTING REPORT
|
||||
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ Pair ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDC ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃
|
||||
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||
│ BTC/USDC │ 45 │ 3.05 │ 903.533 │ 90.35 │ 15 days, 1:43:00 │ 44 0 1 97.8 │
|
||||
│ TOTAL │ 45 │ 3.05 │ 903.533 │ 90.35 │ 15 days, 1:43:00 │ 44 0 1 97.8 │
|
||||
└──────────┴────────┴──────────────┴─────────────────┴──────────────┴──────────────────┴────────────────────────┘
|
||||
LEFT OPEN TRADES REPORT
|
||||
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ Pair ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDC ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃
|
||||
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||
│ BTC/USDC │ 1 │ -40.58 │ -1300.800 │ -130.08 │ 129 days, 4:00:00 │ 0 0 1 0 │
|
||||
│ TOTAL │ 1 │ -40.58 │ -1300.800 │ -130.08 │ 129 days, 4:00:00 │ 0 0 1 0 │
|
||||
└──────────┴────────┴──────────────┴─────────────────┴──────────────┴───────────────────┴────────────────────────┘
|
||||
ENTER TAG STATS
|
||||
┏━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ Enter Tag ┃ Entries ┃ Avg Profit % ┃ Tot Profit USDC ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃
|
||||
┡━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||
│ god │ 45 │ 3.05 │ 903.533 │ 90.35 │ 15 days, 1:43:00 │ 44 0 1 97.8 │
|
||||
│ TOTAL │ 45 │ 3.05 │ 903.533 │ 90.35 │ 15 days, 1:43:00 │ 44 0 1 97.8 │
|
||||
└───────────┴─────────┴──────────────┴─────────────────┴──────────────┴──────────────────┴────────────────────────┘
|
||||
EXIT REASON STATS
|
||||
┏━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ Exit Reason ┃ Exits ┃ Avg Profit % ┃ Tot Profit USDC ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃
|
||||
┡━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||
│ momentum_drop │ 44 │ 4.04 │ 2204.333 │ 220.43 │ 12 days, 11:29:00 │ 44 0 0 100 │
|
||||
│ force_exit │ 1 │ -40.58 │ -1300.800 │ -130.08 │ 129 days, 4:00:00 │ 0 0 1 0 │
|
||||
│ TOTAL │ 45 │ 3.05 │ 903.533 │ 90.35 │ 15 days, 1:43:00 │ 44 0 1 97.8 │
|
||||
└───────────────┴───────┴──────────────┴─────────────────┴──────────────┴───────────────────┴────────────────────────┘
|
||||
MIXED TAG STATS
|
||||
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ Enter Tag ┃ Exit Reason ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDC ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃
|
||||
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||
│ god │ momentum_drop │ 44 │ 4.04 │ 2204.333 │ 220.43 │ 12 days, 11:29:00 │ 44 0 0 100 │
|
||||
│ god │ force_exit │ 1 │ -40.58 │ -1300.800 │ -130.08 │ 129 days, 4:00:00 │ 0 0 1 0 │
|
||||
│ TOTAL │ │ 45 │ 3.05 │ 903.533 │ 90.35 │ 15 days, 1:43:00 │ 44 0 1 97.8 │
|
||||
└───────────┴───────────────┴────────┴──────────────┴─────────────────┴──────────────┴───────────────────┴────────────────────────┘
|
||||
MONTH BREAKDOWN
|
||||
┏━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ Month ┃ Trades ┃ Tot Profit USDC ┃ Profit Factor ┃ Win Draw Loss Win% ┃
|
||||
┡━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||
│ 31/01/2024 │ 3 │ 101.297 │ 0.0 │ 3 0 0 100 │
|
||||
│ 29/02/2024 │ 5 │ 123.805 │ 0.0 │ 5 0 0 100 │
|
||||
│ 31/03/2024 │ 4 │ 119.449 │ 0.0 │ 4 0 0 100 │
|
||||
│ 30/04/2024 │ 2 │ 48.352 │ 0.0 │ 2 0 0 100 │
|
||||
│ 31/05/2024 │ 3 │ 102.779 │ 0.0 │ 3 0 0 100 │
|
||||
│ 30/06/2024 │ 1 │ 40.932 │ 0.0 │ 1 0 0 100 │
|
||||
│ 31/07/2024 │ 4 │ 163.017 │ 0.0 │ 4 0 0 100 │
|
||||
│ 31/08/2024 │ 0 │ 0 │ 0.0 │ 0 0 0 0 │
|
||||
│ 30/09/2024 │ 0 │ 0 │ 0.0 │ 0 0 0 0 │
|
||||
│ 31/10/2024 │ 2 │ 84.227 │ 0.0 │ 2 0 0 100 │
|
||||
│ 30/11/2024 │ 5 │ 301.166 │ 0.0 │ 5 0 0 100 │
|
||||
│ 31/12/2024 │ 1 │ 96.283 │ 0.0 │ 1 0 0 100 │
|
||||
│ 31/01/2025 │ 3 │ 160.102 │ 0.0 │ 3 0 0 100 │
|
||||
│ 28/02/2025 │ 0 │ 0 │ 0.0 │ 0 0 0 0 │
|
||||
│ 31/03/2025 │ 1 │ 62.274 │ 0.0 │ 1 0 0 100 │
|
||||
│ 30/04/2025 │ 1 │ 192.722 │ 0.0 │ 1 0 0 100 │
|
||||
│ 31/05/2025 │ 3 │ 138.491 │ 0.0 │ 3 0 0 100 │
|
||||
│ 30/06/2025 │ 0 │ 0 │ 0.0 │ 0 0 0 0 │
|
||||
│ 31/07/2025 │ 2 │ 210.269 │ 0.0 │ 2 0 0 100 │
|
||||
│ 31/08/2025 │ 2 │ 72.441 │ 0.0 │ 2 0 0 100 │
|
||||
│ 30/09/2025 │ 1 │ 61.018 │ 0.0 │ 1 0 0 100 │
|
||||
│ 31/10/2025 │ 1 │ 125.709 │ 0.0 │ 1 0 0 100 │
|
||||
│ 30/11/2025 │ 0 │ 0 │ 0.0 │ 0 0 0 0 │
|
||||
│ 31/12/2025 │ 0 │ 0 │ 0.0 │ 0 0 0 0 │
|
||||
│ 31/01/2026 │ 0 │ 0 │ 0.0 │ 0 0 0 0 │
|
||||
│ 28/02/2026 │ 1 │ -1300.8 │ 0.0 │ 0 0 1 0 │
|
||||
└────────────┴────────┴─────────────────┴───────────────┴────────────────────────┘
|
||||
SUMMARY METRICS
|
||||
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ Metric ┃ Value ┃
|
||||
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
|
||||
│ Backtesting from │ 2024-01-01 00:00:00 │
|
||||
│ Backtesting to │ 2026-02-10 00:00:00 │
|
||||
│ Trading Mode │ Spot │
|
||||
│ Max open trades │ 1 │
|
||||
│ │ │
|
||||
│ Total/Daily Avg Trades │ 45 / 0.06 │
|
||||
│ Starting balance │ 1000 USDC │
|
||||
│ Final balance │ 1903.533 USDC │
|
||||
│ Absolute profit │ 903.533 USDC │
|
||||
│ Total profit % │ 90.35% │
|
||||
│ CAGR % │ 35.63% │
|
||||
│ Sortino │ -100.00 │
|
||||
│ Sharpe │ 0.11 │
|
||||
│ Calmar │ 5.52 │
|
||||
│ SQN │ 0.66 │
|
||||
│ Profit factor │ 1.69 │
|
||||
│ Expectancy (Ratio) │ 20.08 (0.02) │
|
||||
│ Avg. daily profit │ 1.172 USDC │
|
||||
│ Avg. stake amount │ 1314.959 USDC │
|
||||
│ Total trade volume │ 119488.585 USDC │
|
||||
│ │ │
|
||||
│ Best Pair │ BTC/USDC 90.35% │
|
||||
│ Worst Pair │ BTC/USDC 90.35% │
|
||||
│ Best trade │ BTC/USDC 9.64% │
|
||||
│ Worst trade │ BTC/USDC -40.58% │
|
||||
│ Best day │ 192.722 USDC │
|
||||
│ Worst day │ -1300.8 USDC │
|
||||
│ Days win/draw/lose │ 44 / 726 / 1 │
|
||||
│ Min/Max/Avg. Duration Winners │ 0d 16:00 / 85d 14:00 / 12d 11:29 │
|
||||
│ Min/Max/Avg. Duration Losers │ 129d 04:00 / 129d 04:00 / 129d 04:00 │
|
||||
│ Max Consecutive Wins / Loss │ 44 / 1 │
|
||||
│ Rejected Entry signals │ 0 │
|
||||
│ Entry/Exit Timeouts │ 0 / 0 │
|
||||
│ │ │
|
||||
│ Min balance │ 1029.974 USDC │
|
||||
│ Max balance │ 3204.333 USDC │
|
||||
│ Max % of account underwater │ 40.60% │
|
||||
│ Absolute drawdown │ 1300.8 USDC (40.60%) │
|
||||
│ Drawdown duration │ 129 days 23:00:00 │
|
||||
│ Profit at drawdown start │ 2204.333 USDC │
|
||||
│ Profit at drawdown end │ 903.533 USDC │
|
||||
│ Drawdown start │ 2025-10-03 01:00:00 │
|
||||
│ Drawdown end │ 2026-02-10 00:00:00 │
|
||||
│ Market change │ 64.37% │
|
||||
└───────────────────────────────┴──────────────────────────────────────┘
|
||||
|
||||
Backtested 2024-01-01 00:00:00 -> 2026-02-10 00:00:00 | Max open trades : 1
|
||||
STRATEGY SUMMARY
|
||||
┏━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ Strategy ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDC ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃ Drawdown ┃
|
||||
┡━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━┩
|
||||
│ Empty │ 45 │ 3.05 │ 903.533 │ 90.35 │ 15 days, 1:43:00 │ 44 0 1 97.8 │ 1300.8 USDC 40.60% │
|
||||
└──────────┴────────┴──────────────┴─────────────────┴──────────────┴──────────────────┴────────────────────────┴─────────────────────┘
|
||||
Reference in New Issue
Block a user