synchronise HeikinAshi

This commit is contained in:
Jérôme Delacotte
2025-03-22 17:54:06 +01:00
parent 59daa1af70
commit 117d466722
3 changed files with 478 additions and 250 deletions

View File

@@ -32,23 +32,14 @@ from ta.utils import dropna
import freqtrade.vendor.qtpylib.indicators as qtpylib
from functools import reduce
import numpy as np
from scipy.special import binom
from ta.trend import SMAIndicator, EMAIndicator, MACD, ADXIndicator
from ta.momentum import RSIIndicator, StochasticOscillator
class HeikinAshi(IStrategy):
plot_config = {
"main_plot": {
"min12": {
"color": "#197260"
},
'max12': {
'color': 'green'
},
"haclose": {
"color": "red"
},
'haopen': {
'color': 'blue'
},
"min288": {
"color": "#197260"
},
@@ -57,13 +48,47 @@ class HeikinAshi(IStrategy):
},
'mid288': {
'color': 'blue'
}
},
'hasma5': {
'color': 'red'
},
'max48': {
'color': 'yellow'
},
'min48': {
'color': 'yellow'
},
'sma12': {
'color': 'pink'
},
'ema5_1d': {
'color': "#74effc"
},
'ema20_1d': {
'color': "cyan"
},
},
"subplots": {
"Percent": {
"hapercent": {
"color": "#74effc"
}
},
'up_down': {
'up_pct': {
'color': 'red'
},
'down_pct': {
'color': 'blue'
}
},
'tag': {
'rsi_downtrend': {
'color': 'red'
},
'ma_downtrend': {
'color': 'blue'
}
}
}
@@ -92,7 +117,7 @@ class HeikinAshi(IStrategy):
# Optimal timeframe use it in your config
timeframe = '5m'
columns_logged = False
max_entry_position_adjustment = 20
max_entry_position_adjustment = 30
startup_candle_count = 288
# Trailing stoploss
@@ -100,7 +125,7 @@ class HeikinAshi(IStrategy):
# trailing_stop_positive = 0.001
# trailing_stop_positive_offset = 0.015
# trailing_only_offset_is_reached = True
position_adjustment_enable = False
position_adjustment_enable = True
pairs = {
pair: {
@@ -108,12 +133,18 @@ class HeikinAshi(IStrategy):
"trade_info": {},
"max_touch": 0.0,
"last_sell": 0.0,
"last_buy": 0.0
"last_buy": 0.0,
'count_of_buys': 0,
'current_profit': 0,
'expected_profit': 0,
"last_candle": {},
"last_trade": None,
'base_stake_amount': 0
}
for pair in ["BTC/USDT", "ETH/USDT", "DOGE/USDT", "DASH/USDT", "XRP/USDT", "SOL/USDT"]
}
decalage = IntParameter(0, 48, default=12, space='buy')
decalage = IntParameter(0, 10, default=3, space='buy')
########################################## END RESULT PASTE PLACE #####################################
# ------------------------------------------------------------------------------------------------------------------
@@ -125,26 +156,95 @@ class HeikinAshi(IStrategy):
**kwargs
) -> Union[Optional[float], Tuple[Optional[float], Optional[str]]]:
# ne rien faire si ordre deja en cours
if trade.has_open_orders:
return None
if (self.wallets.get_available_stake_amount() < 50): # or trade.stake_amount >= max_stake:
return 0
dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe)
last_candle = dataframe.iloc[-1].squeeze()
last_candle_24 = dataframe.iloc[-25].squeeze()
# last_candle_decalage = dataframe.iloc[-1 - self.decalage.value].squeeze()
# last_candle_24 = dataframe.iloc[-25].squeeze()
# if (last_candle['sma5_diff_1d'] < -0.1):
# return None
# prépare les données
count_of_buys = trade.nr_of_successful_entries
current_time = current_time.astimezone(timezone.utc)
open_date = trade.open_date.astimezone(timezone.utc)
dispo = round(self.wallets.get_available_stake_amount())
hours = (current_time - trade.date_last_filled_utc).total_seconds() / 3600.0
limit_buy = 4
# if (current_profit > 0.008) \
# and (last_candle['up_pct'] >= 1)\
# and (last_candle['volume'] >= 250) \
# and (hours >= 1):
# additional_stake = self.config['stake_amount']
# self.log_trade(
# last_candle=last_candle,
# date=current_time,
# action="Gain +",
# dispo=dispo,
# pair=trade.pair,
# rate=current_rate,
# trade_type='Increase',
# profit=round(current_profit, 4), # round(current_profit * trade.stake_amount, 2),
# buys=trade.nr_of_successful_entries,
# stake=round(additional_stake, 2)
# )
# # self.pairs[trade.pair]['last_max'] = last_candle['haclose']
# self.pairs[trade.pair]['max_touch'] = last_candle['haclose']
# return additional_stake
# if (last_candle['percent'] > 0.001) and (current_profit > 0):
# # and (last_candle_decalage['min12'] == last_candle['min12']) \
# # and (last_candle_decalage['close'] < last_candle_decalage['mid288']):
# additional_stake = self.config['stake_amount'] / 10
# self.log_trade(
# last_candle=last_candle,
# date=current_time,
# action="Gain +",
# dispo=dispo,
# pair=trade.pair,
# rate=current_rate,
# trade_type='Increase',
# profit=round(current_profit, 4), # round(current_profit * trade.stake_amount, 2),
# buys=trade.nr_of_successful_entries,
# stake=round(additional_stake, 2)
# )
# return additional_stake
max_touch = self.pairs[trade.pair]['max_touch']
pct_max = - round(100 * (last_candle['close'] - max_touch) / max_touch, 1)
# if (last_candle['enter_long'] == 1) and (current_profit < - 0.0075 or hours >= 1) and (count_of_buys == 1):
# additional_stake = self.config['stake_amount'] / 2
# self.log_trade(
# last_candle=last_candle,
# date=current_time,
# action="Long",
# dispo=dispo,
# pair=trade.pair,
# rate=current_rate,
# trade_type='Increase',
# profit=round(current_profit, 4), # round(current_profit * trade.stake_amount, 2),
# buys=trade.nr_of_successful_entries + 1,
# stake=round(additional_stake, 2)
# )
# self.expectedProfit(trade.pair, last_candle, current_rate)
# 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 additional_stake
limit_buy = 5
if (count_of_buys < limit_buy) \
and (last_candle['min288'] == last_candle_24['min288']) \
and (current_profit < -0.01 * count_of_buys) \
and (last_candle['close'] < last_candle['mid288']):
additional_stake = self.config['stake_amount']
and ((last_candle['enter_long'] == 1)) \
and (current_profit < -0.015 * count_of_buys):
# and (last_candle_decalage['min12'] == last_candle['min12']) \
# and (last_candle_decalage['close'] < last_candle_decalage['mid288']):
additional_stake = self.calculate_stake(trade.pair, last_candle, 1) # self.config['stake_amount']
self.log_trade(
last_candle=last_candle,
date=current_time,
@@ -154,12 +254,39 @@ class HeikinAshi(IStrategy):
rate=current_rate,
trade_type='Decrease',
profit=round(current_profit, 4), # round(current_profit * trade.stake_amount, 2),
buys=trade.nr_of_successful_entries,
buys=trade.nr_of_successful_entries + 1,
stake=round(additional_stake, 2)
)
self.expectedProfit(trade.pair, last_candle, current_rate)
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 additional_stake
if (count_of_buys >= limit_buy) & (current_profit < - 0.03 * count_of_buys):
additional_stake = self.config['stake_amount'] * 2
# if (count_of_buys == limit_buy) & (current_profit < - 0.03 * count_of_buys)\
# and ((last_candle['enter_long'] == 1) or last_candle['percent48'] < - 0.03):
# additional_stake = - trade.stake_amount / 2 #self.config['stake_amount'] * (-current_profit / 0.10)
# self.log_trade(
# last_candle=last_candle,
# date=current_time,
# action="Loss -",
# dispo=dispo,
# pair=trade.pair,
# rate=current_rate,
# trade_type='Decrease',
# profit=round(current_profit, 4), # round(current_profit * trade.stake_amount, 2),
# buys=trade.nr_of_successful_entries,
# stake=round(additional_stake, 2)
# )
# # self.pairs[trade.pair]['last_max'] = last_candle['haclose']
# self.pairs[trade.pair]['max_touch'] = last_candle['haclose']
# return additional_stake
pct_limit = (-0.015 * limit_buy) + (- 0.03 * (count_of_buys - limit_buy))
if (count_of_buys >= limit_buy) & (current_profit < pct_limit) \
and ((last_candle['enter_long'] == 1) or last_candle['percent48'] < - 0.03):
additional_stake = self.calculate_stake(trade.pair, last_candle, 1) * (-current_profit / 0.10)
self.log_trade(
last_candle=last_candle,
date=current_time,
@@ -169,15 +296,49 @@ class HeikinAshi(IStrategy):
rate=current_rate,
trade_type='Decrease',
profit=round(current_profit, 4), # round(current_profit * trade.stake_amount, 2),
buys=trade.nr_of_successful_entries,
buys=trade.nr_of_successful_entries + 1,
stake=round(additional_stake, 2)
)
self.expectedProfit(trade.pair, last_candle, current_rate)
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 additional_stake
return None
def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float,
proposed_stake: float, min_stake: float, max_stake: float,
**kwargs) -> float:
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
# Obtenir les données actuelles pour cette paire
last_candle = dataframe.iloc[-1].squeeze()
stake_amount = self.config['stake_amount']
# if last_candle['close'] < last_candle['max5_1d'] * 0.98 :
# stake_amount = 2 * stake_amount
# else:
# if last_candle['close'] > last_candle['max5_1d'] * 1.02:
# stake_amount = 0.5 * stake_amount
# if last_candle['entry_tag'] == 'buy_hammer':
# stake_amount = stake_amount * 2
return stake_amount
def calculate_stake(self, pair, last_candle, factor=1):
amount = self.config['stake_amount'] * factor #1000 / self.first_stack_factor.value self.protection_stake_amount.value #
# if self.pairs[pair]['count_of_buys'] == 1 and factor == 1:
# if last_candle['close'] > last_candle['min5_1d'] + (last_candle['max5_1d'] - last_candle['min5_1d']) / 2:
# factor = 0.5
# amount = self.config['stake_amount'] * factor
# else:
# amount = self.config['stake_amount']
# self.pairs[pair]['base_stake_amount'] = amount
# else:
# amount = max(self.config['stake_amount'], self.pairs[pair]['base_stake_amount'])
amount = self.config['stake_amount']
return amount
def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float, time_in_force: str,
@@ -185,8 +346,32 @@ class HeikinAshi(IStrategy):
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
last_candle = dataframe.iloc[-1].squeeze()
dispo = round(self.wallets.get_available_stake_amount())
# if (self.pairs[pair]['last_sell'] > 0) and (last_candle['close'] * 1.01 > self.pairs[pair]['last_sell']):
# self.log_trade(
# last_candle=last_candle,
# date=current_time,
# action="CANCEL BUY",
# pair=pair,
# rate=rate,
# dispo=dispo,
# profit=0,
# stake=round(stake_amount, 2)
# )
# return False
self.pairs[pair]['last_buy'] = rate
self.pairs[pair]['max_touch'] = last_candle['close']
self.pairs[pair]['last_max'] = last_candle['close']
self.pairs[pair]['last_candle'] = last_candle
self.pairs[pair]['count_of_buys'] = 1
self.pairs[pair]['current_profit'] = 0
stake_amount = self.calculate_stake(pair, last_candle, 1)
# self.columns_logged = False
print(
f"|{'-' * 18}+{'-' * 12}+{'-' * 12}+{'-' * 20}+{'-' * 14}+{'-' * 8}+{'-' * 10}+{'-' * 7}+{'-' * 13}+{'-' * 14}+{'-' * 14}+{'-' * 7}+{'-' * 12}|"
)
self.log_trade(
last_candle=last_candle,
date=current_time,
@@ -195,8 +380,11 @@ class HeikinAshi(IStrategy):
rate=rate,
dispo=dispo,
profit=0,
trade_type=entry_tag,
buys=1,
stake=round(stake_amount, 2)
)
self.expectedProfit(pair, last_candle, rate)
return True
def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float, rate: float,
@@ -210,10 +398,9 @@ class HeikinAshi(IStrategy):
allow_to_sell = (last_candle['percent5'] < -0.00)
ok = (allow_to_sell) | (exit_reason == 'force_exit')
if ok:
# self.pairs[pair]['last_max'] = 0
# self.pairs[pair]['max_touch'] = 0
self.pairs[pair]['last_buy'] = 0
self.pairs[pair]['last_sell'] = rate
self.pairs[pair]['last_trade'] = trade
self.pairs[pair]['last_candle'] = last_candle
self.log_trade(
last_candle=last_candle,
date=current_time,
@@ -224,7 +411,11 @@ class HeikinAshi(IStrategy):
dispo=dispo,
profit=round(trade.calc_profit(rate, amount), 2)
)
#print(f"Sell {current_time} {exit_reason} rate={rate:.3f} amount={amount} profit={amount * rate:.3f}")
self.pairs[pair]['last_max'] = 0
self.pairs[pair]['max_touch'] = 0
self.pairs[pair]['last_buy'] = 0
# print(f"Sell {current_time} {exit_reason} rate={rate:.3f} amount={amount} profit={amount * rate:.3f}")
return ok
@@ -232,23 +423,94 @@ class HeikinAshi(IStrategy):
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
last_candle = dataframe.iloc[-1].squeeze()
before_last_candle = dataframe.iloc[-2].squeeze()
if (current_profit > 0.004) \
& (last_candle['hapercent'] < 0.0) \
& (last_candle['percent'] < 0.0):
count_of_buys = trade.nr_of_successful_entries
return 'profit_' + str(count_of_buys)
max_touch_before = self.pairs[pair]['max_touch']
last_max_before = self.pairs[pair]['last_max']
self.pairs[pair]['last_max'] = max(last_candle['haclose'], self.pairs[pair]['last_max'])
def log_trade(self, action, pair, date, trade_type=None, rate=None, dispo=None, profit=None, buys=None, stake=None, last_candle=None):
last_lost = (last_candle['close'] - max_touch_before) / max_touch_before
count_of_buys = trade.nr_of_successful_entries
self.pairs[pair]['count_of_buys'] = count_of_buys
self.pairs[pair]['current_profit'] = current_profit
days = (current_time - trade.open_date_utc).days
days = max(1, days)
factor = 1
# if days > 10:
# factor = 1 + days / 10
expected_profit = self.pairs[pair]['expected_profit'] / factor
# print(
# f"{current_time} days={days} expected={expected_profit:.3f} rate={current_rate} max_touch={max_touch_before:.1f} profit={current_profit:.3f} last_lost={last_lost:.3f} buys={count_of_buys} percent={last_candle['percent']:.4f}")
if (current_profit > expected_profit) \
& (last_candle['percent'] < 0.0) \
& (last_lost > - current_profit / 5):
# & (before_last_candle['hasma5'] < last_candle['hasma5']):
# & (last_lost < min(-0.003, - min(0.006, current_profit / 4))):
# & (last_candle['up_count'] > 0):
return 'last_lost_' + str(count_of_buys)
self.pairs[pair]['max_touch'] = max(last_candle['haclose'], self.pairs[pair]['max_touch'])
# if (current_profit > 0.004) \
# & (last_candle['hapercent'] < 0.0) \
# & (last_candle['percent3'] < - min(0.01, current_profit / 4)):
# return 'profit_' + str(count_of_buys)
def detect_loose_hammer(self, df: DataFrame) -> DataFrame:
"""
Détection large de marteaux : accepte des corps plus gros, ne vérifie pas le volume,
ne demande pas de divergence, juste un pattern visuel simple.
"""
body = abs(df['close'] - df['open'])
upper_shadow = abs(df['high'] - np.maximum(df['close'], df['open']))
lower_shadow = abs(np.minimum(df['close'], df['open']) - df['low'])
# Critères simplifiés :
df['loose_hammer'] = (
(lower_shadow > body * 2.5) # mèche basse > 1.5x corps
& (upper_shadow < body) # petite mèche haute
& (df['low'] < df['bb_lowerband']) # bougie verte (optionnel, on peut prendre aussi les rouges)
).astype(int)
df['won_hammer'] = (
(upper_shadow > body * 2.5) # mèche basse > 1.5x corps
& (lower_shadow < body) # petite mèche haute
& (df['high'] > df['bb_upperband']) # bougie verte (optionnel, on peut prendre aussi les rouges)
).astype(int)
return df
def expectedProfit(self, pair: str, last_candle, current_rate):
last_buy = self.pairs[pair]['last_buy']
max_touch = self.pairs[pair]['max_touch']
last_max = self.pairs[pair]['last_max']
expected_profit = ((max_touch - last_buy) / max_touch)
self.pairs[pair]['expected_profit'] = max(0.004, expected_profit)
# print(f"expected max_touch={max_touch:.1f} last_buy={last_buy:.1f} expected={expected_profit:.3f} max5_1d={last_candle['max5_1d']:.1f}")
return expected_profit
def log_trade(self, action, pair, date, trade_type=None, rate=None, dispo=None, profit=None, buys=None, stake=None,
last_candle=None):
# Afficher les colonnes une seule fois
if self.config.get('runmode') == 'hyperopt':
return
if self.columns_logged % 30 == 0:
# print(
# f"|{'-' * 18}+{'-' * 12}+{'-' * 12}+{'-' * 20}+{'-' * 14}+{'-' * 8}+{'-' * 10}+{'-' * 7}+{'-' * 13}+{'-' * 14}+{'-' * 14}+{'-' * 7}+{'-' * 12}|"
# )
print(
f"| {'Date':<16} | {'Action':<10} | {'Pair':<10} | {'Trade Type':<18} | {'Rate':>12} | {'Dispo':>6} | {'Profit':>8} | {'Pct':>5} | {'max7_1d':>11} | {'max_touch':>12} | {'last_max':>12} | {'Buys':>5} | {'Stake':>10} |"
f"| {'Date':<16} | {'Action':<10} | {'Pair':<10} | {'Trade Type':<18} | {'Rate':>12} | {'Dispo':>6} | {'Profit':>8} | {'Pct':>5} | {'max_touch':>11} | {'last_lost':>12} | {'last_max':>12} | {'Buys':>5} | {'Stake':>10} |"
)
print(
f"|{'-' * 18}|{'-' * 12}|{'-' * 12}|{'-' * 20}|{'-' * 14}|{'-' * 8}|{'-' * 10}|{'-' * 7}|{'-' * 13}|{'-' * 14}|{'-' * 14}|{'-' * 7}|{'-' * 12}|"
f"|{'-' * 18}+{'-' * 12}+{'-' * 12}+{'-' * 20}+{'-' * 14}+{'-' * 8}+{'-' * 10}+{'-' * 7}+{'-' * 13}+{'-' * 14}+{'-' * 14}+{'-' * 7}+{'-' * 12}|"
)
self.columns_logged += 1
date = str(date)[:16] if date else "-"
@@ -279,28 +541,46 @@ class HeikinAshi(IStrategy):
# if action != 'Sell':
# profit = round((last_candle['close'] - self.pairs[pair]['last_max']) / self.pairs[pair]['last_max'], 2)
last_lost = round((last_candle['haclose'] - self.pairs[pair]['max_touch']) / self.pairs[pair]['max_touch'], 3)
limit_sell = rsi_pct # round((last_candle['close'] - self.pairs[pair]['last_max']) / self.pairs[pair]['last_max'], 4)
max7_1d = round(self.pairs[pair]['max_touch'], 1) #last_candle['max7_1d'] #round(100 * (last_candle['close'] - self.pairs[pair]['last_max']) / self.pairs[pair]['last_max'], 1)
pct_max = round(100 * (last_candle['close'] - max7_1d) / max7_1d, 1)
max_touch = round(self.pairs[pair]['max_touch'],
1) # last_candle['max7_1d'] #round(100 * (last_candle['close'] - self.pairs[pair]['last_max']) / self.pairs[pair]['last_max'], 1)
pct_max = round(100 * self.pairs[pair]['current_profit'],
1) # round(100 * (last_candle['close'] - max_touch) / max_touch, 1)
if trade_type is not None:
trade_type = trade_type + " " + str(round(100 * self.pairs[pair]['expected_profit'], 1))
print(
f"| {date:<16} | {action:<10} | {pair:<10} | {trade_type or '-':<18} | {rate or '-':>12} | {dispo or '-':>6} | {profit or '-':>8} | {pct_max or '-':>5} | {max7_1d or '-':>11} | {round(self.pairs[pair]['max_touch'], 2) or '-':>12} | {round(self.pairs[pair]['last_max'],2) or '-':>12} | {buys or '-':>5} | {stake or '-':>10} |"
f"| {date:<16} | {action:<10} | {pair:<10} | {trade_type or '-':<18} | {rate or '-':>12} | {dispo or '-':>6} | {profit or '-':>8} | {pct_max or '-':>5} | {max_touch or '-':>11} | {last_lost or '-':>12} | {round(self.pairs[pair]['last_max'], 2) or '-':>12} | {self.pairs[pair]['count_of_buys'] or '-':>5} | {stake or '-':>10} |"
)
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
heikinashi = qtpylib.heikinashi(dataframe)
dataframe['haopen'] = heikinashi['open']
dataframe['haclose'] = heikinashi['close']
dataframe['hamid'] = dataframe['haclose'] + (dataframe['haopen'] - dataframe['haclose']) / 2
dataframe['mid'] = dataframe['open'] + (dataframe['close'] - dataframe['open']) / 2
dataframe['sma12'] = dataframe['mid'].rolling(12).sum() / 12
dataframe['hasma5'] = dataframe['hamid'].rolling(5).sum() / 5
dataframe['hasma5_diff'] = dataframe['hasma5'] - dataframe['hasma5'].shift(1)
dataframe['halow'] = heikinashi['low']
dataframe['hapercent'] = (dataframe['haclose'] - dataframe['haopen']) / dataframe['haclose']
dataframe['min12'] = talib.MIN(dataframe['close'], timeperiod=12)
dataframe['max12'] = talib.MAX(dataframe['close'], timeperiod=12)
dataframe['min48'] = talib.MIN(dataframe['close'], timeperiod=48)
dataframe['max48'] = talib.MAX(dataframe['close'], timeperiod=48)
dataframe['min288'] = talib.MIN(dataframe['close'], timeperiod=288)
dataframe['max288'] = talib.MAX(dataframe['close'], timeperiod=288)
dataframe['mid288'] = dataframe['min288'] + (dataframe['max288'] - dataframe['min288']) / 2
dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"]
dataframe["percent3"] = dataframe['close'].pct_change(3)
dataframe["percent5"] = dataframe['close'].pct_change(5)
dataframe["percent12"] = dataframe['close'].pct_change(12)
dataframe["percent48"] = dataframe['close'].pct_change(48)
# Bollinger Bands
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
@@ -309,26 +589,95 @@ class HeikinAshi(IStrategy):
dataframe['bb_upperband'] = bollinger['upper']
dataframe['bb_diff'] = (dataframe['bb_upperband'] - dataframe['bb_lowerband']) / dataframe['bb_lowerband']
# Compter les baisses consécutives
dataframe['down'] = dataframe['hapercent'] <= 0.001
dataframe['up'] = dataframe['hapercent'] >= -0.001
dataframe['down_count'] = - dataframe['down'].astype(int) * (
dataframe['down'].groupby((dataframe['down'] != dataframe['down'].shift()).cumsum()).cumcount() + 1)
dataframe['up_count'] = dataframe['up'].astype(int) * (
dataframe['up'].groupby((dataframe['up'] != dataframe['up'].shift()).cumsum()).cumcount() + 1)
dataframe['down_tag'] = (dataframe['down_count'] < -7)
dataframe['up_tag'] = (dataframe['up_count'] > 7)
# Créer une colonne vide
dataframe['down_pct'] = self.calculateUpDownPct(dataframe, 'down_count')
dataframe['up_pct'] = self.calculateUpDownPct(dataframe, 'up_count')
# # ======================================================================================Decrease
# ################### INFORMATIVE 1d
informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d")
# # Moving Averages
# informative['ema5'] = EMAIndicator(informative['close'], window=5).ema_indicator()
# informative['ema20'] = EMAIndicator(informative['close'], window=20).ema_indicator()
# informative['ma_downtrend'] = (informative['close'] < informative['ema5']) & (informative['ema5'] < informative['ema20'])
#
# # RSI
# informative['rsi'] = RSIIndicator(informative['close'], window=14).rsi()
# informative['rsi_downtrend'] = informative['rsi'] < 50
informative['max5'] = talib.MAX(informative['close'], timeperiod=5)
informative['max12'] = talib.MAX(informative['close'], timeperiod=12)
informative['min5'] = talib.MIN(informative['close'], timeperiod=5)
informative['min12'] = talib.MIN(informative['close'], timeperiod=12)
informative['sma5'] = talib.SMA(informative, timeperiod=25)
informative['sma5_diff'] = 100 * (informative['sma5'] - informative['sma5'].shift(1)) / informative['sma5']
# informative = self.detect_loose_hammer(informative)
dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True)
dataframe = self.detect_loose_hammer(dataframe)
return dataframe
def calculateUpDownPct(self, dataframe, key):
down_pct_values = np.full(len(dataframe), np.nan)
# Remplir la colonne avec les bons calculs
for i in range(len(dataframe)):
shift_value = abs(int(dataframe[key].iloc[i])) # Récupérer le shift actuel
if i - shift_value > 1: # Vérifier que le shift ne dépasse pas l'index
down_pct_values[i] = 100 * (dataframe['close'].iloc[i] - dataframe['close'].iloc[i - shift_value]) / \
dataframe['close'].iloc[i - shift_value]
return down_pct_values
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Buy strategy Hyperopt will build and use.
"""
d = self.decalage.value
# dataframe.loc[
# (dataframe['halow'] <= dataframe['min12'])
# (dataframe['halow'].shift(d) <= dataframe['min12'].shift(d))
# & (dataframe['min12'].shift(d) == dataframe['min12'])
# # & (dataframe['close'] < dataframe['hasma5'])
# # & (dataframe['bb_diff'] > 0.01)
# ,
# ['enter_long', 'enter_tag']] = [1, 'buy_halow']
# dataframe.loc[
# (dataframe['hasma5_diff'].shift(2) >= dataframe['hasma5_diff'].shift(1))
# & (dataframe['hasma5_diff'].shift(1) <= dataframe['hasma5_diff'])
# # & (dataframe['bb_diff'] > 0.01)
# ,
# ['enter_long', 'enter_tag']] = [1, 'buy_hasma5_diff']
# dataframe.loc[
# (dataframe['halow'].shift(decalage) <= dataframe['min288'].shift(decalage))
# # & (dataframe['min288'].shift(decalage) == dataframe['min288'])
# # & (dataframe['open'] <= dataframe['bb_middleband'])
# # & (dataframe['bb_diff'] > 0.01)
# ,
# 'buy']=1
decalage = 3
dataframe.loc[
(dataframe['halow'].shift(decalage) <= dataframe['min288'].shift(decalage))
& (dataframe['min288'].shift(decalage) == dataframe['min288'])
# & (dataframe['open'] <= dataframe['bb_middleband'])
# & (dataframe['bb_diff'] > 0.01)
(
(dataframe['down_count'].shift(1) <= -8)
| (dataframe['percent12'] <= -0.012)
)
& (dataframe['down_count'] == 0)
,
'buy']=1
['enter_long', 'enter_tag']] = [1, 'buy_down']
dataframe.loc[(dataframe['loose_hammer'] == 1)
,
['enter_long', 'enter_tag']] = [1, 'buy_hammer']
return dataframe
@@ -340,3 +689,11 @@ class HeikinAshi(IStrategy):
# (qtpylib.crossed_above(dataframe['haclose'], dataframe['haopen'])),
# 'sell']=1
return dataframe
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 informative_pairs