Frictrade
This commit is contained in:
57
Frictrade.py
57
Frictrade.py
@@ -41,7 +41,7 @@ RESET = "\033[0m"
|
||||
|
||||
|
||||
class Frictrade(IStrategy):
|
||||
startup_candle_count = 60 * 24
|
||||
startup_candle_count = 180
|
||||
|
||||
# ROI table:
|
||||
minimal_roi = {
|
||||
@@ -103,6 +103,19 @@ class Frictrade(IStrategy):
|
||||
trades = list()
|
||||
max_profit_pairs = {}
|
||||
|
||||
btc_ath_history = [
|
||||
{"date": "2011-06-09", "price_usd": 26.15, "note": "pic 2011 (early breakout)"},
|
||||
{"date": "2013-11-29", "price_usd": 1132.00, "note": "bull run fin 2013"},
|
||||
{"date": "2017-12-17", "price_usd": 19783.00, "note": "ATH décembre 2017 (crypto bubble)"},
|
||||
{"date": "2020-12-31", "price_usd": 29001.72, "note": "fin 2020, nouveau record après accumulation)"},
|
||||
{"date": "2021-11-10", "price_usd": 68742.00, "note": "record novembre 2021 (institutional demand)"},
|
||||
{"date": "2024-03-05", "price_usd": 69000.00,
|
||||
"note": "nouveau pic début 2024 (source presse, valeur indicative)"},
|
||||
{"date": "2025-07-11", "price_usd": 118755.00, "note": "pic juillet 2025 (valeur rapportée par la presse)"},
|
||||
{"date": "2025-10-06", "price_usd": 126198.07,
|
||||
"note": "pic oct. 2025 (source agrégée, à vérifier selon l'exchange)"}
|
||||
]
|
||||
|
||||
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:
|
||||
|
||||
@@ -292,7 +305,7 @@ class Frictrade(IStrategy):
|
||||
if self.columns_logged % 10 == 0:
|
||||
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_max':>7}|{'Buys':>5}| {'Stake':>5} |"
|
||||
f"| {'Pct':>6} | {'max_touch':>11} | {'last_lost':>12} | {'last_max':>7}| {'last_min':>7}|{'Buys':>5}| {'Stake':>5} |"
|
||||
f"{'rsi':>6}" #|Distmax|s201d|s5_1d|s5_2d|s51h|s52h|smt1h|smt2h|tdc1d|tdc1h"
|
||||
)
|
||||
self.printLineLog()
|
||||
@@ -539,13 +552,18 @@ class Frictrade(IStrategy):
|
||||
# return adjusted_stake_amount
|
||||
|
||||
def adjust_stake_amount(self, pair: str, last_candle: DataFrame):
|
||||
|
||||
ath = max(self.pairs[pair]['last_max'], self.get_last_ath_before_candle(last_candle))
|
||||
|
||||
ath_dist = 100 * (ath - last_candle["mid"]) / ath
|
||||
|
||||
# Calcule max/min 180
|
||||
low180 = last_candle["min180"]
|
||||
high180 = last_candle["max180"]
|
||||
|
||||
mult = 1 - ((last_candle["mid"] - low180) / (high180 - low180))
|
||||
|
||||
print(f"low={low180} mid={last_candle['mid']} high={high180} mult={mult}")
|
||||
print(f"low={low180} mid={last_candle['mid']} high={high180} mult={mult} ath={ath} ath_dist={round(ath_dist, 2)}" )
|
||||
# base_size = montant de base que tu veux utiliser (ex: stake_amount ou autre)
|
||||
base_size = 2 * self.config.get('stake_amount') # exemple fraction du portefeuille; adapte selon ton code
|
||||
# new stake proportionnel à mult
|
||||
@@ -612,7 +630,7 @@ class Frictrade(IStrategy):
|
||||
# stake_amount = last_amount * current_rate * 0.5
|
||||
# return stake_amount
|
||||
|
||||
condition = last_candle['hapercent'] > 0 and last_candle['sma60_deriv1'] > 0
|
||||
condition = last_candle['hapercent'] > 0 and last_candle['sma24_deriv1'] > 0
|
||||
limit_buy = 40
|
||||
if decline >= dca_threshold and condition:
|
||||
try:
|
||||
@@ -760,11 +778,11 @@ class Frictrade(IStrategy):
|
||||
if zone == 0:
|
||||
current_trailing_stop_positive = self.trailing_stop_positive
|
||||
current_trailing_stop_positive_offset = self.trailing_stop_positive_offset * 2
|
||||
if minutes > 1440:
|
||||
current_trailing_only_offset_is_reached = False
|
||||
current_trailing_stop_positive_offset = self.trailing_stop_positive_offset
|
||||
# if zone == 1:
|
||||
|
||||
|
||||
if last_candle['sma24_deriv1'] > 0: # and last_candle['sma5_deriv1'] > -0.15:
|
||||
return None
|
||||
# ----- 5) Calcul du trailing stop dynamique -----
|
||||
# Exemple : offset=0.321 => stop à +24.8%
|
||||
|
||||
@@ -773,7 +791,7 @@ class Frictrade(IStrategy):
|
||||
if max_profit:
|
||||
baisse = (max_profit - profit) / max_profit
|
||||
|
||||
if minutes % 15 == 0:
|
||||
if minutes % 12 == 0:
|
||||
self.log_trade(
|
||||
last_candle=last_candle,
|
||||
date=current_time,
|
||||
@@ -781,12 +799,15 @@ class Frictrade(IStrategy):
|
||||
dispo=dispo,
|
||||
pair=pair,
|
||||
rate=last_candle['close'],
|
||||
trade_type=f"{round(profit, 2)} {round(max_profit, 2)} {round(trailing_stop,2)}",
|
||||
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['sma24_deriv1'] > 0 and minutes < 180: # and last_candle['sma5_deriv1'] > -0.15:
|
||||
return None
|
||||
|
||||
# ----- 4) OFFSET : faut-il attendre de dépasser trailing_stop_positive_offset ? -----
|
||||
if current_trailing_only_offset_is_reached:
|
||||
# Max profit pas atteint ET perte < 2 * current_trailing_stop_positive
|
||||
@@ -797,7 +818,7 @@ class Frictrade(IStrategy):
|
||||
|
||||
# ----- 6) Condition de vente -----
|
||||
if profit > 0 and profit <= trailing_stop and last_candle['mid'] < last_candle['sma5']:
|
||||
return f"stop_{count_of_buys}"
|
||||
return f"stop_{count_of_buys}_{self.pairs[pair]['has_gain']}"
|
||||
return None
|
||||
|
||||
def informative_pairs(self):
|
||||
@@ -892,3 +913,19 @@ class Frictrade(IStrategy):
|
||||
|
||||
return dataframe
|
||||
|
||||
import pandas as pd
|
||||
|
||||
def to_utc_ts(self, x):
|
||||
return pd.to_datetime(x, utc=True)
|
||||
|
||||
# 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", []):
|
||||
ath_date = self.to_utc_ts(a["date"])
|
||||
if ath_date <= candle_date:
|
||||
if best is None or ath_date > best[0]:
|
||||
best = (ath_date, a["price_usd"])
|
||||
return best[1] if best is not None else None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user