FrictradeLearning.py gestion steps de mises adjust

This commit is contained in:
Jérôme Delacotte
2025-12-15 20:37:24 +01:00
parent c82b3359fa
commit 17d8b7ccbc
2 changed files with 60 additions and 53 deletions

View File

@@ -9,7 +9,7 @@
},
"trailing": {
"trailing_stop": false,
"trailing_stop_positive": 0.2,
"trailing_stop_positive": 0.15,
"trailing_stop_positive_offset": 1,
"trailing_only_offset_is_reached": true
},
@@ -26,10 +26,10 @@
"indic_1h_force_buy": "sma5_deriv1_1h"
},
"sell": {
"offset_max": 18,
"offset_min": 17
"offset_max": 6,
"offset_min": 27
}
},
"ft_stratparam_v": 1,
"export_time": "2025-12-14 18:44:03.713386+00:00"
"export_time": "2025-12-15 19:03:21.177158+00:00"
}

View File

@@ -126,8 +126,8 @@ class FrictradeLearning(IStrategy):
columns_logged = False
pairs = {
pair: {
"first_buy": 0,
"last_buy": 0.0,
"first_price": 0,
"last_price": 0.0,
"last_min": 999999999999999.5,
"last_max": 0,
"trade_info": {},
@@ -145,7 +145,6 @@ class FrictradeLearning(IStrategy):
'stop': False,
'max_profit': 0,
'first_amount': 0,
'first_price': 0,
'total_amount': 0,
'has_gain': 0,
'force_sell': False,
@@ -178,19 +177,19 @@ class FrictradeLearning(IStrategy):
"note": "pic oct. 2025 (source agrégée, à vérifier selon l'exchange)"}
]
def dynamic_trailing_offset(self, price, ath, nb_entries, max_dca=5):
dd_ath = (ath - price) / ath
dd_ath = max(0.0, min(dd_ath, 0.5))
def dynamic_trailing_offset(self, pair, price, ath, count_of_buys, max_dca=5):
# dd_ath = (ath - price) / ath
# dd_ath = max(0.0, min(dd_ath, 0.5))
#
# dca_risk = min(count_of_buys / max_dca, 1.0)
#
# breathing_score = 0.7 * dd_ath + 0.3 * (1 - dca_risk)
# breathing_score = min(max(breathing_score, 0.0), 1.0)
#
# OFFSET_MIN = self.offset_min.value
# OFFSET_MAX = self.offset_min.value + self.offset_max.value
dca_risk = min(nb_entries / max_dca, 1.0)
breathing_score = 0.7 * dd_ath + 0.3 * (1 - dca_risk)
breathing_score = min(max(breathing_score, 0.0), 1.0)
OFFSET_MIN = self.offset_min.value
OFFSET_MAX = self.offset_min.value + self.offset_max.value
return OFFSET_MIN + breathing_score * (OFFSET_MAX - OFFSET_MIN)
return self.pairs[pair]['total_amount'] / 100 # OFFSET_MIN + breathing_score * (OFFSET_MAX - OFFSET_MIN)
def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str,
current_time: datetime, entry_tag: Optional[str], **kwargs) -> bool:
@@ -210,8 +209,8 @@ class FrictradeLearning(IStrategy):
if allow_to_buy:
self.trades = list()
self.pairs[pair]['first_buy'] = rate
self.pairs[pair]['last_buy'] = rate
self.pairs[pair]['first_price'] = rate
self.pairs[pair]['last_price'] = rate
self.pairs[pair]['max_touch'] = last_candle['close']
self.pairs[pair]['last_candle'] = last_candle
self.pairs[pair]['count_of_buys'] = 1
@@ -329,7 +328,7 @@ class FrictradeLearning(IStrategy):
self.pairs[pair]['total_amount'] = 0
self.pairs[pair]['count_of_buys'] = 0
self.pairs[pair]['max_touch'] = 0
self.pairs[pair]['last_buy'] = 0
self.pairs[pair]['last_price'] = 0
self.pairs[pair]['last_date'] = current_time
self.pairs[pair]['current_trade'] = None
else:
@@ -367,8 +366,8 @@ class FrictradeLearning(IStrategy):
# self.pairs[pair]['current_profit'] = profit
#
# dispo = round(self.wallets.get_available_stake_amount())
# 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_since_first_price = (current_time - trade.open_date_utc).seconds / 3600.0
# days_since_first_price = (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
#
@@ -406,10 +405,10 @@ class FrictradeLearning(IStrategy):
return last_lost
def getPctFirstBuy(self, pair, last_candle):
return round((last_candle['close'] - self.pairs[pair]['first_buy']) / self.pairs[pair]['first_buy'], 3)
return round((last_candle['close'] - self.pairs[pair]['first_price']) / self.pairs[pair]['first_price'], 3)
def getPctLastBuy(self, pair, last_candle):
return round((last_candle['close'] - self.pairs[pair]['last_buy']) / self.pairs[pair]['last_buy'], 4)
return round((last_candle['close'] - self.pairs[pair]['last_price']) / self.pairs[pair]['last_price'], 4)
def expectedProfit(self, pair: str, last_candle: DataFrame):
lim = 0.01
@@ -442,7 +441,7 @@ class FrictradeLearning(IStrategy):
colonnes_a_exclure = ['last_candle',
'trade_info', 'last_date', 'last_count_of_buys', 'base_stake_amount', 'stop_buy']
df_filtered = df[df['count_of_buys'] > 0].drop(columns=colonnes_a_exclure)
# df_filtered = df_filtered["first_buy", "last_max", "max_touch", "last_sell","last_buy", 'count_of_buys', 'current_profit']
# df_filtered = df_filtered["first_price", "last_max", "max_touch", "last_sell","last_price", 'count_of_buys', 'current_profit']
self.printLog(df_filtered)
@@ -645,14 +644,14 @@ class FrictradeLearning(IStrategy):
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_price'] = buy.price
self.pairs[pair]['first_amount'] = buy.price * buy.filled
# dataframe['close01'] = buy.price * 1.01
# Order(id=2396, trade=1019, order_id=29870026652, side=buy, filled=0.00078, price=63921.01,
# status=closed, date=2024-08-26 02:20:11)
dataframe['last_price'] = buy.price
self.pairs[pair]['last_buy'] = buy.price
self.pairs[pair]['last_price'] = buy.price
count = count + 1
amount += buy.price * buy.filled
self.pairs[pair]['count_of_buys'] = count
@@ -911,11 +910,17 @@ class FrictradeLearning(IStrategy):
# f"steps={steps} "
# f"pct={(round(val - (ath * (1 - self.allow_decrease_rate.value))) / val, 4)}")
# print(dca_thresholds)
if self.pairs[pair]['last_ath'] == 0:
ath = max(val, self.get_last_ath_before_candle(last_candle['date']))
self.pairs[pair]['last_ath'] = ath
if len(self.pairs[pair]['dca_thresholds']) == 0:
self.calculateStepsDcaThresholds(last_candle, pair)
print(f"val={val} dca={self.pairs[pair]['dca_thresholds']} ath={self.pairs[pair]['last_ath']} first_price={self.pairs[pair]['first_price']}")
if self.dp:
if self.dp and self.pairs[pair]['first_price'] > 0:
if self.dp.runmode.value in ('live', 'dry_run'):
full, mises, steps = self.calculateMises(last_candle, pair)
full, mises, steps = self.calculateMises(pair, self.pairs[pair]['last_ath'], val)
# stake = min(self.wallets.get_available_stake_amount(), self.adjust_stake_amount(pair, last_candle))
if val and len(self.pairs[pair]['dca_thresholds']) > 0:
print(self.pairs[pair]['dca_thresholds'])
@@ -925,14 +930,14 @@ class FrictradeLearning(IStrategy):
for dca in self.pairs[pair]['dca_thresholds']:
stake = mises[count]
pct += dca
offset = self.dynamic_trailing_offset(price=val, ath=ath, nb_entries=count)
offset = self.dynamic_trailing_offset(pair, price=val, ath=ath, count_of_buys=count)
if (count == self.pairs[pair]['count_of_buys']):
print(f"next_buy={val * (1 - pct)} count={count} pct={round(pct, 4)}")
if count == self.pairs[pair]['count_of_buys']:
print(f"next_buy={round(val * (1 - pct),1)} count={count} pct={round(pct, 4)}")
dataframe[f"next_buy"] = val * (1 - pct)
count += 1
print(
f"stake={stake} count={count} pct={round(pct, 4)} offset={offset} next_buy={val * (1 - pct)}")
f"stake={round(stake, 1)} count={count} pct={round(pct, 4)} offset={round(offset, 1)} next_buy={round(val * (1 - pct), 2)}")
return dataframe
@@ -1131,17 +1136,18 @@ class FrictradeLearning(IStrategy):
count = self.pairs[pair]['count_of_buys'] - self.pairs[pair]['has_gain']
return mises[count] if count < len(mises) else self.pairs[pair]['first_amount']
full, mises, steps = self.calculateMises(last_candle, pair)
ath = max(self.pairs[pair]['last_max'], self.get_last_ath_before_candle(last_candle['date']))
full, mises, steps = self.calculateMises(pair, ath, last_candle['mid'])
base_stake = mises[self.pairs[pair]['count_of_buys']] if self.pairs[pair]['count_of_buys'] < len(
mises) else full / (steps * 2)
return base_stake
def calculateMises(self, last_candle, pair):
ath = max(self.pairs[pair]['last_max'], self.get_last_ath_before_candle(last_candle['date']))
def calculateMises(self, pair, ath, val):
# ath = max(self.pairs[pair]['last_max'], self.get_last_ath_before_candle(last_candle['date']))
self.pairs[pair]['last_ath'] = ath
full = self.wallets.get_total_stake_amount()
steps = self.calculateNumberOfSteps(last_candle['mid'], ath, max_steps=self.max_steps.value)
steps = self.calculateNumberOfSteps(val, ath, max_steps=self.max_steps.value)
mises = self.progressive_parts(full, steps, full / (steps * 2))
print(f"ath={ath} full={full} steps={steps} mises={mises} ")
self.pairs[pair]['mises'] = mises
@@ -1167,8 +1173,8 @@ class FrictradeLearning(IStrategy):
current_time = current_time.astimezone(timezone.utc)
# open_date = trade.open_date.astimezone(timezone.utc)
dispo = round(self.wallets.get_available_stake_amount())
# 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_since_first_price = (current_time - trade.open_date_utc).seconds / 3600.0
# days_since_first_price = (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
@@ -1184,7 +1190,7 @@ class FrictradeLearning(IStrategy):
# total_counts = sum(
# pair_data['count_of_buys'] for pair_data in self.pairs.values() if not self.getShortName(pair) == 'BTC')
#
# if self.pairs[pair]['first_buy']:
# if self.pairs[pair]['first_price']:
# pct_first = self.getPctFirstBuy(pair, last_candle)
# if profit > - self.pairs[pair]['first_amount'] \
@@ -1208,7 +1214,7 @@ class FrictradeLearning(IStrategy):
# stake=round(stake_amount, 2)
# )
#
# self.pairs[trade.pair]['last_buy'] = current_rate
# self.pairs[trade.pair]['last_price'] = current_rate
# self.pairs[trade.pair]['max_touch'] = last_candle['close']
# self.pairs[trade.pair]['last_candle'] = last_candle
#
@@ -1223,7 +1229,7 @@ class FrictradeLearning(IStrategy):
return None
# Dernier prix d'achat réel (pas le prix moyen)
last_fill_price = self.pairs[trade.pair]['last_buy'] # trade.open_rate # remplacé juste après ↓
last_fill_price = self.pairs[trade.pair]['last_price'] # trade.open_rate # remplacé juste après ↓
# if len(trade.orders) > 0:
# # On cherche le dernier BUY exécuté
@@ -1287,8 +1293,9 @@ class FrictradeLearning(IStrategy):
# FIN ########################## ALGO ATH
force = False #hours > self.hours_force.value and last_candle[self.indic_1h_force_buy.value] > 0
condition = last_candle['percent'] > 0 and last_candle['sma24_deriv1'] > 0 \
and last_candle['close'] < self.pairs[pair]['first_buy']
condition = last_candle['percent'] > 0 \
and ((count_of_buys <= 4 and last_candle['sma24_deriv1'] > 0) or (count_of_buys > 4 and last_candle['sma60_deriv1'] > 0))\
and last_candle['close'] < self.pairs[pair]['first_price']
if ((force or decline >= dca_threshold) and condition):
try:
@@ -1321,7 +1328,7 @@ class FrictradeLearning(IStrategy):
stake=round(stake_amount, 2)
)
self.pairs[trade.pair]['last_buy'] = current_rate
self.pairs[trade.pair]['last_price'] = current_rate
self.pairs[trade.pair]['max_touch'] = last_candle['close']
self.pairs[trade.pair]['last_candle'] = last_candle
@@ -1329,7 +1336,7 @@ class FrictradeLearning(IStrategy):
# colonnes_a_exclure = ['last_candle', 'stop',
# 'trade_info', 'last_date', 'expected_profit', 'last_count_of_buys', 'base_stake_amount', 'stop_buy']
# df_filtered = df[df['count_of_buys'] > 0].drop(columns=colonnes_a_exclure)
# # df_filtered = df_filtered["first_buy", "last_max", "max_touch", "last_sell","last_buy", 'count_of_buys', 'current_profit']
# # df_filtered = df_filtered["first_price", "last_max", "max_touch", "last_sell","last_price", 'count_of_buys', 'current_profit']
#
# self.printLog(df_filtered)
@@ -1365,7 +1372,7 @@ class FrictradeLearning(IStrategy):
buys=trade.nr_of_successful_entries + 1,
stake=round(stake_amount, 2)
)
self.pairs[trade.pair]['last_buy'] = current_rate
self.pairs[trade.pair]['last_price'] = current_rate
self.pairs[trade.pair]['max_touch'] = last_candle['close']
self.pairs[trade.pair]['last_candle'] = last_candle
return stake_amount
@@ -1417,8 +1424,8 @@ class FrictradeLearning(IStrategy):
self.pairs[pair]['current_profit'] = profit
dispo = round(self.wallets.get_available_stake_amount())
# 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_since_first_price = (current_time - trade.open_date_utc).seconds / 3600.0
# days_since_first_price = (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
@@ -1432,9 +1439,9 @@ class FrictradeLearning(IStrategy):
current_trailing_only_offset_is_reached = self.trailing_only_offset_is_reached
current_trailing_stop_positive_offset = self.trailing_stop_positive_offset
current_trailing_stop_positive_offset = self.dynamic_trailing_offset(price=current_rate,
current_trailing_stop_positive_offset = self.dynamic_trailing_offset(pair, price=current_rate,
ath=self.pairs[pair]['last_ath'],
nb_entries=count_of_buys)
count_of_buys=count_of_buys)
# max_ = last_candle['max180']
# min_ = last_candle['min180']