FrictradeLearning.py Stoploss auto et gestion steps de mises adjust
This commit is contained in:
@@ -119,6 +119,8 @@ class FrictradeLearning(IStrategy):
|
||||
-18: 0.30,
|
||||
}
|
||||
|
||||
allow_decrease_rate = 0.4
|
||||
|
||||
# ROI table:
|
||||
minimal_roi = {
|
||||
"0": 10
|
||||
@@ -168,7 +170,9 @@ class FrictradeLearning(IStrategy):
|
||||
'total_amount': 0,
|
||||
'has_gain': 0,
|
||||
'force_sell': False,
|
||||
'force_buy': False
|
||||
'force_buy': False,
|
||||
'last_ath': 0,
|
||||
'dca_thresholds': {}
|
||||
}
|
||||
for pair in ["BTC/USDC", "ETH/USDC", "DOGE/USDC", "XRP/USDC", "SOL/USDC",
|
||||
"BTC/USDT", "ETH/USDT", "DOGE/USDT", "XRP/USDT", "SOL/USDT"]
|
||||
@@ -216,7 +220,6 @@ class FrictradeLearning(IStrategy):
|
||||
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'])
|
||||
|
||||
|
||||
dispo = round(self.wallets.get_available_stake_amount())
|
||||
self.printLineLog()
|
||||
|
||||
@@ -225,6 +228,8 @@ class FrictradeLearning(IStrategy):
|
||||
self.pairs[pair]['total_amount'] = stake_amount
|
||||
self.pairs[pair]['first_amount'] = stake_amount
|
||||
|
||||
self.calculateStepsDcaThresholds(last_candle, pair)
|
||||
|
||||
self.log_trade(
|
||||
last_candle=last_candle,
|
||||
date=current_time,
|
||||
@@ -240,6 +245,23 @@ class FrictradeLearning(IStrategy):
|
||||
|
||||
return allow_to_buy
|
||||
|
||||
def calculateStepsDcaThresholds(self, last_candle, pair):
|
||||
def split_ratio_one_third(n, p):
|
||||
a = n / (2 * p) # première valeur
|
||||
d = n / (p * (p - 1)) # incrément
|
||||
return [round(a + i * d, 3) for i in range(p)]
|
||||
|
||||
if self.pairs[pair]['last_ath'] == 0 :
|
||||
ath = max(last_candle['mid'], self.get_last_ath_before_candle(last_candle))
|
||||
self.pairs[pair]['last_ath'] = ath
|
||||
|
||||
steps = self.approx_value(last_candle['mid'], self.pairs[pair]['last_ath'])
|
||||
self.pairs[pair]['dca_thresholds'] = split_ratio_one_third(
|
||||
(last_candle['mid'] - (self.pairs[pair]['last_ath'] * (1 - self.allow_decrease_rate))) / last_candle['mid'],
|
||||
steps)
|
||||
print(f"val={last_candle['mid']} steps={steps} pct={(last_candle['mid'] - (self.pairs[pair]['last_ath'] * (1 - self.allow_decrease_rate))) / last_candle['mid']}")
|
||||
print(self.pairs[pair]['dca_thresholds'])
|
||||
|
||||
def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float, rate: float,
|
||||
time_in_force: str,
|
||||
exit_reason: str, current_time, **kwargs, ) -> bool:
|
||||
@@ -381,7 +403,7 @@ class FrictradeLearning(IStrategy):
|
||||
self.printLog(
|
||||
f"| {'Date':<16} | {'Action':<10} |{'Pair':<5}| {'Trade Type':<18} |{'Rate':>8} | {'Dispo':>6} | {'Profit':>8} "
|
||||
f"| {'Pct':>6} | {'max_touch':>11} | {'last_lost':>12} | {'last_max':>7}| {'last_min':>7}|{'Buys':>5}| {'Stake':>5} |"
|
||||
f"{'rsi':>6}|{'mlprob':>6}" #|Distmax|s201d|s5_1d|s5_2d|s51h|s52h|smt1h|smt2h|tdc1d|tdc1h"
|
||||
f"{'rsi':>6}|{'rsi_1h':>6}|{'rsi_1d':>6}|{'mlprob':>6}" #|Distmax|s201d|s5_1d|s5_2d|s51h|s52h|smt1h|smt2h|tdc1d|tdc1h"
|
||||
)
|
||||
self.printLineLog()
|
||||
df = pd.DataFrame.from_dict(self.pairs, orient='index')
|
||||
@@ -565,8 +587,12 @@ class FrictradeLearning(IStrategy):
|
||||
filled_buys = trade.select_filled_orders('buy')
|
||||
count = 0
|
||||
amount = 0
|
||||
min_price = 111111111111110;
|
||||
max_price = 0;
|
||||
for buy in filled_buys:
|
||||
if count == 0:
|
||||
min_price = min(min_price, buy.price)
|
||||
max_price = max(max_price, buy.price)
|
||||
dataframe['first_price'] = buy.price
|
||||
self.pairs[pair]['first_buy'] = buy.price
|
||||
self.pairs[pair]['first_amount'] = buy.price * buy.filled
|
||||
@@ -782,6 +808,36 @@ class FrictradeLearning(IStrategy):
|
||||
# Non utilisé dans le modèle
|
||||
dataframe['min60'] = talib.MIN(dataframe['mid'], timeperiod=60)
|
||||
|
||||
# val = 90000
|
||||
# steps = 12
|
||||
# [0.018, 0.022, 0.025, 0.028, 0.032, 0.035, 0.038, 0.042, 0.045, 0.048, 0.052, 0.055]
|
||||
|
||||
# val = 100000
|
||||
# steps = 20
|
||||
# [0.012, 0.014, 0.015, 0.016, 0.018, 0.019, 0.02, 0.022, 0.023, 0.024, 0.025, 0.027, 0.028, 0.029, 0.031, 0.032,
|
||||
# 0.033, 0.035, 0.036, 0.037]
|
||||
|
||||
# val = 110000
|
||||
# steps = 28
|
||||
# [0.01, 0.01, 0.011, 0.012, 0.013, 0.013, 0.014, 0.015, 0.015, 0.016, 0.017, 0.018, 0.018, 0.019, 0.02, 0.02,
|
||||
# 0.021, 0.022, 0.023, 0.023, 0.024, 0.025, 0.025, 0.026, 0.027, 0.028, 0.028, 0.029]
|
||||
|
||||
# val = 120000
|
||||
# steps = 35
|
||||
# [0.008, 0.009, 0.009, 0.01, 0.01, 0.011, 0.011, 0.012, 0.012, 0.013, 0.013, 0.014, 0.014, 0.015, 0.015, 0.016,
|
||||
# 0.016, 0.017, 0.017, 0.018, 0.018, 0.019, 0.019, 0.019, 0.02, 0.02, 0.021, 0.021, 0.022, 0.022, 0.023, 0.023,
|
||||
# 0.024, 0.024, 0.025]
|
||||
|
||||
# def split_ratio_one_third(n, p):
|
||||
# a = n / (2 * p) # première valeur
|
||||
# d = n / (p * (p - 1)) # incrément
|
||||
# return [round(a + i * d, 3) for i in range(p)]
|
||||
#
|
||||
# for val in range(90000, 130000, 10000):
|
||||
# steps = self.approx_value(val, 126000)
|
||||
# print(f"val={val} steps={steps} pct={(val - (126000 * (1 - self.allow_decrease_rate))) / val}")
|
||||
# dca = split_ratio_one_third((val - (126000 * (1 - self.allow_decrease_rate))) / 126000, steps)
|
||||
# print(dca)
|
||||
|
||||
return dataframe
|
||||
|
||||
@@ -959,21 +1015,37 @@ class FrictradeLearning(IStrategy):
|
||||
#
|
||||
# return adjusted_stake_amount
|
||||
|
||||
def approx_value(self, x, X_max):
|
||||
X_min = X_max * (1 - self.allow_decrease_rate) # 126198 * 0.4 = 75718,8
|
||||
Y_min = 1
|
||||
Y_max = 40
|
||||
a = (Y_max - Y_min) / (X_max - X_min) # 39 ÷ (126198 − 126198×0,6) = 0,000772595
|
||||
b = Y_min - a * X_min # 1 − (0,000772595 × 75718,8) = −38
|
||||
y = a * x + b # 0,000772595 * 115000 - 38
|
||||
return max(round(y), 1) # évite les valeurs négatives
|
||||
|
||||
def adjust_stake_amount(self, pair: str, last_candle: DataFrame):
|
||||
|
||||
if self.pairs[pair]['first_amount'] > 0:
|
||||
return self.pairs[pair]['first_amount']
|
||||
|
||||
ath = max(self.pairs[pair]['last_max'], self.get_last_ath_before_candle(last_candle))
|
||||
self.pairs[pair]['last_ath'] = ath
|
||||
|
||||
ath_dist = 100 * (ath - last_candle["mid"]) / ath
|
||||
|
||||
|
||||
# ath_dist
|
||||
# 0 ==> 1
|
||||
# 20 ==> 1.5
|
||||
# 40 ==> 2
|
||||
# 50 * (1 + (ath_dist / 40))
|
||||
base_stake = self.config.get('stake_amount') * (1 + (ath_dist / 40))
|
||||
|
||||
full = self.wallets.get_total_stake_amount()
|
||||
steps = self.approx_value(last_candle['mid'], ath)
|
||||
base_stake = full / steps
|
||||
|
||||
# base_stake = stake * (1 + (ath_dist / 40))
|
||||
|
||||
# Calcule max/min 180
|
||||
low180 = last_candle["min180"]
|
||||
@@ -995,8 +1067,6 @@ class FrictradeLearning(IStrategy):
|
||||
if trade.has_open_orders:
|
||||
# self.printLog("skip open orders")
|
||||
return None
|
||||
if (self.wallets.get_available_stake_amount() < 10): # or trade.stake_amount >= max_stake:
|
||||
return 0
|
||||
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe)
|
||||
last_candle = dataframe.iloc[-1].squeeze()
|
||||
@@ -1008,6 +1078,8 @@ class FrictradeLearning(IStrategy):
|
||||
hours_since_first_buy = (current_time - trade.open_date_utc).seconds / 3600.0
|
||||
days_since_first_buy = (current_time - trade.open_date_utc).days
|
||||
hours = (current_time - trade.date_last_filled_utc).total_seconds() / 3600.0
|
||||
minutes = (current_time - trade.date_last_filled_utc).total_seconds() / 60.0
|
||||
|
||||
count_of_buys = trade.nr_of_successful_entries
|
||||
current_time_utc = current_time.astimezone(timezone.utc)
|
||||
open_date = trade.open_date.astimezone(timezone.utc)
|
||||
@@ -1023,6 +1095,34 @@ class FrictradeLearning(IStrategy):
|
||||
if self.pairs[pair]['first_buy']:
|
||||
pct_first = self.getPctFirstBuy(pair, last_candle)
|
||||
|
||||
if profit > - self.pairs[pair]['first_amount'] and count_of_buys > 15 and last_candle['sma24_deriv1_1h'] < 0:
|
||||
stake_amount = trade.stake_amount
|
||||
self.pairs[pair]['previous_profit'] = profit
|
||||
trade_type = "Sell " + (last_candle['enter_tag'] if last_candle['enter_long'] == 1 else '')
|
||||
self.pairs[trade.pair]['count_of_buys'] += 1
|
||||
self.pairs[pair]['total_amount'] = stake_amount
|
||||
self.log_trade(
|
||||
last_candle=last_candle,
|
||||
date=current_time,
|
||||
action="🟧 Sell +",
|
||||
dispo=dispo,
|
||||
pair=trade.pair,
|
||||
rate=current_rate,
|
||||
trade_type=trade_type,
|
||||
profit=round(profit, 1),
|
||||
buys=trade.nr_of_successful_entries + 1,
|
||||
stake=round(stake_amount, 2)
|
||||
)
|
||||
|
||||
self.pairs[trade.pair]['last_buy'] = current_rate
|
||||
self.pairs[trade.pair]['max_touch'] = last_candle['close']
|
||||
self.pairs[trade.pair]['last_candle'] = last_candle
|
||||
|
||||
return -stake_amount
|
||||
|
||||
if (self.wallets.get_available_stake_amount() < 10): # or trade.stake_amount >= max_stake:
|
||||
return 0
|
||||
|
||||
lim = 0.3
|
||||
if (len(dataframe) < 1):
|
||||
# self.printLog("skip dataframe")
|
||||
@@ -1038,7 +1138,21 @@ class FrictradeLearning(IStrategy):
|
||||
# last_fill_price = buy_orders[-1].price
|
||||
|
||||
# baisse relative
|
||||
dca_threshold = 0.0025 * count_of_buys
|
||||
if minutes % 60 == 0:
|
||||
ath = max(self.pairs[pair]['last_max'], self.get_last_ath_before_candle(last_candle))
|
||||
self.pairs[pair]['last_ath'] = ath
|
||||
else:
|
||||
ath = self.pairs[pair]['last_ath']
|
||||
|
||||
# steps = self.approx_value(last_candle['mid'], ath)
|
||||
|
||||
# dca_thresholds = split_ratio_one_third((last_candle['mid'] - (ath * self.allow_decrease_rate)) / last_candle['mid'], steps) #((last_candle['mid'] - (ath * self.allow_decrease_rate)) / steps) / last_candle['mid'] # 0.0025 + 0.0005 * count_of_buys
|
||||
if len(self.pairs[pair]['dca_thresholds']) == 0:
|
||||
self.calculateStepsDcaThresholds(last_candle, pair)
|
||||
|
||||
dca_threshold = self.pairs[pair]['dca_thresholds'][min(count_of_buys - 1, len(self.pairs[pair]['dca_thresholds']) - 1)]
|
||||
|
||||
# print(f"{count_of_buys} {ath * (1 - self.allow_decrease_rate)} {round(last_candle['mid'], 2)} {round((last_candle['mid'] - (ath * self.allow_decrease_rate)) / last_candle['mid'], 2)} {steps} {round(dca_threshold, 4)}")
|
||||
decline = (last_fill_price - current_rate) / last_fill_price
|
||||
increase = - decline
|
||||
|
||||
@@ -1078,21 +1192,21 @@ class FrictradeLearning(IStrategy):
|
||||
# return None
|
||||
|
||||
# FIN ########################## ALGO ATH
|
||||
|
||||
force = hours > 24 and last_candle['sma60_deriv1_1h'] > 0
|
||||
condition = last_candle['percent'] > 0 and last_candle['sma24_deriv1'] > 0 \
|
||||
and last_candle['close'] < self.pairs[pair]['first_buy']
|
||||
# and last_candle['ml_prob'] > 0.65
|
||||
|
||||
limit_buy = 40
|
||||
# or (last_candle['close'] <= last_candle['min180'] and hours > 3)
|
||||
if (decline >= dca_threshold) and condition:
|
||||
if ((force or decline >= dca_threshold) and condition):
|
||||
try:
|
||||
if self.pairs[pair]['has_gain'] and profit > 0:
|
||||
self.pairs[pair]['force_sell'] = True
|
||||
self.pairs[pair]['previous_profit'] = profit
|
||||
return None
|
||||
|
||||
stake_amount = min(self.wallets.get_available_stake_amount(), self.adjust_stake_amount(pair, last_candle) / 2)
|
||||
stake_amount = min(self.wallets.get_available_stake_amount(), self.adjust_stake_amount(pair, last_candle))
|
||||
# print(f"profit={profit} previous={self.pairs[pair]['previous_profit']} count_of_buys={trade.nr_of_successful_entries}")
|
||||
if stake_amount > 0:
|
||||
self.pairs[pair]['previous_profit'] = profit
|
||||
@@ -1102,7 +1216,7 @@ class FrictradeLearning(IStrategy):
|
||||
self.log_trade(
|
||||
last_candle=last_candle,
|
||||
date=current_time,
|
||||
action="🟧 Loss -",
|
||||
action="🟧 " + ("Force" if force else 'Loss -'),
|
||||
dispo=dispo,
|
||||
pair=trade.pair,
|
||||
rate=current_rate,
|
||||
@@ -1130,7 +1244,8 @@ class FrictradeLearning(IStrategy):
|
||||
self.printLog(exception)
|
||||
return None
|
||||
|
||||
if current_profit > dca_threshold and (increase >= dca_threshold and self.wallets.get_available_stake_amount() > 0):
|
||||
if current_profit > dca_threshold and (increase >= dca_threshold and self.wallets.get_available_stake_amount() > 0)\
|
||||
and last_candle['rsi'] < 75:
|
||||
try:
|
||||
self.pairs[pair]['previous_profit'] = profit
|
||||
stake_amount = max(20, min(self.wallets.get_available_stake_amount(), self.adjust_stake_amount(pair, last_candle)))
|
||||
@@ -1242,19 +1357,19 @@ class FrictradeLearning(IStrategy):
|
||||
if max_profit:
|
||||
baisse = (max_profit - profit) / max_profit
|
||||
|
||||
if minutes % 12 == 0:
|
||||
self.log_trade(
|
||||
last_candle=last_candle,
|
||||
date=current_time,
|
||||
action="🟢 CURRENT", #🔴 CURRENT" if self.pairs[pair]['stop'] or last_candle['stop_buying'] else "
|
||||
dispo=dispo,
|
||||
pair=pair,
|
||||
rate=last_candle['close'],
|
||||
trade_type=f"{round(profit, 2)} {round(max_profit, 2)} {round(trailing_stop,2)} {minutes}",
|
||||
profit=round(profit, 2),
|
||||
buys=count_of_buys,
|
||||
stake=0
|
||||
)
|
||||
# if minutes % 12 == 0:
|
||||
# self.log_trade(
|
||||
# last_candle=last_candle,
|
||||
# date=current_time,
|
||||
# action="🟢 CURRENT", #🔴 CURRENT" if self.pairs[pair]['stop'] or last_candle['stop_buying'] else "
|
||||
# dispo=dispo,
|
||||
# pair=pair,
|
||||
# rate=last_candle['close'],
|
||||
# trade_type=f"{round(profit, 2)} {round(max_profit, 2)} {round(trailing_stop,2)} {minutes}",
|
||||
# profit=round(profit, 2),
|
||||
# buys=count_of_buys,
|
||||
# stake=0
|
||||
# )
|
||||
|
||||
if last_candle['sma12'] > last_candle['sma24']:
|
||||
return None
|
||||
@@ -1275,6 +1390,7 @@ class FrictradeLearning(IStrategy):
|
||||
|
||||
# ----- 6) Condition de vente -----
|
||||
if 0 < profit <= trailing_stop and last_candle['mid'] < last_candle['sma5']:
|
||||
self.pairs[pair]['force_buy'] = True
|
||||
return f"stop_{count_of_buys}_{self.pairs[pair]['has_gain']}"
|
||||
return None
|
||||
|
||||
@@ -1377,6 +1493,7 @@ class FrictradeLearning(IStrategy):
|
||||
|
||||
# suppose self.btc_ath_history exists (liste de dict)
|
||||
def get_last_ath_before_candle(self, last_candle):
|
||||
|
||||
candle_date = self.to_utc_ts(last_candle['date']) # ou to_utc_ts(last_candle.name)
|
||||
best = None
|
||||
for a in self.btc_ath_history: #getattr(self, "btc_ath_history", []):
|
||||
@@ -1420,7 +1537,7 @@ class FrictradeLearning(IStrategy):
|
||||
|
||||
# 3️⃣ Créer la cible : 1 si le prix monte dans les prochaines bougies
|
||||
# df['target'] = (df['sma24'].shift(-24) > df['sma24']).astype(int)
|
||||
df['target'] = ((df["sma24"].shift(-13) - df["sma24"]) > 0).astype(int)
|
||||
df['target'] = ((df["sma24"].shift(-13) - df["sma24"]) > 100).astype(int)
|
||||
df['target'] = df['target'].fillna(0).astype(int)
|
||||
|
||||
# Corrélations triées par importance avec une colonne cible
|
||||
@@ -1545,11 +1662,11 @@ class FrictradeLearning(IStrategy):
|
||||
# )
|
||||
|
||||
local_model = XGBClassifier(
|
||||
n_estimators=300, #trial.suggest_int("n_estimators", 300, 500),
|
||||
max_depth=trial.suggest_int("max_depth", 1, 3),
|
||||
learning_rate=0.01, #trial.suggest_float("learning_rate", 0.005, 0.3, log=True),
|
||||
subsample=0.7, #trial.suggest_float("subsample", 0.6, 1.0),
|
||||
colsample_bytree=0.8, #trial.suggest_float("colsample_bytree", 0.6, 1.0),
|
||||
n_estimators=trial.suggest_int("n_estimators", 300, 500),
|
||||
max_depth=trial.suggest_int("max_depth", 1, 6),
|
||||
learning_rate=trial.suggest_float("learning_rate", 0.005, 0.3, log=True),
|
||||
subsample=trial.suggest_float("subsample", 0.6, 1.0),
|
||||
colsample_bytree=trial.suggest_float("colsample_bytree", 0.6, 1.0),
|
||||
scale_pos_weight=1,
|
||||
objective="binary:logistic",
|
||||
eval_metric="logloss",
|
||||
|
||||
Reference in New Issue
Block a user