Files
Freqtrade/GodStraJD3_7_5_6.py
Jérôme Delacotte 7c239227d8 first commit
2025-03-06 11:01:43 +01:00

899 lines
44 KiB
Python
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# GodStraNew Strategy
# Author: @Mablue (Masoud Azizi)
# github: https://github.com/mablue/
# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy roi trailing sell --strategy GodStraNew
# --- Do not remove these libs ---
from datetime import timedelta, datetime
from typing import Optional
from freqtrade import data
from freqtrade.persistence import Trade
from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter
from numpy.lib import math
from freqtrade.strategy.interface import IStrategy
import pandas
from pandas import DataFrame
import time
import calendar
from freqtrade.loggers import setup_logging
from technical.indicators import cmf
from freqtrade.strategy.strategy_helper import merge_informative_pair
# --------------------------------
# Add your lib to import here
# TODO: talib is fast but have not more indicators
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
from functools import reduce
import numpy as np
from random import shuffle
operators = [
"D", # Disabled gene
">", # Indicator, bigger than cross indicator
"<", # Indicator, smaller than cross indicator
"=", # Indicator, equal with cross indicator
"C", # Indicator, crossed the cross indicator
"CA", # Indicator, crossed above the cross indicator
"CB", # Indicator, crossed below the cross indicator
">R", # Normalized indicator, bigger than real number
"=R", # Normalized indicator, equal with real number
"<R", # Normalized indicator, smaller than real number
"/>R", # Normalized indicator devided to cross indicator, bigger than real number
"/=R", # Normalized indicator devided to cross indicator, equal with real number
"/<R", # Normalized indicator devided to cross indicator, smaller than real number
"UT", # Indicator, is in UpTrend status
"DT", # Indicator, is in DownTrend status
"OT", # Indicator, is in Off trend status(RANGE)
"CUT", # Indicator, Entered to UpTrend status
"CDT", # Indicator, Entered to DownTrend status
"COT" # Indicator, Entered to Off trend status(RANGE)
]
# number of candles to check up,don,off trend.
TREND_CHECK_CANDLES = 8
DECIMALS = 2
buy_crossed_indicator0 = 'MINUS_DM-5'
buy_operator0 = "/<R"
buy_indicator0 = 'MA-20'
buy_crossed_indicator1 = 'DX-5'
buy_operator1 = ">"
buy_indicator1 = 'STOCH-1-10'
buy_crossed_indicator2 = 'LINEARREG-50'
buy_operator2 = "/<R"
buy_indicator2 = 'CDLDRAGONFLYDOJI-5'
def normalize(df):
df = (df-df.min())/(df.max()-df.min())
return df
def gene_calculator(dataframe, indicator):
# Cuz Timeperiods not effect calculating CDL patterns recognations
if 'CDL' in indicator:
splited_indicator = indicator.split('-')
splited_indicator[1] = "0"
new_indicator = "-".join(splited_indicator)
# print(indicator, new_indicator)
indicator = new_indicator
gene = indicator.split("-")
gene_name = gene[0]
gene_len = len(gene)
if indicator in dataframe.keys():
# print(f"{indicator}, calculated befoure")
# print(len(dataframe.keys()))
return dataframe[indicator]
else:
result = None
# For Pattern Recognations
if gene_len == 1:
# print('gene_len == 1\t', indicator)
result = getattr(ta, gene_name)(
dataframe
)
return normalize(result)
elif gene_len == 2:
# print('gene_len == 2\t', indicator)
gene_timeperiod = int(gene[1])
result = getattr(ta, gene_name)(
dataframe,
timeperiod=gene_timeperiod,
)
return normalize(result)
# For
elif gene_len == 3:
# print('gene_len == 3\t', indicator)
gene_timeperiod = int(gene[2])
gene_index = int(gene[1])
result = getattr(ta, gene_name)(
dataframe,
timeperiod=gene_timeperiod,
).iloc[:, gene_index]
return normalize(result)
# For trend operators(MA-5-SMA-4)
elif gene_len == 4:
# print('gene_len == 4\t', indicator)
gene_timeperiod = int(gene[1])
sharp_indicator = f'{gene_name}-{gene_timeperiod}'
dataframe[sharp_indicator] = getattr(ta, gene_name)(
dataframe,
timeperiod=gene_timeperiod,
)
return normalize(ta.SMA(dataframe[sharp_indicator].fillna(0), TREND_CHECK_CANDLES))
# For trend operators(STOCH-0-4-SMA-4)
elif gene_len == 5:
# print('gene_len == 5\t', indicator)
gene_timeperiod = int(gene[2])
gene_index = int(gene[1])
sharp_indicator = f'{gene_name}-{gene_index}-{gene_timeperiod}'
dataframe[sharp_indicator] = getattr(ta, gene_name)(
dataframe,
timeperiod=gene_timeperiod,
).iloc[:, gene_index]
return normalize(ta.SMA(dataframe[sharp_indicator].fillna(0), TREND_CHECK_CANDLES))
def condition_generator(dataframe, operator, indicator, crossed_indicator, real_num, decalage):
condition = (dataframe['volume'] > 10)
# TODO : it ill callculated in populate indicators.
dataframe[indicator] = gene_calculator(dataframe, indicator)
dataframe[crossed_indicator] = gene_calculator(dataframe, crossed_indicator)
indicator_trend_sma = f"{indicator}-SMA-{TREND_CHECK_CANDLES}"
if operator in ["UT", "DT", "OT", "CUT", "CDT", "COT"]:
dataframe[indicator_trend_sma] = gene_calculator(dataframe, indicator_trend_sma)
if operator == ">":
condition = (dataframe[indicator].shift(decalage) > dataframe[crossed_indicator].shift(decalage))
elif operator == "=":
condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage)))
elif operator == "<":
condition = (dataframe[indicator].shift(decalage) < dataframe[crossed_indicator].shift(decalage))
elif operator == "C":
condition = (
(qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage))) |
(qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage)))
)
elif operator == "CA":
condition = (qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage)))
elif operator == "CB":
condition = (qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[crossed_indicator].shift(decalage)))
elif operator == ">R":
condition = (dataframe[indicator].shift(decalage) > real_num)
elif operator == "=R":
condition = (np.isclose(dataframe[indicator].shift(decalage), real_num))
elif operator == "<R":
condition = (dataframe[indicator].shift(decalage) < real_num)
elif operator == "/>R":
condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) > real_num)
elif operator == "/=R":
condition = (np.isclose(dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)), real_num))
elif operator == "/<R":
condition = (dataframe[indicator].shift(decalage).div(dataframe[crossed_indicator].shift(decalage)) < real_num)
elif operator == "UT":
condition = (dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage))
elif operator == "DT":
condition = (dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage))
elif operator == "OT":
condition = (np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage)))
elif operator == "CUT":
condition = (
(
qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))
) &
(
dataframe[indicator].shift(decalage) > dataframe[indicator_trend_sma].shift(decalage)
)
)
elif operator == "CDT":
condition = (
(
qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))
) &
(
dataframe[indicator].shift(decalage) < dataframe[indicator_trend_sma].shift(decalage)
)
)
elif operator == "COT":
condition = (
(
(
qtpylib.crossed_below(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))
) |
(
qtpylib.crossed_above(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))
)
) &
(
np.isclose(dataframe[indicator].shift(decalage), dataframe[indicator_trend_sma].shift(decalage))
)
)
return condition, dataframe
class GodStraJD3_7_5_6(IStrategy):
# #################### RESULTS PASTE PLACE ####################
# ROI table:
minimal_roi = {
"0": 10,
# "600": 0.12,
# "1200": 0.08,
# "2400": 0.06,
# "3600": 0.04,
# "7289": 0
}
# Stoploss:
stoploss = -1
# Buy hypers
timeframe = '5m'
# Trailing stoploss
trailing_stop = False
trailing_stop_positive = 0.15
trailing_stop_positive_offset = 0.20
trailing_only_offset_is_reached = True
plot_config = {
# Main plot indicators (Moving averages, ...)
'main_plot': {
'bb_lowerband': {'color': 'red'},
'bb_upperband': {'color': 'green'},
'sma100': {'color': 'blue'},
'sma10': {'color': 'yellow'},
'min20': {'color': '#87e470'},
'min50': {'color': '#ac3e2a'},
"min1.1": {'color': 'yellow'},
'sma20': {'color': 'cyan'}
},
'subplots': {
# Subplots - each dict defines one additional plot
"BB": {
'bb_width': {'color': 'white'}
},
# "Ind0": {
# buy_crossed_indicator0: {'color': 'green'},
# buy_indicator0: {'color': 'red'}
# },
"Cond": {
'cond1': {'color': 'yellow'},
},
# "Ind1": {
# buy_indicator1: {'color': 'yellow'},
# buy_crossed_indicator1: {'color': 'pink'}
# },
# "Ind2": {
# buy_indicator2: {'color': 'cyan'},
# buy_crossed_indicator2: {'color': 'blue'},
# },
"Rsi": {
'rsi': {'color': 'pink'},
},
"Ecart": {
'normal_var_20': {'color': 'red'},
'normal_var_50': {'color': 'yellow'},
},
# "rolling": {
# 'bb_rolling': {'color': '#87e470'},
# "bb_rolling_min": {'color': '#ac3e2a'}
# },
"percent": {
"percent": {'color': 'green'},
"percent3": {'color': 'blue'},
"percent5": {'color': 'red'},
"distance_min": {'color': 'white'}
}
}
}
# #################### END OF RESULT PLACE ####################
profit_no_change = False
profit_old_sma10 = False
profit_over_rsi = True
profit_quick_gain = True
profit_quick_gain_3 = True
profit_quick_lost = False
profit_short_loss = False
profit_sma10 = True
profit_sma20 = True
profit_very_old_sma10 = False
trades = list()
# profit_no_change = BooleanParameter(default=True, space="buy")
# profit_quick_lost = BooleanParameter(default=True, space="buy")
# profit_sma10 = BooleanParameter(default=True, space="buy")
# profit_sma20 = BooleanParameter(default=True, space="buy")
# profit_quick_gain = BooleanParameter(default=True, space="buy")
# profit_quick_gain_3 = BooleanParameter(default=True, space="buy")
# profit_old_sma10 = BooleanParameter(default=True, space="buy")
# profit_very_old_sma10 = BooleanParameter(default=True, space="buy")
# profit_over_rsi = BooleanParameter(default=True, space="buy")
# profit_short_loss = BooleanParameter(default=True, space="buy")
# buy_signal_bb_width = DecimalParameter(0.06, 0.15, decimals=2, default=0.065, space='buy')
# buy_1_cond_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy')
# buy_2_cond_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy')
buy_3_cond_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy')
# buy_1_cond_1h_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy')
# buy_2_cond_1h_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy')
buy_3_cond_1h_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy')
buy_3_percent_1d_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy')
buy_3_percent_1w_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy')
# buy_1_real_num = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy')
# buy_2_real_num = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy')
buy_3_real_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy')
buy_min_horizon = IntParameter(50, 200, default=72, space='buy')
buy_0 = BooleanParameter(default=True, space="buy")
# buy_2 = BooleanParameter(default=True, space="buy")
buy_3 = BooleanParameter(default=True, space="buy")
buy_0_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy')
# buy_2_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy')
buy_3_percent20 = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.02, space='buy')
# buy_1_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy')
# buy_2_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy')
buy_3_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy')
# buy_1_cmf100_sup = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy')
# buy_2_cmf100_sup = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy')
buy_3_cmf100_sup = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy')
# buy_1_cmf100_inf = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy')
# buy_2_cmf100_inf = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy')
buy_3_cmf100_inf = DecimalParameter(-1, 1, decimals=1, default=0.0, space='buy')
# buy_1_min = DecimalParameter(1, 1.03, decimals=3, default=1.02, space='buy')
# buy_2_min = DecimalParameter(1, 1.03, decimals=3, default=1.02, space='buy')
buy_3_min = DecimalParameter(1, 1.03, decimals=3, default=1.02, space='buy')
# buy_1_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy')
# buy_2_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy')
buy_3_normal_var = DecimalParameter(0, 5, decimals=1, default=0, space='buy')
# buy_1_decalage_deb = IntParameter(1, 3, default=5, space='buy')
# buy_2_decalage_deb = IntParameter(1, 3, default=5, space='buy')
buy_3_decalage_deb = IntParameter(1, 3, default=5, space='buy')
# buy_1_decalage = IntParameter(buy_1_decalage_deb.value + 1, 8, default=5, space='buy')
# buy_2_decalage = IntParameter(# buy_2_decalage_deb.value + 1, 8, default=5, space='buy')
buy_3_decalage = IntParameter(buy_3_decalage_deb.value + 1, 8, default=5, space='buy')
buy_1_volume = IntParameter(0, 100, default=10, space='buy')
# buy_2_volume = IntParameter(0, 100, default=10, space='buy')
buy_3_volume = IntParameter(0, 100, default=10, space='buy')
protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection')
protection_stop = IntParameter(1, 100, default=48, space='protection')
protection_stoploss_stop = IntParameter(1, 100, default=48, space='protection')
lookback = IntParameter(1, 200, default=48, space='protection')
trade_limit = IntParameter(1, 10, default=2, space='protection')
inf_tf = '4h'
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=pair, timeframe=self.timeframe)
current_candle = dataframe.iloc[-1].squeeze()
# for decalage in range(self.buy_3_decalage_deb.value, self.buy_3_decalage.value):
# decalage_candle = dataframe.iloc[- decalage].squeeze()
# # if (decalage_candle['normal_var_20'] >= 0.6):
# amount = 10 * (- decalage_candle['percent20'] * 100)
# print("use more stake", pair, " ", amount)
# return min(max_stake, amount)
# print("proposed_stake=", proposed_stake, " max_stake=", max_stake)
# if current_candle['bb_width'] > 0.05:
# print("use more stake", pair, " ", proposed_stake * 2)
# return min(max_stake, proposed_stake * 2)
#
# if current_candle['bb_width'] > 0.035:
# print("use more stake", pair, " ", proposed_stake * 1.5)
# return min(max_stake, proposed_stake * 1.5)
# if current_candle['bb_width'] < 0.020:
# print("use less stake", pair, " ", proposed_stake / 2)
# return min(max_stake, proposed_stake / 2)
# if self.config['stake_amount'] == 'unlimited':
# # Use entire available wallet during favorable conditions when in compounding mode.
# return max_stake
# else:
# # Compound profits during favorable conditions instead of using a static stake.
# return self.wallets.get_total_stake_amount() / self.config['max_open_trades']
# Use default stake amount.
return proposed_stake
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:
# {'symbol': 'FTM/USDT', 'timestamp': 1646494199570, 'datetime': '2022-03-05T15:29:59.570Z', 'high': 1.7489,
# 'low': 1.6084, 'bid': 1.6505, 'bidVolume': 2135.0, 'ask': 1.6508, 'askVolume': 2815.0, 'vwap': 1.66852198,
# 'open': 1.7313, 'close': 1.6505, 'last': 1.6505, 'previousClose': '1.73170000', 'change': -0.0808,
# 'percentage': -4.667, 'average': 1.6909, 'baseVolume': 124656725.0, 'quoteVolume': 207992485.7799,
# 'info':
# {'symbol': 'FTMUSDT', 'priceChange': '-0.08080000', 'priceChangePercent': '-4.667',
# 'weightedAvgPrice': '1.66852198', 'prevClosePrice': '1.73170000', 'lastPrice': '1.65050000',
# 'lastQty': '143.00000000', 'bidPrice': '1.65050000', 'bidQty': '2135.00000000',
# 'askPrice': '1.65080000', 'askQty': '2815.00000000', 'openPrice': '1.73130000',
# 'highPrice': '1.74890000', 'lowPrice': '1.60840000', 'volume': '124656725.00000000',
# 'quoteVolume': '207992485.77990000', 'openTime': '1646407799570', 'closeTime': '1646494199570',
# 'firstId': '137149614', 'lastId': '137450289', 'count': '300676'}} - 0.9817468621938484
allow_to_buy = True
max_gain = -100
sum_gain = 0
max_time = 0
if self.dp:
if self.dp.runmode.value in ('live', 'dry_run'):
if len(self.trades) == 0:
print('search')
self.trades = Trade.get_open_trades()
if len(self.trades) >= self.config['max_open_trades'] / 2:
for trade in self.trades:
ticker = self.dp.ticker(trade.pair)
last_price = ticker['last']
gain = (last_price - trade.open_rate) / trade.open_rate
max_gain = max(max_gain, gain)
sum_gain += gain
max_time = max(max_time, datetime.timestamp(trade.open_date))
print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date),
datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000))
now = datetime.now()
diff = (datetime.timestamp(now) - max_time / 3600)
if (max_gain <= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6):
print("allow_to_buy=false")
allow_to_buy = False
print(pair, allow_to_buy, len(self.trades),
"max gain=", max_gain,
"sum_gain=", sum_gain,
"now=", now,
"max=", max_time,
"diff=", datetime.timestamp(now) - max_time)
if allow_to_buy:
self.trades = list()
return allow_to_buy
# @property
# def protections(self):
# return [
# {
# "method": "CooldownPeriod",
# "stop_duration_candles": 10
# },
# {
# "method": "MaxDrawdown",
# "lookback_period_candles": self.lookback.value,
# "trade_limit": self.trade_limit.value,
# "stop_duration_candles": self.protection_stop.value,
# "max_allowed_drawdown": self.protection_max_allowed_dd.value,
# "only_per_pair": False
# },
# {
# "method": "StoplossGuard",
# "lookback_period_candles": 24,
# "trade_limit": 4,
# "stop_duration_candles": self.protection_stoploss_stop.value,
# "only_per_pair": False
# }
# ]
def custom_sell(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float,
current_profit: float, **kwargs):
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
last_candle = dataframe.iloc[-1].squeeze()
previous_last_candle = dataframe.iloc[-2].squeeze()
previous_5_candle = dataframe.iloc[-5].squeeze()
# if (0 < current_profit) & ((current_time - trade.open_date_utc).seconds > 3600) \
# & (last_candle['percent10'] < 0.001):
# return 'small_profit'
#
# if (current_profit > 0.01) \
# & ((previous_last_candle['sma10'] - last_candle['sma10']) / previous_last_candle['sma10'] > 0.003):
# # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
# return 'sma10_quick'
if (current_profit >= -0.01) & ((current_time - trade.open_date_utc).days >= 5)\
& ((current_time - trade.open_date_utc).days < 10)\
& (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0):
return "too_old_0.01"
if (current_profit >= -0.02) & ((current_time - trade.open_date_utc).days >= 10)\
& ((current_time - trade.open_date_utc).days < 15) \
& (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0):
return "too_old_0.02"
if (current_profit >= -0.03) & ((current_time - trade.open_date_utc).days >= 15) \
& (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0):
return "too_old_0.03"
if self.profit_quick_lost:
if (current_profit >= 0) & (last_candle['percent3'] < -0.015):
return "quick_lost"
if self.profit_no_change:
if (current_profit > 0.005) & (last_candle['percent10'] < 0.001) & (last_candle['percent5'] < 0) & ((current_time - trade.open_date_utc).seconds >= 3600):
return "no_change"
if (current_profit > 0.005) & (last_candle['normal_var_20'] < 0.008):
return "no_change_20"
if (current_profit > 0.01) & (last_candle['normal_var_10'] < 0.008):
return "no_change_10"
if (current_profit > 0.01) & (last_candle['normal_var_5'] < 0.005):
return "no_change_5"
#if (current_profit > 0.01) & (last_candle['rsi'] < 30):
# return "small_rsi"
if self.profit_quick_gain_3:
if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600):
return "quick_gain_3"
if self.profit_quick_gain:
if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0): #& ((current_time - trade.open_date_utc).seconds <= 3600)
return "quick_gain"
if self.profit_sma10:
if (current_profit > 0.01) \
& ((previous_5_candle['sma10'] > last_candle['sma10']) \
| (last_candle['percent3'] < -0.01) | (last_candle['percent5'] < -0.01)) \
& ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)):
# print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
return 'sma10'
if self.profit_sma20:
if (current_profit > 0.005) \
& (previous_last_candle['sma10'] > last_candle['sma10']) \
& ((current_time - trade.open_date_utc).seconds >= 3600) \
& ((previous_last_candle['sma20'] > last_candle['sma20']) &
((last_candle['percent5'] < 0) | (last_candle['percent10'] < 0) | (last_candle['percent20'] < 0))):
# print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
return 'sma20'
# if self.profit_old_sma10:
# if (current_profit > 0) \
# & ((current_time - trade.open_date_utc).days >= 3) \
# & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < -0.005) | (last_candle['percent5'] < -0.005)) \
# & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)):
# # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
# return 'old_sma10'
# if self.profit_very_old_sma10:
# if (current_profit > -0.01) \
# & ((current_time - trade.open_date_utc).days >= 6) \
# & ((previous_5_candle['sma10'] > last_candle['sma10']) | (last_candle['percent3'] < 0) | (last_candle['percent5'] < 0)) \
# & ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)):
# # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
# return 'very_old_sma10'
if self.profit_over_rsi:
if (current_profit > 0) & (previous_last_candle['rsi'] > 88): # & (last_candle['percent'] < 0): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)):
# print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
return 'over_rsi'
if (current_profit > 0) & (previous_last_candle['rsi'] > 82) & (last_candle['percent'] < -0.02): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)):
# print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
return 'over_rsi_2'
if self.profit_short_loss:
if (current_profit > -0.01) & (previous_last_candle['percent10'] > 0.04) & (last_candle['percent'] < 0)\
& ((current_time - trade.open_date_utc).days >= 1): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)):
# print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
return 'short_lost'
# if (current_profit > 0) \
# & (last_candle['rsi'] > 82) & (previous_last_candle['rsi'] > 75): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)):
# # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
# return 'over_rsi_2'
def informative_pairs(self):
# get access to all pairs available in whitelist.
pairs = self.dp.current_whitelist()
# Assign tf to each pair so they can be downloaded and cached for strategy.
informative_pairs = [(pair, self.inf_tf) for pair in pairs]
informative_pairs += [(pair, '1d') for pair in pairs]
informative_pairs += [(pair, '1w') for pair in pairs]
# Optionally Add additional "static" pairs
# informative_pairs += [("ETH/USDT", "5m"), ("BTC/TUSD", "15m")]
return informative_pairs
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# dataframe['profit'] = 0
# RSI
dataframe['rsi'] = ta.RSI(dataframe)
dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10)
dataframe['sma20'] = ta.SMA(dataframe, timeperiod=20)
dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50)
dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100)
dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"]
dataframe["percent5"] = dataframe["percent"].rolling(5).sum()
dataframe["percent3"] = dataframe["percent"].rolling(3).sum()
dataframe["percent10"] = dataframe["percent"].rolling(10).sum()
dataframe["percent20"] = dataframe["percent"].rolling(20).sum()
dataframe["percent50"] = dataframe["percent"].rolling(50).sum()
# if (dataframe["percent50"] < -0.03) & (dataframe['sma10'] > dataframe['sma10'].shift(2)):
# dataframe["percent_ok"] = new dataframe()
# else:
# dataframe["percent_ok"] = 0
dataframe['ecart_20'] = dataframe['close'].rolling(20).var() / dataframe['close']
dataframe['ecart_50'] = dataframe['close'].rolling(50).var() / dataframe['close']
dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=self.buy_min_horizon.value)
dataframe['min10'] = ta.MIN(dataframe['close'], timeperiod=10)
dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20)
dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50)
dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200)
dataframe["volume10"] = dataframe["volume"].rolling(10).mean()
dataframe['max'] = ta.MAX(dataframe['close'], timeperiod=200)
dataframe['max_min'] = dataframe['max'] / dataframe['min']
# Bollinger Bands
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
dataframe['bb_lowerband'] = bollinger['lower']
dataframe['bb_middleband'] = bollinger['mid']
dataframe['bb_upperband'] = bollinger['upper']
dataframe["bb_percent"] = (
(dataframe["close"] - dataframe["bb_lowerband"]) /
(dataframe["bb_upperband"] - dataframe["bb_lowerband"])
)
dataframe["bb_width"] = (
(dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"]
)
dataframe['bb_lower_var_5'] = dataframe['bb_lowerband'].rolling(5).var()
# dataframe['bb_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36)
dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close']
dataframe['min1.1'] = 1.01 * dataframe['min']
dataframe['normal'] = 100 * (dataframe['close'] / dataframe['close'].rolling(200).mean())
dataframe['normal_var_5'] = dataframe['normal'].rolling(5).var()
dataframe['normal_var_10'] = dataframe['normal'].rolling(10).var()
dataframe['normal_var_20'] = dataframe['normal'].rolling(20).var()
dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var()
# Bollinger Bands - Weighted (EMA based instead of SMA)
# weighted_bollinger = qtpylib.weighted_bollinger_bands(
# qtpylib.typical_price(dataframe), window=20, stds=2
# )
# dataframe["wbb_upperband"] = weighted_bollinger["upper"]
# dataframe["wbb_lowerband"] = weighted_bollinger["lower"]
# dataframe["wbb_middleband"] = weighted_bollinger["mid"]
# dataframe["wbb_percent"] = (
# (dataframe["close"] - dataframe["wbb_lowerband"]) /
# (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"])
# )
# dataframe["wbb_width"] = (
# (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"]
# )
dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0)
dataframe[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1)
dataframe[buy_crossed_indicator2] = gene_calculator(dataframe, buy_crossed_indicator2)
dataframe[buy_indicator0] = gene_calculator(dataframe, buy_indicator0)
dataframe[buy_indicator1] = gene_calculator(dataframe, buy_indicator1)
dataframe[buy_indicator2] = gene_calculator(dataframe, buy_indicator2)
dataframe["cond1"] = dataframe[buy_indicator0].div(dataframe[buy_crossed_indicator0])
dataframe['cmf20'] = cmf(dataframe, 20)
dataframe['cmf50'] = cmf(dataframe, 50)
dataframe['cmf100'] = cmf(dataframe, 100)
# dataframe["dist_min_50"] = dataframe['close'] - dataframe['min50']
# dataframe["dist_min_20"] = dataframe['close'] - dataframe['min20']
# # EMA - Exponential Moving Average
# dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
# # INFORMATIVE PAIRS
# Get the informative pair
informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe=self.inf_tf)
informative[buy_crossed_indicator0] = gene_calculator(informative, buy_crossed_indicator0)
informative[buy_indicator0] = gene_calculator(informative, buy_indicator0)
informative["cond1"] = informative[buy_indicator0].div(informative[buy_crossed_indicator0])
pandas.set_option('display.max_rows', informative.shape[0] + 1)
pandas.set_option('display.max_columns', 50)
# print('informative', metadata['pair'], informative.tail(1))
dataframe = merge_informative_pair(dataframe, informative, self.timeframe, self.inf_tf, ffill=True)
informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe='1d')
informative[buy_crossed_indicator0] = gene_calculator(informative, buy_crossed_indicator0)
informative[buy_indicator0] = gene_calculator(informative, buy_indicator0)
informative["cond1"] = informative[buy_indicator0].div(informative[buy_crossed_indicator0])
informative["percent"] = (informative["close"] - informative["open"]) / informative["open"]
informative["percent5"] = informative["percent"].rolling(5).sum()
informative["percent3"] = informative["percent"].rolling(3).sum()
dataframe = merge_informative_pair(dataframe, informative, self.timeframe, '1d', ffill=True)
informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe='1w')
informative[buy_crossed_indicator0] = gene_calculator(informative, buy_crossed_indicator0)
informative[buy_indicator0] = gene_calculator(informative, buy_indicator0)
informative["cond1"] = informative[buy_indicator0].div(informative[buy_crossed_indicator0])
informative["percent"] = (informative["close"] - informative["open"]) / informative["open"]
informative["percent5"] = informative["percent"].rolling(5).sum()
informative["percent3"] = informative["percent"].rolling(3).sum()
dataframe = merge_informative_pair(dataframe, informative, self.timeframe, '1w', ffill=True)
return dataframe
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# pandas.set_option('display.max_rows', dataframe.shape[0] + 1)
# pandas.set_option('display.max_columns', 50)
#
# allow_to_buy = True
# max_gain = -100
# trades = Trade.get_open_trades()
#
# if self.dp:
# if self.dp.runmode.value in ('live', 'dry_run'):
# pairs = self.dp.current_whitelist()
# pairs_len = len(pairs)
# pair_index = pairs.index(metadata['pair'])
#
# # print(pair_index, " ", metadata['pair'])
#
# # ob = self.dp.orderbook(metadata['pair'], 1)
# # dataframe['best_bid'] = ob['bids'][0][0]
# # dataframe['best_ask'] = ob['asks'][0][0]
# # print(ob)
#
# for trade in trades:
# # if (metadata['pair'] == trade.pair):
# ticker = self.dp.ticker(trade.pair) #metadata['pair'])
# last_price = ticker['last']
# # dataframe['volume24h'] = ticker['quoteVolume']
# # dataframe['vwap'] = ticker['vwap']
# # d = dataframe.tail(1)
# # print(dataframe)
# gain = (last_price - trade.open_rate) / trade.open_rate
#
# # print("Found open trade: ", trade, " ", ticker['last'], " ", trade.open_rate, gain)
# max_gain = max(max_gain, gain)
#
# if max_gain > - 0.05:
# allow_to_buy = False
#
# # print(metadata['pair'], max_gain, allow_to_buy, len(trades))
# for decalage in range(self.buy_1_decalage_deb.value, self.buy_1_decalage.value):
# if self.buy_0.value:
# conditions = list()
# condition1, dataframe = condition_generator(
# dataframe,
# buy_operator0,
# buy_indicator0,
# buy_crossed_indicator0,
# self.buy_1_real_num.value,
# self.buy_1_decalage.value
# )
# conditions.append(condition1)
# dataframe.loc[
# (
# reduce(lambda x, y: x & y, conditions)
# & (dataframe['cmf100'] < self.buy_1_cmf100_sup.value)
# & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_1_volume.value)
# & (dataframe['sma10'].shift(1) <= dataframe['sma10'])
# & (dataframe['close'] < dataframe['bb_middleband'])
# & (dataframe['open'] < dataframe['sma10'])
# & (dataframe['open'] < dataframe['sma100'])
# & (dataframe['min50'].shift(decalage) == dataframe['min50'])
# & (dataframe['open'] <= dataframe['min200'] * self.buy_1_min.value)
# & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value)
# # & (dataframe['min20'] == dataframe['min50'])
# & (dataframe['distance_min'] <= self.buy_1_distance.value)
# & (dataframe['normal_var_20'] >= self.buy_1_normal_var.value)
# ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage))
# for decalage in range(self.buy_2_decalage_deb.value, self.buy_2_decalage.value):
# if self.buy_2.value:
# dataframe.loc[
# (
# (dataframe['cond1'].shift(decalage) <= self.buy_2_cond_num.value)
# & (dataframe['cond1'].shift(decalage) >= self.buy_3_cond_num.value)
# & (dataframe['cond1_1h'] <= self.buy_2_cond_1h_num.value)
# & (dataframe['cmf100'] >= self.buy_2_cmf100_sup.value)
# & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_2_volume.value)
# # & (dataframe['sma10'].shift(1) <= dataframe['sma10'])
# & (dataframe['close'] < dataframe['sma10'])
# & (dataframe['open'] < dataframe['sma100'])
# & (dataframe['open'] < dataframe['sma10'])
# & (dataframe['min50'].shift(decalage) == dataframe['min50'])
# #& (dataframe['min10'] <= dataframe['min50'] * 1.02)
# & (dataframe['percent20'].shift(decalage) <= self.buy_2_percent20.value)
# # & (dataframe['min20'] == dataframe['min50'])
# & (dataframe['distance_min'] <= self.buy_2_distance.value)
# # & (dataframe['normal_var_20'] >= self.buy_2_normal_var.value)
# ), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage))
for decalage in range(self.buy_3_decalage_deb.value, self.buy_3_decalage.value):
if self.buy_3.value:
dataframe.loc[
(
(dataframe['cond1'].shift(decalage) <= self.buy_3_cond_num.value)
#& (dataframe['percent_1d'] <= self.buy_3_percent_1d_num.value)
#& (dataframe['percent_1w'] <= self.buy_3_percent_1w_num.value)
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_3_volume.value)
# & (dataframe['sma10'].shift(1) <= dataframe['sma10'])
# & (dataframe['cmf100'] < self.buy_3_cmf100_sup.value)
# & (dataframe['cmf100'] > self.buy_3_cmf100_inf.value)
# & (dataframe['cmf100'] > self.buy_3_cmf100_inf.value)
& (dataframe['close'] < dataframe['sma10'])
& (dataframe['open'] < dataframe['sma20'])
& (dataframe['open'] < dataframe['sma10'])
& (dataframe['min50'].shift(decalage) == dataframe['min50'])
# & (dataframe['open'] <= dataframe['min200'] * self.buy_3_min.value)
& (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value)
& (dataframe['distance_min'] <= self.buy_3_distance.value)
# & (dataframe['normal_var_20'] >= self.buy_3_normal_var.value)
), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage))
# pair = metadata['pair']
# allow_to_buy = True
# max_gain = -100
# sum_gain = 0
# max_time = 0
# if len(self.trades) == 0:
# print('search')
# self.trades = Trade.get_open_trades()
#
# # if self.dp:
# # if self.dp.runmode.value in ('live', 'dry_run'):
# if len(self.trades) >= self.config['max_open_trades'] / 2:
# for trade in self.trades:
# ticker = self.dp.ticker(trade.pair)
# last_price = ticker['last']
# gain = (last_price - trade.open_rate) / trade.open_rate
# max_gain = max(max_gain, gain)
# sum_gain += gain
# max_time = max(max_time, datetime.timestamp(trade.open_date))
# print(trade.pair, ticker['datetime'], ticker['timestamp'] / 1000, datetime.timestamp(trade.open_date),
# datetime.timestamp(trade.open_date) - int(ticker['timestamp'] / 1000))
# now = datetime.now()
# diff = (datetime.timestamp(now) - max_time / 3600)
# if (max_gain >= -0.05) & (len(self.trades) >= self.config['max_open_trades'] / 2) & (diff < 6):
# print("allow_to_buy=false")
# allow_to_buy = False
# print(pair, allow_to_buy, len(self.trades),
# "max gain=", max_gain,
# "sum_gain=", sum_gain,
# "now=", now,
# "max=", max_time,
# "diff=", datetime.timestamp(now) - max_time)
#
# if allow_to_buy:
# self.trades = list()
# print(condition1)
return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
return dataframe