first commit
This commit is contained in:
1049
BB_RTR_dca.py
Normal file
1049
BB_RTR_dca.py
Normal file
File diff suppressed because it is too large
Load Diff
71
BinHV45.py
Normal file
71
BinHV45.py
Normal file
@@ -0,0 +1,71 @@
|
||||
# --- Do not remove these libs ---
|
||||
from freqtrade.strategy import IStrategy
|
||||
from freqtrade.strategy import IntParameter
|
||||
from pandas import DataFrame
|
||||
import numpy as np
|
||||
# --------------------------------
|
||||
|
||||
import talib.abstract as ta
|
||||
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||
|
||||
|
||||
def bollinger_bands(stock_price, window_size, num_of_std):
|
||||
rolling_mean = stock_price.rolling(window=window_size).mean()
|
||||
rolling_std = stock_price.rolling(window=window_size).std()
|
||||
lower_band = rolling_mean - (rolling_std * num_of_std)
|
||||
|
||||
return rolling_mean, lower_band
|
||||
|
||||
|
||||
class BinHV45(IStrategy):
|
||||
INTERFACE_VERSION = 2
|
||||
|
||||
minimal_roi = {
|
||||
"0": 0.0125
|
||||
}
|
||||
|
||||
stoploss = -0.05
|
||||
timeframe = '1m'
|
||||
|
||||
buy_bbdelta = IntParameter(low=1, high=15, default=30, space='buy', optimize=True)
|
||||
buy_closedelta = IntParameter(low=15, high=20, default=30, space='buy', optimize=True)
|
||||
buy_tail = IntParameter(low=20, high=30, default=30, space='buy', optimize=True)
|
||||
|
||||
# Hyperopt parameters
|
||||
buy_params = {
|
||||
"buy_bbdelta": 7,
|
||||
"buy_closedelta": 17,
|
||||
"buy_tail": 25,
|
||||
}
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
bollinger = qtpylib.bollinger_bands(dataframe['close'], window=40, stds=2)
|
||||
|
||||
dataframe['upper'] = bollinger['upper']
|
||||
dataframe['mid'] = bollinger['mid']
|
||||
dataframe['lower'] = bollinger['lower']
|
||||
dataframe['bbdelta'] = (dataframe['mid'] - dataframe['lower']).abs()
|
||||
dataframe['pricedelta'] = (dataframe['open'] - dataframe['close']).abs()
|
||||
dataframe['closedelta'] = (dataframe['close'] - dataframe['close'].shift()).abs()
|
||||
dataframe['tail'] = (dataframe['close'] - dataframe['low']).abs()
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
dataframe.loc[
|
||||
(
|
||||
dataframe['lower'].shift().gt(0) &
|
||||
dataframe['bbdelta'].gt(dataframe['close'] * self.buy_bbdelta.value / 1000) &
|
||||
dataframe['closedelta'].gt(dataframe['close'] * self.buy_closedelta.value / 1000) &
|
||||
dataframe['tail'].lt(dataframe['bbdelta'] * self.buy_tail.value / 1000) &
|
||||
dataframe['close'].lt(dataframe['lower'].shift()) &
|
||||
dataframe['close'].le(dataframe['close'].shift())
|
||||
),
|
||||
'buy'] = 1
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
no sell signal
|
||||
"""
|
||||
dataframe.loc[:, 'sell'] = 0
|
||||
return dataframe
|
||||
67
BreakEven.py
Normal file
67
BreakEven.py
Normal file
@@ -0,0 +1,67 @@
|
||||
# --- Do not remove these libs ---
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
from pandas import DataFrame
|
||||
# --------------------------------
|
||||
|
||||
|
||||
class BreakEven(IStrategy):
|
||||
"""
|
||||
author@: lenik
|
||||
|
||||
Sometimes I want to close the bot ASAP, but not have the positions floating around.
|
||||
|
||||
I can "/stopbuy" and wait for the positions to get closed by the bot rules, which is
|
||||
waiting for some profit, etc -- this usually takes too long...
|
||||
|
||||
What I would prefer is to close everything that is over 0% profit to avoid the losses.
|
||||
|
||||
Here's a simple strategy with empty buy/sell signals and "minimal_roi = { 0 : 0 }" that
|
||||
sells everything already at profit and wait until the positions at loss will come to break
|
||||
even point (or the small profit you provide in ROI table).
|
||||
|
||||
You may restart the bot with the new strategy as a command-line parameter.
|
||||
|
||||
Another way would be to specify the original strategy in the config file, then change to
|
||||
this one and simply "/reload_config" from the Telegram bot.
|
||||
|
||||
"""
|
||||
|
||||
# This attribute will be overridden if the config file contains "minimal_roi"
|
||||
minimal_roi = {
|
||||
"0": 0.01, # at least 1% at first
|
||||
"10": 0 # after 10min, everything goes
|
||||
}
|
||||
|
||||
# This is more radical version that sells everything above the profit level
|
||||
# minimal_roi = {
|
||||
# "0": 0
|
||||
# }
|
||||
|
||||
# And this is basically "/forcesell all", that sells no matter what profit
|
||||
# minimal_roi = {
|
||||
# "0": -1
|
||||
# }
|
||||
|
||||
# Optimal stoploss designed for the strategy
|
||||
stoploss = -0.05
|
||||
|
||||
# Optimal timeframe for the strategy
|
||||
timeframe = '5m'
|
||||
|
||||
# don't generate any buy or sell signals, everything is handled by ROI and stop_loss
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
dataframe.loc[
|
||||
(
|
||||
),
|
||||
'buy'] = 0
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
dataframe.loc[
|
||||
(
|
||||
),
|
||||
'sell'] = 0
|
||||
return dataframe
|
||||
29
DevilStra.json
Normal file
29
DevilStra.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"strategy_name": "DevilStra",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 0.574,
|
||||
"1757": 0.158,
|
||||
"3804": 0.089,
|
||||
"6585": 0
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -0.28
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": null,
|
||||
"trailing_stop_positive_offset": 0.0,
|
||||
"trailing_only_offset_is_reached": false
|
||||
},
|
||||
"buy": {
|
||||
"buy_spell": "Gu,Ra,Si,Gu,Pa,De,Si,La,Si,De,Cu,Lu,Pa,Si,De,La,Gu,La,Cu,Cu,Zi,Si,Gu,Lu,Pa,Lu,Ra,La,Si,Si,Ra,Lu,Pa,Ra,De,Zi,Ra,Si,De,La,La,Lu,Gu,Lu,Cu,Ra,Cu,Cu,La,Lu,De,Gu,Si,Cu,Cu,La,Si,Ra,Cu,Zi,La,Gu,De,Zi,De,Gu,Pa,Si,Cu,Lu,Gu,Si,Gu,Lu,Ra,De,Lu,Pa,Pa,Si,Zi,Pa,Cu,Ra,Gu,Ra,De,Cu,Lu,De,Pa,Lu,De,Lu,Pa,Gu,Cu,De,La,Ra,Pa,Gu,Lu,Zi,La,Ra,Cu,Si,De,Ra,La,Zi,Lu,Gu,De,Si,Ra,Pa,Si,De,De,La,La,Lu,Cu,La,Lu,Pa,Pa,Pa,De,Lu,La,Zi,Si,Pa,Pa,La,Si,Cu,Ra,Ra,Gu,Zi,Si,Si,La,La,Lu,La,La,Lu,Pa,Lu,Pa,Cu,Lu,Lu,Si,Zi,Lu,Si,Gu,La,La,La,Pa,Ra,Ra,Cu,De,De,Si,De,De,Ra,Pa,Lu,Zi,Cu,Zi,Gu,Zi,Pa,Si,Gu,Zi,La,Ra,La,Zi,Si,Zi,Si,La,La,Zi,Pa,La,Pa,La,Lu,Pa,Si,Zi,Gu,Zi,De,Zi,Ra,Pa,Cu,De,Cu,Ra,Gu,Gu,Zi,Gu,Zi,Cu,Lu,Gu,Zi,Cu,Pa,Gu,Si,Zi,La,Ra,Lu,Pa,Gu,Si,Zi,La,Ra,Pa,Ra,Cu,Cu,Zi,Cu,Gu,De,Lu,De,De,Ra,Cu,Gu,De,Ra,Si,Pa,La,Si,La,Zi,Lu,Zi,Cu,Zi,La,De,Lu,Cu,Zi"
|
||||
},
|
||||
"sell": {
|
||||
"sell_spell": "La,Pa,De,De,La,Si,Si,La,La,La,Si,Pa,Pa,Lu,De,Cu,Cu,Gu,Lu,Ra,Lu,Si,Ra,De,La,Cu,La,La,Gu,La,De,Ra,Ra,Ra,Gu,Lu,Si,Si,Zi,Zi,La,Pa,Pa,Zi,Cu,Gu,Gu,Pa,Gu,Cu,Si,Ra,Ra,La,Gu,De,Si,La,Ra,Pa,Si,Lu,Pa,De,Zi,De,Lu,Si,Gu,De,Lu,De,Ra,Ra,Zi,De,Cu,Zi,Gu,Pa,Ra,De,Pa,De,Pa,Ra,Si,Si,Zi,Cu,Lu,Zi,Ra,De,Ra,Zi,Zi,Pa,Lu,Zi,Cu,Pa,Gu,Pa,Cu,De,Zi,De,De,Pa,Pa,Zi,Lu,Ra,Pa,Ra,Lu,Zi,Gu,Zi,Si,Lu,Ra,Ra,Zi,Lu,Pa,Lu,Si,Pa,Pa,Pa,Si,Zi,La,La,Lu,De,Zi,Gu,Ra,Ra,Ra,Zi,Pa,Zi,Cu,Lu,Gu,Cu,De,Lu,Gu,Lu,Gu,Si,Pa,Pa,Si,La,Gu,Ra,Pa,Si,Si,Si,Cu,Cu,Cu,Si,De,Lu,Gu,Gu,Lu,De,Ra,Gu,Gu,Gu,Cu,La,De,Cu,Zi,Pa,Si,De,Pa,Pa,Pa,La,De,Gu,Zi,La,De,Cu,La,Pa,Ra,Si,Si,Zi,Cu,Ra,Pa,Gu,Pa,Ra,Zi,De,Zi,Gu,Gu,Pa,Cu,Lu,Gu,De,Si,Pa,La,Cu,Zi,Gu,De,Gu,La,Cu,Gu,De,Cu,Cu,Gu,Ra,Lu,Zi,De,La,Ra,Pa,Pa,Si,La,Lu,La,De,De,Ra,De,La,La,Pa,Cu,Lu,Pa,Ra,Pa,Pa,Cu,Zi,Gu,Cu,Gu,La,Si,Ra,Pa"
|
||||
},
|
||||
"protection": {}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-03-04 11:36:44.627014+00:00"
|
||||
}
|
||||
721
DevilStra.py
Normal file
721
DevilStra.py
Normal file
@@ -0,0 +1,721 @@
|
||||
# DevilStra Strategy
|
||||
# 𝔇𝔢𝔳𝔦𝔩 𝔦𝔰 𝔞𝔩𝔴𝔞𝔶𝔰 𝔰𝔱𝔯𝔬𝔫𝔤𝔢𝔯 𝔱𝔥𝔞𝔫 𝔊𝔬𝔡.
|
||||
# 𝔅𝔲𝔱 𝔱𝔥𝔢 𝔬𝔫𝔩𝔶 𝔬𝔫𝔢 𝔴𝔥𝔬 𝔥𝔞𝔰 𝔱𝔥𝔢 𝔞𝔟𝔦𝔩𝔦𝔱𝔶
|
||||
# 𝔗𝔬 𝔠𝔯𝔢𝔞𝔱𝔢 𝔫𝔢𝔴 𝔠𝔯𝔢𝔞𝔱𝔲𝔯𝔢𝔰 𝔦𝔰 𝔊𝔬𝔡.
|
||||
# 𝔄𝔫𝔡 𝔱𝔥𝔢 𝔇𝔢𝔳𝔦𝔩 𝔪𝔞𝔨𝔢𝔰 𝔭𝔬𝔴𝔢𝔯𝔣𝔲𝔩 𝔰𝔭𝔢𝔩𝔩𝔰
|
||||
# 𝔉𝔯𝔬𝔪 𝔱𝔥𝔦𝔰 𝔰𝔪𝔞𝔩𝔩 𝔠𝔯𝔢𝔞𝔱𝔲𝔯𝔢𝔰 (𝔩𝔦𝔨𝔢 𝔣𝔯𝔬𝔤𝔰, 𝔢𝔱𝔠.)
|
||||
# 𝔚𝔦𝔱𝔥 𝔣𝔯𝔞𝔤𝔪𝔢𝔫𝔱𝔞𝔱𝔦𝔬𝔫 𝔞𝔫𝔡 𝔪𝔦𝔵𝔦𝔫𝔤 𝔱𝔥𝔢𝔪.
|
||||
# Author: @Mablue (Masoud Azizi)
|
||||
# github: https://github.com/mablue/
|
||||
# * IMPORTANT: You Need An "STATIC" Pairlist On Your Config.json !
|
||||
# * IMPORTANT: First set PAIR_LIST_LENGHT={pair_whitelist size}
|
||||
# * And re-hyperopt the Sell strategy And paste result in exact
|
||||
# * place(lines 535~564)
|
||||
|
||||
# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell -s 𝕯𝖊𝖛𝖎𝖑𝕾𝖙𝖗𝖆
|
||||
|
||||
# --- Do not remove these libs ---
|
||||
import numpy as np
|
||||
from functools import reduce
|
||||
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||
import talib.abstract as ta
|
||||
import random
|
||||
from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter
|
||||
|
||||
from numpy.lib import math
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
from pandas import DataFrame
|
||||
|
||||
# ########################## SETTINGS ##############################
|
||||
# pairlist lenght(use exact count of pairs you used in whitelist size+1):
|
||||
PAIR_LIST_LENGHT = 269
|
||||
# you can find exact value of this inside GodStraNew
|
||||
TREND_CHECK_CANDLES = 4
|
||||
# Set the pain range of devil(2~9999)
|
||||
PAIN_RANGE = 1000
|
||||
# Add "GodStraNew" Generated Results As spells inside SPELLS.
|
||||
# Set them unic phonemes like 'Zi' 'Gu' or 'Lu'!
|
||||
# * Use below replacement on GodStraNew results to
|
||||
# * Change God Generated Creatures to Spells:
|
||||
# +-----------------------------+----------------------+
|
||||
# | GodStraNew Hyperopt Results | DevilStra Spells |
|
||||
# +-----------------------------+----------------------+
|
||||
# | | "phonem" : { |
|
||||
# | buy_params = { | "buy_params" : { |
|
||||
# | ... | ... |
|
||||
# | } | }, |
|
||||
# | sell_params = { | "sell_params" : { |
|
||||
# | ... | ... |
|
||||
# | } | } |
|
||||
# | | }, |
|
||||
# +-----------------------------+----------------------+
|
||||
SPELLS = {
|
||||
"Zi": {
|
||||
"buy_params": {
|
||||
"buy_crossed_indicator0": "BOP-4",
|
||||
"buy_crossed_indicator1": "MACD-0-50",
|
||||
"buy_crossed_indicator2": "DEMA-52",
|
||||
"buy_indicator0": "MINUS_DI-50",
|
||||
"buy_indicator1": "HT_TRENDMODE-50",
|
||||
"buy_indicator2": "CORREL-128",
|
||||
"buy_operator0": "/>R",
|
||||
"buy_operator1": "CA",
|
||||
"buy_operator2": "CDT",
|
||||
"buy_real_num0": 0.1763,
|
||||
"buy_real_num1": 0.6891,
|
||||
"buy_real_num2": 0.0509,
|
||||
},
|
||||
"sell_params": {
|
||||
"sell_crossed_indicator0": "WCLPRICE-52",
|
||||
"sell_crossed_indicator1": "AROONOSC-15",
|
||||
"sell_crossed_indicator2": "CDLRISEFALL3METHODS-52",
|
||||
"sell_indicator0": "COS-50",
|
||||
"sell_indicator1": "CDLCLOSINGMARUBOZU-30",
|
||||
"sell_indicator2": "CDL2CROWS-130",
|
||||
"sell_operator0": "DT",
|
||||
"sell_operator1": ">R",
|
||||
"sell_operator2": "/>R",
|
||||
"sell_real_num0": 0.0678,
|
||||
"sell_real_num1": 0.8698,
|
||||
"sell_real_num2": 0.3917,
|
||||
}
|
||||
},
|
||||
"Gu": {
|
||||
"buy_params": {
|
||||
"buy_crossed_indicator0": "SMA-20",
|
||||
"buy_crossed_indicator1": "CDLLADDERBOTTOM-20",
|
||||
"buy_crossed_indicator2": "OBV-50",
|
||||
"buy_indicator0": "MAMA-1-50",
|
||||
"buy_indicator1": "SUM-40",
|
||||
"buy_indicator2": "VAR-30",
|
||||
"buy_operator0": "<R",
|
||||
"buy_operator1": "D",
|
||||
"buy_operator2": "D",
|
||||
"buy_real_num0": 0.2644,
|
||||
"buy_real_num1": 0.0736,
|
||||
"buy_real_num2": 0.8954,
|
||||
},
|
||||
"sell_params": {
|
||||
"sell_crossed_indicator0": "CDLLADDERBOTTOM-50",
|
||||
"sell_crossed_indicator1": "CDLHARAMICROSS-50",
|
||||
"sell_crossed_indicator2": "CDLDARKCLOUDCOVER-30",
|
||||
"sell_indicator0": "CDLLADDERBOTTOM-10",
|
||||
"sell_indicator1": "MAMA-1-40",
|
||||
"sell_indicator2": "OBV-30",
|
||||
"sell_operator0": "UT",
|
||||
"sell_operator1": ">R",
|
||||
"sell_operator2": "CUT",
|
||||
"sell_real_num0": 0.2707,
|
||||
"sell_real_num1": 0.7987,
|
||||
"sell_real_num2": 0.6891,
|
||||
}
|
||||
},
|
||||
"Lu": {
|
||||
"buy_params": {
|
||||
"buy_crossed_indicator0": "HT_SINE-0-28",
|
||||
"buy_crossed_indicator1": "ADD-130",
|
||||
"buy_crossed_indicator2": "ADD-12",
|
||||
"buy_indicator0": "ADD-28",
|
||||
"buy_indicator1": "AVGPRICE-15",
|
||||
"buy_indicator2": "AVGPRICE-12",
|
||||
"buy_operator0": "DT",
|
||||
"buy_operator1": "D",
|
||||
"buy_operator2": "C",
|
||||
"buy_real_num0": 0.3676,
|
||||
"buy_real_num1": 0.4284,
|
||||
"buy_real_num2": 0.372,
|
||||
},
|
||||
"sell_params": {
|
||||
"sell_crossed_indicator0": "HT_SINE-0-5",
|
||||
"sell_crossed_indicator1": "HT_SINE-0-4",
|
||||
"sell_crossed_indicator2": "HT_SINE-0-28",
|
||||
"sell_indicator0": "ADD-30",
|
||||
"sell_indicator1": "AVGPRICE-28",
|
||||
"sell_indicator2": "ADD-50",
|
||||
"sell_operator0": "CUT",
|
||||
"sell_operator1": "DT",
|
||||
"sell_operator2": "=R",
|
||||
"sell_real_num0": 0.3205,
|
||||
"sell_real_num1": 0.2055,
|
||||
"sell_real_num2": 0.8467,
|
||||
}
|
||||
},
|
||||
"La": {
|
||||
"buy_params": {
|
||||
"buy_crossed_indicator0": "WMA-14",
|
||||
"buy_crossed_indicator1": "MAMA-1-14",
|
||||
"buy_crossed_indicator2": "CDLHIKKAKE-14",
|
||||
"buy_indicator0": "T3-14",
|
||||
"buy_indicator1": "BETA-14",
|
||||
"buy_indicator2": "HT_PHASOR-1-14",
|
||||
"buy_operator0": "/>R",
|
||||
"buy_operator1": ">",
|
||||
"buy_operator2": ">R",
|
||||
"buy_real_num0": 0.0551,
|
||||
"buy_real_num1": 0.3469,
|
||||
"buy_real_num2": 0.3871,
|
||||
},
|
||||
"sell_params": {
|
||||
"sell_crossed_indicator0": "HT_TRENDLINE-14",
|
||||
"sell_crossed_indicator1": "LINEARREG-14",
|
||||
"sell_crossed_indicator2": "STOCHRSI-1-14",
|
||||
"sell_indicator0": "CDLDARKCLOUDCOVER-14",
|
||||
"sell_indicator1": "AD-14",
|
||||
"sell_indicator2": "CDLSTALLEDPATTERN-14",
|
||||
"sell_operator0": "/=R",
|
||||
"sell_operator1": "COT",
|
||||
"sell_operator2": "OT",
|
||||
"sell_real_num0": 0.3992,
|
||||
"sell_real_num1": 0.7747,
|
||||
"sell_real_num2": 0.7415,
|
||||
}
|
||||
},
|
||||
"Si": {
|
||||
"buy_params": {
|
||||
"buy_crossed_indicator0": "MACDEXT-2-14",
|
||||
"buy_crossed_indicator1": "CORREL-14",
|
||||
"buy_crossed_indicator2": "CMO-14",
|
||||
"buy_indicator0": "MA-14",
|
||||
"buy_indicator1": "ADXR-14",
|
||||
"buy_indicator2": "CDLMARUBOZU-14",
|
||||
"buy_operator0": "<",
|
||||
"buy_operator1": "/<R",
|
||||
"buy_operator2": "<R",
|
||||
"buy_real_num0": 0.7883,
|
||||
"buy_real_num1": 0.8286,
|
||||
"buy_real_num2": 0.6512,
|
||||
},
|
||||
"sell_params": {
|
||||
"sell_crossed_indicator0": "AROON-1-14",
|
||||
"sell_crossed_indicator1": "STOCHRSI-0-14",
|
||||
"sell_crossed_indicator2": "SMA-14",
|
||||
"sell_indicator0": "T3-14",
|
||||
"sell_indicator1": "AROONOSC-14",
|
||||
"sell_indicator2": "MIDPOINT-14",
|
||||
"sell_operator0": "C",
|
||||
"sell_operator1": "CA",
|
||||
"sell_operator2": "CB",
|
||||
"sell_real_num0": 0.372,
|
||||
"sell_real_num1": 0.5948,
|
||||
"sell_real_num2": 0.9872,
|
||||
}
|
||||
},
|
||||
"Pa": {
|
||||
"buy_params": {
|
||||
"buy_crossed_indicator0": "AROON-0-60",
|
||||
"buy_crossed_indicator1": "APO-60",
|
||||
"buy_crossed_indicator2": "BBANDS-0-60",
|
||||
"buy_indicator0": "WILLR-12",
|
||||
"buy_indicator1": "AD-15",
|
||||
"buy_indicator2": "MINUS_DI-12",
|
||||
"buy_operator0": "D",
|
||||
"buy_operator1": ">",
|
||||
"buy_operator2": "CA",
|
||||
"buy_real_num0": 0.2208,
|
||||
"buy_real_num1": 0.1371,
|
||||
"buy_real_num2": 0.6389,
|
||||
},
|
||||
"sell_params": {
|
||||
"sell_crossed_indicator0": "MACDEXT-0-15",
|
||||
"sell_crossed_indicator1": "BBANDS-2-15",
|
||||
"sell_crossed_indicator2": "DEMA-15",
|
||||
"sell_indicator0": "ULTOSC-15",
|
||||
"sell_indicator1": "MIDPOINT-12",
|
||||
"sell_indicator2": "PLUS_DI-12",
|
||||
"sell_operator0": "<",
|
||||
"sell_operator1": "DT",
|
||||
"sell_operator2": "COT",
|
||||
"sell_real_num0": 0.278,
|
||||
"sell_real_num1": 0.0643,
|
||||
"sell_real_num2": 0.7065,
|
||||
}
|
||||
},
|
||||
"De": {
|
||||
"buy_params": {
|
||||
"buy_crossed_indicator0": "HT_DCPERIOD-12",
|
||||
"buy_crossed_indicator1": "HT_PHASOR-0-12",
|
||||
"buy_crossed_indicator2": "MACDFIX-1-15",
|
||||
"buy_indicator0": "CMO-12",
|
||||
"buy_indicator1": "TRIMA-12",
|
||||
"buy_indicator2": "MACDEXT-0-15",
|
||||
"buy_operator0": "<",
|
||||
"buy_operator1": "D",
|
||||
"buy_operator2": "<",
|
||||
"buy_real_num0": 0.3924,
|
||||
"buy_real_num1": 0.5546,
|
||||
"buy_real_num2": 0.7648,
|
||||
},
|
||||
"sell_params": {
|
||||
"sell_crossed_indicator0": "MACDFIX-1-15",
|
||||
"sell_crossed_indicator1": "MACD-1-15",
|
||||
"sell_crossed_indicator2": "WMA-15",
|
||||
"sell_indicator0": "ROC-15",
|
||||
"sell_indicator1": "MACD-2-15",
|
||||
"sell_indicator2": "CCI-60",
|
||||
"sell_operator0": "CA",
|
||||
"sell_operator1": "<R",
|
||||
"sell_operator2": "/<R",
|
||||
"sell_real_num0": 0.4989,
|
||||
"sell_real_num1": 0.4131,
|
||||
"sell_real_num2": 0.8904,
|
||||
}
|
||||
},
|
||||
"Ra": {
|
||||
"buy_params": {
|
||||
"buy_crossed_indicator0": "EMA-110",
|
||||
"buy_crossed_indicator1": "SMA-5",
|
||||
"buy_crossed_indicator2": "SMA-6",
|
||||
"buy_indicator0": "SMA-6",
|
||||
"buy_indicator1": "EMA-12",
|
||||
"buy_indicator2": "EMA-5",
|
||||
"buy_operator0": "D",
|
||||
"buy_operator1": "<",
|
||||
"buy_operator2": "/<R",
|
||||
"buy_real_num0": 0.9814,
|
||||
"buy_real_num1": 0.5528,
|
||||
"buy_real_num2": 0.0541,
|
||||
},
|
||||
"sell_params": {
|
||||
"sell_crossed_indicator0": "SMA-50",
|
||||
"sell_crossed_indicator1": "EMA-12",
|
||||
"sell_crossed_indicator2": "SMA-100",
|
||||
"sell_indicator0": "EMA-110",
|
||||
"sell_indicator1": "EMA-50",
|
||||
"sell_indicator2": "EMA-15",
|
||||
"sell_operator0": "<",
|
||||
"sell_operator1": "COT",
|
||||
"sell_operator2": "/=R",
|
||||
"sell_real_num0": 0.3506,
|
||||
"sell_real_num1": 0.8767,
|
||||
"sell_real_num2": 0.0614,
|
||||
}
|
||||
},
|
||||
"Cu": {
|
||||
"buy_params": {
|
||||
"buy_crossed_indicator0": "SMA-110",
|
||||
"buy_crossed_indicator1": "SMA-110",
|
||||
"buy_crossed_indicator2": "SMA-5",
|
||||
"buy_indicator0": "SMA-110",
|
||||
"buy_indicator1": "SMA-55",
|
||||
"buy_indicator2": "SMA-15",
|
||||
"buy_operator0": "<R",
|
||||
"buy_operator1": "<",
|
||||
"buy_operator2": "CA",
|
||||
"buy_real_num0": 0.5,
|
||||
"buy_real_num1": 0.7,
|
||||
"buy_real_num2": 0.9,
|
||||
},
|
||||
"sell_params": {
|
||||
"sell_crossed_indicator0": "SMA-55",
|
||||
"sell_crossed_indicator1": "SMA-50",
|
||||
"sell_crossed_indicator2": "SMA-100",
|
||||
"sell_indicator0": "SMA-5",
|
||||
"sell_indicator1": "SMA-50",
|
||||
"sell_indicator2": "SMA-50",
|
||||
"sell_operator0": "/=R",
|
||||
"sell_operator1": "CUT",
|
||||
"sell_operator2": "DT",
|
||||
"sell_real_num0": 0.4,
|
||||
"sell_real_num1": 0.2,
|
||||
"sell_real_num2": 0.7,
|
||||
}
|
||||
}
|
||||
}
|
||||
# ######################## END SETTINGS ############################
|
||||
|
||||
|
||||
def spell_finder(index, space):
|
||||
return SPELLS[index][space+"_params"]
|
||||
|
||||
|
||||
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):
|
||||
|
||||
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] > dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "=":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "<":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "C":
|
||||
condition = (
|
||||
(qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) |
|
||||
(qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator]))
|
||||
)
|
||||
elif operator == "CA":
|
||||
condition = (
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "CB":
|
||||
condition = (
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == ">R":
|
||||
condition = (
|
||||
dataframe[indicator] > real_num
|
||||
)
|
||||
elif operator == "=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], real_num)
|
||||
)
|
||||
elif operator == "<R":
|
||||
condition = (
|
||||
dataframe[indicator] < real_num
|
||||
)
|
||||
elif operator == "/>R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) > real_num
|
||||
)
|
||||
elif operator == "/=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator].div(
|
||||
dataframe[crossed_indicator]), real_num)
|
||||
)
|
||||
elif operator == "/<R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) < real_num
|
||||
)
|
||||
elif operator == "UT":
|
||||
condition = (
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "DT":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "OT":
|
||||
condition = (
|
||||
|
||||
np.isclose(dataframe[indicator], dataframe[indicator_trend_sma])
|
||||
)
|
||||
elif operator == "CUT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "CDT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "COT":
|
||||
condition = (
|
||||
(
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) |
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
) &
|
||||
(
|
||||
np.isclose(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return condition, dataframe
|
||||
|
||||
|
||||
class DevilStra(IStrategy):
|
||||
# #################### RESULT PASTE PLACE ####################
|
||||
# 16/16: 108 trades. 75/18/15 Wins/Draws/Losses. Avg profit 7.77%. Median profit 8.89%. Total profit 0.08404983 BTC ( 84.05Σ%). Avg duration 3 days, 6:49:00 min. Objective: -11.22849
|
||||
|
||||
# Buy hyperspace params:
|
||||
buy_params = {
|
||||
"buy_spell": "Zi,Lu,Ra,Ra,La,Si,Pa,Si,Cu,La,De,Lu,De,La,Zi,Zi,Zi,Zi,Zi,Lu,Lu,Lu,Si,La,Ra,Pa,La,Zi,Zi,Gu,Ra,De,Gu,Zi,Ra,Ra,Ra,Cu,Pa,De,De,La,Lu,Lu,Lu,La,Zi,Cu,Ra,Gu,Pa,La,Zi,Zi,Si,Lu,Ra,Cu,Cu,Pa,Si,Gu,De,De,Lu,Gu,Zi,Pa,Lu,Pa,Ra,Gu,Cu,La,Pa,Lu,Zi,La,Zi,Gu,Zi,De,Cu,Ra,Lu,Ra,Gu,Si,Ra,La,La,Lu,Gu,Zi,Si,La,Pa,Pa,Cu,Cu,Zi,Gu,Pa,Zi,Pa,Cu,Lu,Pa,Si,De,Gu,Lu,Lu,Cu,Ra,Si,Pa,Gu,Si,Cu,Pa,Zi,Pa,Zi,Gu,Lu,Ra,Pa,Ra,De,Ra,Pa,Zi,La,Pa,De,Pa,Cu,Gu,De,Lu,La,Ra,Zi,Si,Zi,Zi,Cu,Cu,De,Pa,Pa,Zi,De,Ra,La,Lu,De,Lu,Gu,Cu,Cu,La,De,Gu,Lu,Ra,Pa,Lu,Cu,Pa,Pa,De,Si,Zi,Cu,De,De,De,Lu,Si,Zi,Gu,Si,Si,Ra,Pa,Si,La,La,Lu,Lu,De,Gu,Gu,Zi,Ra,La,Lu,Lu,La,Si,Zi,Si,Zi,Si,Lu,Cu,Zi,Lu,De,La,Ra,Ra,Lu,De,Pa,Zi,Gu,Cu,Zi,Pa,De,Si,Lu,De,Cu,De,Zi,Ra,Gu,De,Si,Lu,Lu,Ra,De,Gu,Cu,Gu,La,De,Lu,Lu,Si,Cu,Lu,Zi,Lu,Cu,Gu,Lu,Lu,Ra,Si,Ra,Pa,Lu,De,Ra,Zi,Gu,Gu,Zi,Lu,Cu,Cu,Cu,Lu",
|
||||
}
|
||||
|
||||
# Sell hyperspace params:
|
||||
sell_params = {
|
||||
"sell_spell": "La,Pa,De,De,La,Si,Si,La,La,La,Si,Pa,Pa,Lu,De,Cu,Cu,Gu,Lu,Ra,Lu,Si,Ra,De,La,Cu,La,La,Gu,La,De,Ra,Ra,Ra,Gu,Lu,Si,Si,Zi,Zi,La,Pa,Pa,Zi,Cu,Gu,Gu,Pa,Gu,Cu,Si,Ra,Ra,La,Gu,De,Si,La,Ra,Pa,Si,Lu,Pa,De,Zi,De,Lu,Si,Gu,De,Lu,De,Ra,Ra,Zi,De,Cu,Zi,Gu,Pa,Ra,De,Pa,De,Pa,Ra,Si,Si,Zi,Cu,Lu,Zi,Ra,De,Ra,Zi,Zi,Pa,Lu,Zi,Cu,Pa,Gu,Pa,Cu,De,Zi,De,De,Pa,Pa,Zi,Lu,Ra,Pa,Ra,Lu,Zi,Gu,Zi,Si,Lu,Ra,Ra,Zi,Lu,Pa,Lu,Si,Pa,Pa,Pa,Si,Zi,La,La,Lu,De,Zi,Gu,Ra,Ra,Ra,Zi,Pa,Zi,Cu,Lu,Gu,Cu,De,Lu,Gu,Lu,Gu,Si,Pa,Pa,Si,La,Gu,Ra,Pa,Si,Si,Si,Cu,Cu,Cu,Si,De,Lu,Gu,Gu,Lu,De,Ra,Gu,Gu,Gu,Cu,La,De,Cu,Zi,Pa,Si,De,Pa,Pa,Pa,La,De,Gu,Zi,La,De,Cu,La,Pa,Ra,Si,Si,Zi,Cu,Ra,Pa,Gu,Pa,Ra,Zi,De,Zi,Gu,Gu,Pa,Cu,Lu,Gu,De,Si,Pa,La,Cu,Zi,Gu,De,Gu,La,Cu,Gu,De,Cu,Cu,Gu,Ra,Lu,Zi,De,La,Ra,Pa,Pa,Si,La,Lu,La,De,De,Ra,De,La,La,Pa,Cu,Lu,Pa,Ra,Pa,Pa,Cu,Zi,Gu,Cu,Gu,La,Si,Ra,Pa",
|
||||
}
|
||||
|
||||
# ROI table:
|
||||
minimal_roi = {
|
||||
"0": 0.574,
|
||||
"1757": 0.158,
|
||||
"3804": 0.089,
|
||||
"6585": 0
|
||||
}
|
||||
|
||||
# Stoploss:
|
||||
stoploss = -0.28
|
||||
# #################### END OF RESULT PLACE ####################
|
||||
|
||||
# 𝖂𝖔𝖗𝖘𝖙, 𝖀𝖓𝖎𝖉𝖊𝖆𝖑, 𝕾𝖚𝖇𝖔𝖕𝖙𝖎𝖒𝖆𝖑, 𝕸𝖆𝖑𝖆𝖕𝖗𝖔𝖕𝖔𝖘 𝕬𝖓𝖉 𝕯𝖎𝖘𝖒𝖆𝖑 𝖙𝖎𝖒𝖊𝖋𝖗𝖆𝖒𝖊 𝖋𝖔𝖗 𝖙𝖍𝖎𝖘 𝖘𝖙𝖗𝖆𝖙𝖊𝖌𝖞:
|
||||
timeframe = '4h'
|
||||
|
||||
spell_pot = [
|
||||
",".join(
|
||||
tuple(
|
||||
random.choices(
|
||||
list(SPELLS.keys()),
|
||||
# TODO: k will be change to len(pairlist)
|
||||
k=PAIR_LIST_LENGHT
|
||||
)
|
||||
)
|
||||
)for i in range(PAIN_RANGE)
|
||||
]
|
||||
|
||||
buy_spell = CategoricalParameter(
|
||||
spell_pot, default=spell_pot[0], space='buy')
|
||||
sell_spell = CategoricalParameter(
|
||||
spell_pot, default=spell_pot[0], space='sell')
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
pairs = self.dp.current_whitelist()
|
||||
pairs_len = len(pairs)
|
||||
pair_index = pairs.index(metadata['pair'])
|
||||
|
||||
buy_spells = self.buy_spell.value.split(",")
|
||||
buy_spells_len = len(buy_spells)
|
||||
|
||||
if pairs_len > buy_spells_len:
|
||||
print(
|
||||
f"First set PAIR_LIST_LENGHT={pairs_len + 1} And re-hyperopt the")
|
||||
print("Buy strategy And paste result in exact place(lines 535~564)")
|
||||
print("IMPORTANT: You Need An 'STATIC' Pairlist On Your Config.json !!!")
|
||||
exit()
|
||||
|
||||
buy_params_index = buy_spells[pair_index]
|
||||
|
||||
params = spell_finder(buy_params_index, 'buy')
|
||||
conditions = list()
|
||||
# TODO: Its not dry code!
|
||||
buy_indicator = params['buy_indicator0']
|
||||
buy_crossed_indicator = params['buy_crossed_indicator0']
|
||||
buy_operator = params['buy_operator0']
|
||||
buy_real_num = params['buy_real_num0']
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
# backup
|
||||
buy_indicator = params['buy_indicator1']
|
||||
buy_crossed_indicator = params['buy_crossed_indicator1']
|
||||
buy_operator = params['buy_operator1']
|
||||
buy_real_num = params['buy_real_num1']
|
||||
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
buy_indicator = params['buy_indicator2']
|
||||
buy_crossed_indicator = params['buy_crossed_indicator2']
|
||||
buy_operator = params['buy_operator2']
|
||||
buy_real_num = params['buy_real_num2']
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
'buy']=1
|
||||
|
||||
# print(len(dataframe.keys()))
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
pairs = self.dp.current_whitelist()
|
||||
pairs_len = len(pairs)
|
||||
pair_index = pairs.index(metadata['pair'])
|
||||
|
||||
sell_spells = self.sell_spell.value.split(",")
|
||||
sell_spells_len = len(sell_spells)
|
||||
|
||||
if pairs_len > sell_spells_len:
|
||||
print(
|
||||
f"First set PAIR_LIST_LENGHT={pairs_len + 1} And re-hyperopt the")
|
||||
print("Sell strategy And paste result in exact place(lines 535~564)")
|
||||
print("IMPORTANT: You Need An 'STATIC' Pairlist On Your Config.json !!!")
|
||||
exit()
|
||||
|
||||
sell_params_index = sell_spells[pair_index]
|
||||
|
||||
params = spell_finder(sell_params_index, 'sell')
|
||||
|
||||
conditions = list()
|
||||
# TODO: Its not dry code!
|
||||
sell_indicator = params['sell_indicator0']
|
||||
sell_crossed_indicator = params['sell_crossed_indicator0']
|
||||
sell_operator = params['sell_operator0']
|
||||
sell_real_num = params['sell_real_num0']
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
sell_indicator = params['sell_indicator1']
|
||||
sell_crossed_indicator = params['sell_crossed_indicator1']
|
||||
sell_operator = params['sell_operator1']
|
||||
sell_real_num = params['sell_real_num1']
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
sell_indicator = params['sell_indicator2']
|
||||
sell_crossed_indicator = params['sell_crossed_indicator2']
|
||||
sell_operator = params['sell_operator2']
|
||||
sell_real_num = params['sell_real_num2']
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
'sell']=1
|
||||
return dataframe
|
||||
76
DevilStra.txt
Normal file
76
DevilStra.txt
Normal file
@@ -0,0 +1,76 @@
|
||||
Result for strategy DevilStra
|
||||
============================================================ BACKTESTING REPORT ===========================================================
|
||||
| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% |
|
||||
|-----------+--------+----------------+----------------+-------------------+----------------+-------------------+-------------------------|
|
||||
| SAND/USDT | 8 | 231.37 | 1850.99 | 1852.839 | 185.28 | 39 days, 21:07:00 | 6 1 1 75.0 |
|
||||
| SOL/USDT | 135 | 4.65 | 628.37 | 628.998 | 62.90 | 2 days, 6:16:00 | 83 7 45 61.5 |
|
||||
| AVAX/USDT | 84 | 5.75 | 483.08 | 483.565 | 48.36 | 3 days, 15:04:00 | 63 6 15 75.0 |
|
||||
| GALA/USDT | 13 | 14.36 | 186.68 | 186.864 | 18.69 | 4 days, 22:32:00 | 9 0 4 69.2 |
|
||||
| ETH/USDT | 43 | 3.56 | 153.26 | 153.409 | 15.34 | 4 days, 11:59:00 | 32 6 5 74.4 |
|
||||
| BNB/USDT | 31 | 4.56 | 141.48 | 141.626 | 14.16 | 4 days, 15:44:00 | 18 10 3 58.1 |
|
||||
| ROSE/USDT | 48 | 2.89 | 138.94 | 139.075 | 13.91 | 3 days, 22:48:00 | 25 15 8 52.1 |
|
||||
| XRP/USDT | 50 | 1.64 | 82.23 | 82.309 | 8.23 | 3 days, 16:22:00 | 27 8 15 54.0 |
|
||||
| EGLD/USDT | 44 | 0.08 | 3.35 | 3.355 | 0.34 | 4 days, 7:08:00 | 27 6 11 61.4 |
|
||||
| ZEC/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 |
|
||||
| ADA/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 |
|
||||
| IOTX/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 |
|
||||
| CELR/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 |
|
||||
| TRX/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 |
|
||||
| BTC/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 |
|
||||
| TOTAL | 456 | 8.04 | 3668.37 | 3672.038 | 367.20 | 4 days, 3:40:00 | 290 59 107 63.6 |
|
||||
=========================================================== BUY TAG STATS ===========================================================
|
||||
| TAG | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% |
|
||||
|-------+--------+----------------+----------------+-------------------+----------------+-----------------+-------------------------|
|
||||
| TOTAL | 456 | 8.04 | 3668.37 | 3672.038 | 367.20 | 4 days, 3:40:00 | 290 59 107 63.6 |
|
||||
===================================================== SELL REASON STATS =====================================================
|
||||
| Sell Reason | Sells | Win Draws Loss Win% | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % |
|
||||
|---------------+---------+--------------------------+----------------+----------------+-------------------+----------------|
|
||||
| roi | 316 | 257 59 0 100 | 16.93 | 5351.22 | 5356.57 | 356.75 |
|
||||
| sell_signal | 81 | 32 0 49 39.5 | -1.14 | -92.04 | -92.136 | -6.14 |
|
||||
| stop_loss | 56 | 0 0 56 0 | -28.14 | -1576.06 | -1577.63 | -105.07 |
|
||||
| force_sell | 3 | 1 0 2 33.3 | -4.92 | -14.75 | -14.763 | -0.98 |
|
||||
========================================================= LEFT OPEN TRADES REPORT =========================================================
|
||||
| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% |
|
||||
|-----------+--------+----------------+----------------+-------------------+----------------+-------------------+-------------------------|
|
||||
| EGLD/USDT | 1 | 8.35 | 8.35 | 8.353 | 0.84 | 1 day, 12:00:00 | 1 0 0 100 |
|
||||
| SOL/USDT | 1 | -10.94 | -10.94 | -10.952 | -1.10 | 8 days, 12:30:00 | 0 0 1 0 |
|
||||
| XRP/USDT | 1 | -12.15 | -12.15 | -12.165 | -1.22 | 10 days, 12:20:00 | 0 0 1 0 |
|
||||
| TOTAL | 3 | -4.92 | -14.75 | -14.763 | -1.48 | 6 days, 20:17:00 | 1 0 2 33.3 |
|
||||
=============== SUMMARY METRICS ================
|
||||
| Metric | Value |
|
||||
|------------------------+---------------------|
|
||||
| Backtesting from | 2021-01-01 00:00:00 |
|
||||
| Backtesting to | 2021-11-20 00:00:00 |
|
||||
| Max open trades | 15 |
|
||||
| | |
|
||||
| Total/Daily Avg Trades | 456 / 1.41 |
|
||||
| Starting balance | 1000.000 USDT |
|
||||
| Final balance | 4672.038 USDT |
|
||||
| Absolute profit | 3672.038 USDT |
|
||||
| Total profit % | 367.20% |
|
||||
| Trades per day | 1.41 |
|
||||
| Avg. daily profit % | 1.14% |
|
||||
| Avg. stake amount | 100.000 USDT |
|
||||
| Total trade volume | 45600.000 USDT |
|
||||
| | |
|
||||
| Best Pair | SAND/USDT 1850.99% |
|
||||
| Worst Pair | ZEC/USDT 0.00% |
|
||||
| Best trade | SAND/USDT 1576.03% |
|
||||
| Worst trade | ETH/USDT -28.14% |
|
||||
| Best day | 1577.608 USDT |
|
||||
| Worst day | -197.204 USDT |
|
||||
| Days win/draw/lose | 170 / 98 / 55 |
|
||||
| Avg. Duration Winners | 3 days, 15:35:00 |
|
||||
| Avg. Duration Loser | 3 days, 18:33:00 |
|
||||
| Rejected Buy signals | 0 |
|
||||
| | |
|
||||
| Min balance | 1015.800 USDT |
|
||||
| Max balance | 4686.801 USDT |
|
||||
| Drawdown | 362.40% |
|
||||
| Drawdown | 362.761 USDT |
|
||||
| Drawdown high | 1116.607 USDT |
|
||||
| Drawdown low | 753.846 USDT |
|
||||
| Drawdown Start | 2021-05-12 21:55:00 |
|
||||
| Drawdown End | 2021-06-22 12:45:00 |
|
||||
| Market change | 2716.79% |
|
||||
================================================
|
||||
29
DevilStra2.json
Normal file
29
DevilStra2.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"strategy_name": "DevilStra2",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 0.574,
|
||||
"1757": 0.158,
|
||||
"3804": 0.089,
|
||||
"6585": 0
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -0.28
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": null,
|
||||
"trailing_stop_positive_offset": 0.0,
|
||||
"trailing_only_offset_is_reached": false
|
||||
},
|
||||
"buy": {
|
||||
"buy_spell": "De,De,Si,Zi,Si,Ra,Lu,Gu,Ra,Pa,Ra,La,La,Ra,Ra,Zi,La,Gu,De,Ra,Zi,Cu,Cu,La,Lu,Si,Pa,Zi,Zi,Ra,Cu,De,Zi,Zi,Si,Gu,La,Zi,Zi,Gu,Zi,La,Pa,Pa,Gu,Gu,Pa,De,Pa,Lu,La,La,Gu,Ra,Lu,Zi,Pa,Lu,Gu,De,Si,Cu,Gu,La,Zi,Gu,Cu,Si,Pa,La,La,Lu,Cu,Gu,Si,Lu,Ra,De,Si,Lu,Si,La,Si,Cu,De,Lu,Pa,Gu,Pa,Si,Gu,Lu,Lu,Cu,Lu,De,Cu,Pa,De,Pa,Si,Si,Lu,Pa,La,Gu,Pa,Si,Cu,Gu,Zi,La,Lu,Lu,Zi,De,La,La,Zi,La,Gu,Pa,Cu,Pa,Gu,Pa,Gu,Gu,Ra,Lu,Lu,Zi,De,Ra,Lu,La,Lu,De,Si,Lu,Ra,Si,Si,La,Pa,Lu,Zi,Zi,Cu,Cu,Ra,Si,De,Ra,Ra,Lu,La,Zi,De,Pa,Pa,Si,Zi,Gu,De,Gu,Ra,Cu,Pa,Lu,De,Pa,La,Lu,Cu,Ra,Pa,Cu,Cu,Ra,Gu,Zi,La,Si,Zi,La,Si,De,Cu,Ra,Si,Gu,Si,De,Si,Ra,Pa,Gu,Gu,Pa,Si,Zi,Si,Cu,La,Si,De,Cu,Lu,De,Zi,Si,Pa,Gu,Cu,Si,Pa,Gu,De,La,Ra,Pa,Ra,La,Ra,Ra,La,Pa,Ra,La,Cu,De,Lu,Ra,Si,Ra,Cu,Pa,Si,Zi,Gu,De,Cu,De,Lu,Pa,Zi,La,La,La,La,Lu,La,Lu,Cu,Zi,Zi,Zi,La,Si,Ra,De,Lu,Ra,Si,Ra,De,Pa,Lu"
|
||||
},
|
||||
"sell": {
|
||||
"sell_spell": "La,Pa,De,De,La,Si,Si,La,La,La,Si,Pa,Pa,Lu,De,Cu,Cu,Gu,Lu,Ra,Lu,Si,Ra,De,La,Cu,La,La,Gu,La,De,Ra,Ra,Ra,Gu,Lu,Si,Si,Zi,Zi,La,Pa,Pa,Zi,Cu,Gu,Gu,Pa,Gu,Cu,Si,Ra,Ra,La,Gu,De,Si,La,Ra,Pa,Si,Lu,Pa,De,Zi,De,Lu,Si,Gu,De,Lu,De,Ra,Ra,Zi,De,Cu,Zi,Gu,Pa,Ra,De,Pa,De,Pa,Ra,Si,Si,Zi,Cu,Lu,Zi,Ra,De,Ra,Zi,Zi,Pa,Lu,Zi,Cu,Pa,Gu,Pa,Cu,De,Zi,De,De,Pa,Pa,Zi,Lu,Ra,Pa,Ra,Lu,Zi,Gu,Zi,Si,Lu,Ra,Ra,Zi,Lu,Pa,Lu,Si,Pa,Pa,Pa,Si,Zi,La,La,Lu,De,Zi,Gu,Ra,Ra,Ra,Zi,Pa,Zi,Cu,Lu,Gu,Cu,De,Lu,Gu,Lu,Gu,Si,Pa,Pa,Si,La,Gu,Ra,Pa,Si,Si,Si,Cu,Cu,Cu,Si,De,Lu,Gu,Gu,Lu,De,Ra,Gu,Gu,Gu,Cu,La,De,Cu,Zi,Pa,Si,De,Pa,Pa,Pa,La,De,Gu,Zi,La,De,Cu,La,Pa,Ra,Si,Si,Zi,Cu,Ra,Pa,Gu,Pa,Ra,Zi,De,Zi,Gu,Gu,Pa,Cu,Lu,Gu,De,Si,Pa,La,Cu,Zi,Gu,De,Gu,La,Cu,Gu,De,Cu,Cu,Gu,Ra,Lu,Zi,De,La,Ra,Pa,Pa,Si,La,Lu,La,De,De,Ra,De,La,La,Pa,Cu,Lu,Pa,Ra,Pa,Pa,Cu,Zi,Gu,Cu,Gu,La,Si,Ra,Pa"
|
||||
},
|
||||
"protection": {}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-03-04 13:36:54.394335+00:00"
|
||||
}
|
||||
658
DevilStra2.py
Normal file
658
DevilStra2.py
Normal file
@@ -0,0 +1,658 @@
|
||||
# DevilStra Strategy
|
||||
# 𝔇𝔢𝔳𝔦𝔩 𝔦𝔰 𝔞𝔩𝔴𝔞𝔶𝔰 𝔰𝔱𝔯𝔬𝔫𝔤𝔢𝔯 𝔱𝔥𝔞𝔫 𝔊𝔬𝔡.
|
||||
# 𝔅𝔲𝔱 𝔱𝔥𝔢 𝔬𝔫𝔩𝔶 𝔬𝔫𝔢 𝔴𝔥𝔬 𝔥𝔞𝔰 𝔱𝔥𝔢 𝔞𝔟𝔦𝔩𝔦𝔱𝔶
|
||||
# 𝔗𝔬 𝔠𝔯𝔢𝔞𝔱𝔢 𝔫𝔢𝔴 𝔠𝔯𝔢𝔞𝔱𝔲𝔯𝔢𝔰 𝔦𝔰 𝔊𝔬𝔡.
|
||||
# 𝔄𝔫𝔡 𝔱𝔥𝔢 𝔇𝔢𝔳𝔦𝔩 𝔪𝔞𝔨𝔢𝔰 𝔭𝔬𝔴𝔢𝔯𝔣𝔲𝔩 𝔰𝔭𝔢𝔩𝔩𝔰
|
||||
# 𝔉𝔯𝔬𝔪 𝔱𝔥𝔦𝔰 𝔰𝔪𝔞𝔩𝔩 𝔠𝔯𝔢𝔞𝔱𝔲𝔯𝔢𝔰 (𝔩𝔦𝔨𝔢 𝔣𝔯𝔬𝔤𝔰, 𝔢𝔱𝔠.)
|
||||
# 𝔚𝔦𝔱𝔥 𝔣𝔯𝔞𝔤𝔪𝔢𝔫𝔱𝔞𝔱𝔦𝔬𝔫 𝔞𝔫𝔡 𝔪𝔦𝔵𝔦𝔫𝔤 𝔱𝔥𝔢𝔪.
|
||||
# Author: @Mablue (Masoud Azizi)
|
||||
# github: https://github.com/mablue/
|
||||
# * IMPORTANT: You Need An "STATIC" Pairlist On Your Config.json !
|
||||
# * IMPORTANT: First set PAIR_LIST_LENGHT={pair_whitelist size}
|
||||
# * And re-hyperopt the Sell strategy And paste result in exact
|
||||
# * place(lines 535~564)
|
||||
|
||||
# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell -s 𝕯𝖊𝖛𝖎𝖑𝕾𝖙𝖗𝖆
|
||||
|
||||
# --- Do not remove these libs ---
|
||||
import numpy as np
|
||||
from functools import reduce
|
||||
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||
import talib.abstract as ta
|
||||
import random
|
||||
from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter
|
||||
|
||||
from numpy.lib import math
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
from pandas import DataFrame
|
||||
|
||||
# ########################## SETTINGS ##############################
|
||||
# pairlist lenght(use exact count of pairs you used in whitelist size+1):
|
||||
PAIR_LIST_LENGHT = 269
|
||||
# you can find exact value of this inside GodStraNew
|
||||
TREND_CHECK_CANDLES = 4
|
||||
# Set the pain range of devil(2~9999)
|
||||
PAIN_RANGE = 1000
|
||||
# Add "GodStraNew" Generated Results As spells inside SPELLS.
|
||||
# Set them unic phonemes like 'Zi' 'Gu' or 'Lu'!
|
||||
# * Use below replacement on GodStraNew results to
|
||||
# * Change God Generated Creatures to Spells:
|
||||
# +-----------------------------+----------------------+
|
||||
# | GodStraNew Hyperopt Results | DevilStra Spells |
|
||||
# +-----------------------------+----------------------+
|
||||
# | | "phonem" : { |
|
||||
# | buy_params = { | "buy_params" : { |
|
||||
# | ... | ... |
|
||||
# | } | }, |
|
||||
# | sell_params = { | "sell_params" : { |
|
||||
# | ... | ... |
|
||||
# | } | } |
|
||||
# | | }, |
|
||||
# +-----------------------------+----------------------+
|
||||
SPELLS = {
|
||||
"Zi": {
|
||||
"buy_params": {
|
||||
"buy_crossed_indicator0": "BOP-4",
|
||||
"buy_crossed_indicator1": "MACD-0-50",
|
||||
"buy_crossed_indicator2": "DEMA-52",
|
||||
"buy_indicator0": "MINUS_DI-50",
|
||||
"buy_indicator1": "HT_TRENDMODE-50",
|
||||
"buy_indicator2": "CORREL-128",
|
||||
"buy_operator0": "/>R",
|
||||
"buy_operator1": "CA",
|
||||
"buy_operator2": "CDT",
|
||||
"buy_real_num0": 0.1763,
|
||||
"buy_real_num1": 0.6891,
|
||||
"buy_real_num2": 0.0509,
|
||||
},
|
||||
"sell_params": {
|
||||
"sell_crossed_indicator0": "WCLPRICE-52",
|
||||
"sell_crossed_indicator1": "AROONOSC-15",
|
||||
"sell_crossed_indicator2": "CDLRISEFALL3METHODS-52",
|
||||
"sell_indicator0": "COS-50",
|
||||
"sell_indicator1": "CDLCLOSINGMARUBOZU-30",
|
||||
"sell_indicator2": "CDL2CROWS-130",
|
||||
"sell_operator0": "DT",
|
||||
"sell_operator1": ">R",
|
||||
"sell_operator2": "/>R",
|
||||
"sell_real_num0": 0.0678,
|
||||
"sell_real_num1": 0.8698,
|
||||
"sell_real_num2": 0.3917,
|
||||
}
|
||||
},
|
||||
"Gu": {
|
||||
"buy_params": {
|
||||
"buy_crossed_indicator0": "SMA-20",
|
||||
"buy_crossed_indicator1": "CDLLADDERBOTTOM-20",
|
||||
"buy_crossed_indicator2": "OBV-50",
|
||||
"buy_indicator0": "MAMA-1-50",
|
||||
"buy_indicator1": "SUM-40",
|
||||
"buy_indicator2": "VAR-30",
|
||||
"buy_operator0": "<R",
|
||||
"buy_operator1": "D",
|
||||
"buy_operator2": "D",
|
||||
"buy_real_num0": 0.2644,
|
||||
"buy_real_num1": 0.0736,
|
||||
"buy_real_num2": 0.8954,
|
||||
},
|
||||
"sell_params": {
|
||||
"sell_crossed_indicator0": "CDLLADDERBOTTOM-50",
|
||||
"sell_crossed_indicator1": "CDLHARAMICROSS-50",
|
||||
"sell_crossed_indicator2": "CDLDARKCLOUDCOVER-30",
|
||||
"sell_indicator0": "CDLLADDERBOTTOM-10",
|
||||
"sell_indicator1": "MAMA-1-40",
|
||||
"sell_indicator2": "OBV-30",
|
||||
"sell_operator0": "UT",
|
||||
"sell_operator1": ">R",
|
||||
"sell_operator2": "CUT",
|
||||
"sell_real_num0": 0.2707,
|
||||
"sell_real_num1": 0.7987,
|
||||
"sell_real_num2": 0.6891,
|
||||
}
|
||||
},
|
||||
"Lu": {
|
||||
"buy_params": {
|
||||
"buy_crossed_indicator0": "HT_SINE-0-28",
|
||||
"buy_crossed_indicator1": "ADD-130",
|
||||
"buy_crossed_indicator2": "ADD-12",
|
||||
"buy_indicator0": "ADD-28",
|
||||
"buy_indicator1": "AVGPRICE-15",
|
||||
"buy_indicator2": "AVGPRICE-12",
|
||||
"buy_operator0": "DT",
|
||||
"buy_operator1": "D",
|
||||
"buy_operator2": "C",
|
||||
"buy_real_num0": 0.3676,
|
||||
"buy_real_num1": 0.4284,
|
||||
"buy_real_num2": 0.372,
|
||||
},
|
||||
"sell_params": {
|
||||
"sell_crossed_indicator0": "HT_SINE-0-5",
|
||||
"sell_crossed_indicator1": "HT_SINE-0-4",
|
||||
"sell_crossed_indicator2": "HT_SINE-0-28",
|
||||
"sell_indicator0": "ADD-30",
|
||||
"sell_indicator1": "AVGPRICE-28",
|
||||
"sell_indicator2": "ADD-50",
|
||||
"sell_operator0": "CUT",
|
||||
"sell_operator1": "DT",
|
||||
"sell_operator2": "=R",
|
||||
"sell_real_num0": 0.3205,
|
||||
"sell_real_num1": 0.2055,
|
||||
"sell_real_num2": 0.8467,
|
||||
}
|
||||
},
|
||||
"La": {
|
||||
"buy_params": {
|
||||
"buy_crossed_indicator0": "WMA-14",
|
||||
"buy_crossed_indicator1": "MAMA-1-14",
|
||||
"buy_crossed_indicator2": "CDLHIKKAKE-14",
|
||||
"buy_indicator0": "T3-14",
|
||||
"buy_indicator1": "BETA-14",
|
||||
"buy_indicator2": "HT_PHASOR-1-14",
|
||||
"buy_operator0": "/>R",
|
||||
"buy_operator1": ">",
|
||||
"buy_operator2": ">R",
|
||||
"buy_real_num0": 0.0551,
|
||||
"buy_real_num1": 0.3469,
|
||||
"buy_real_num2": 0.3871,
|
||||
},
|
||||
"sell_params": {
|
||||
"sell_crossed_indicator0": "HT_TRENDLINE-14",
|
||||
"sell_crossed_indicator1": "LINEARREG-14",
|
||||
"sell_crossed_indicator2": "STOCHRSI-1-14",
|
||||
"sell_indicator0": "CDLDARKCLOUDCOVER-14",
|
||||
"sell_indicator1": "AD-14",
|
||||
"sell_indicator2": "CDLSTALLEDPATTERN-14",
|
||||
"sell_operator0": "/=R",
|
||||
"sell_operator1": "COT",
|
||||
"sell_operator2": "OT",
|
||||
"sell_real_num0": 0.3992,
|
||||
"sell_real_num1": 0.7747,
|
||||
"sell_real_num2": 0.7415,
|
||||
}
|
||||
},
|
||||
"Si": {
|
||||
"buy_params": {
|
||||
"buy_crossed_indicator0": "MACDEXT-2-14",
|
||||
"buy_crossed_indicator1": "CORREL-14",
|
||||
"buy_crossed_indicator2": "CMO-14",
|
||||
"buy_indicator0": "MA-14",
|
||||
"buy_indicator1": "ADXR-14",
|
||||
"buy_indicator2": "CDLMARUBOZU-14",
|
||||
"buy_operator0": "<",
|
||||
"buy_operator1": "/<R",
|
||||
"buy_operator2": "<R",
|
||||
"buy_real_num0": 0.7883,
|
||||
"buy_real_num1": 0.8286,
|
||||
"buy_real_num2": 0.6512,
|
||||
},
|
||||
"sell_params": {
|
||||
"sell_crossed_indicator0": "AROON-1-14",
|
||||
"sell_crossed_indicator1": "STOCHRSI-0-14",
|
||||
"sell_crossed_indicator2": "SMA-14",
|
||||
"sell_indicator0": "T3-14",
|
||||
"sell_indicator1": "AROONOSC-14",
|
||||
"sell_indicator2": "MIDPOINT-14",
|
||||
"sell_operator0": "C",
|
||||
"sell_operator1": "CA",
|
||||
"sell_operator2": "CB",
|
||||
"sell_real_num0": 0.372,
|
||||
"sell_real_num1": 0.5948,
|
||||
"sell_real_num2": 0.9872,
|
||||
}
|
||||
},
|
||||
"Pa": {
|
||||
"buy_params": {
|
||||
"buy_crossed_indicator0": "AROON-0-60",
|
||||
"buy_crossed_indicator1": "APO-60",
|
||||
"buy_crossed_indicator2": "BBANDS-0-60",
|
||||
"buy_indicator0": "WILLR-12",
|
||||
"buy_indicator1": "AD-15",
|
||||
"buy_indicator2": "MINUS_DI-12",
|
||||
"buy_operator0": "D",
|
||||
"buy_operator1": ">",
|
||||
"buy_operator2": "CA",
|
||||
"buy_real_num0": 0.2208,
|
||||
"buy_real_num1": 0.1371,
|
||||
"buy_real_num2": 0.6389,
|
||||
},
|
||||
"sell_params": {
|
||||
"sell_crossed_indicator0": "MACDEXT-0-15",
|
||||
"sell_crossed_indicator1": "BBANDS-2-15",
|
||||
"sell_crossed_indicator2": "DEMA-15",
|
||||
"sell_indicator0": "ULTOSC-15",
|
||||
"sell_indicator1": "MIDPOINT-12",
|
||||
"sell_indicator2": "PLUS_DI-12",
|
||||
"sell_operator0": "<",
|
||||
"sell_operator1": "DT",
|
||||
"sell_operator2": "COT",
|
||||
"sell_real_num0": 0.278,
|
||||
"sell_real_num1": 0.0643,
|
||||
"sell_real_num2": 0.7065,
|
||||
}
|
||||
},
|
||||
"De": {
|
||||
"buy_params": {
|
||||
"buy_crossed_indicator0": "HT_DCPERIOD-12",
|
||||
"buy_crossed_indicator1": "HT_PHASOR-0-12",
|
||||
"buy_crossed_indicator2": "MACDFIX-1-15",
|
||||
"buy_indicator0": "CMO-12",
|
||||
"buy_indicator1": "TRIMA-12",
|
||||
"buy_indicator2": "MACDEXT-0-15",
|
||||
"buy_operator0": "<",
|
||||
"buy_operator1": "D",
|
||||
"buy_operator2": "<",
|
||||
"buy_real_num0": 0.3924,
|
||||
"buy_real_num1": 0.5546,
|
||||
"buy_real_num2": 0.7648,
|
||||
},
|
||||
"sell_params": {
|
||||
"sell_crossed_indicator0": "MACDFIX-1-15",
|
||||
"sell_crossed_indicator1": "MACD-1-15",
|
||||
"sell_crossed_indicator2": "WMA-15",
|
||||
"sell_indicator0": "ROC-15",
|
||||
"sell_indicator1": "MACD-2-15",
|
||||
"sell_indicator2": "CCI-60",
|
||||
"sell_operator0": "CA",
|
||||
"sell_operator1": "<R",
|
||||
"sell_operator2": "/<R",
|
||||
"sell_real_num0": 0.4989,
|
||||
"sell_real_num1": 0.4131,
|
||||
"sell_real_num2": 0.8904,
|
||||
}
|
||||
},
|
||||
"Ra": {
|
||||
"buy_params": {
|
||||
"buy_crossed_indicator0": "EMA-110",
|
||||
"buy_crossed_indicator1": "SMA-5",
|
||||
"buy_crossed_indicator2": "SMA-6",
|
||||
"buy_indicator0": "SMA-6",
|
||||
"buy_indicator1": "EMA-12",
|
||||
"buy_indicator2": "EMA-5",
|
||||
"buy_operator0": "D",
|
||||
"buy_operator1": "<",
|
||||
"buy_operator2": "/<R",
|
||||
"buy_real_num0": 0.9814,
|
||||
"buy_real_num1": 0.5528,
|
||||
"buy_real_num2": 0.0541,
|
||||
},
|
||||
"sell_params": {
|
||||
"sell_crossed_indicator0": "SMA-50",
|
||||
"sell_crossed_indicator1": "EMA-12",
|
||||
"sell_crossed_indicator2": "SMA-100",
|
||||
"sell_indicator0": "EMA-110",
|
||||
"sell_indicator1": "EMA-50",
|
||||
"sell_indicator2": "EMA-15",
|
||||
"sell_operator0": "<",
|
||||
"sell_operator1": "COT",
|
||||
"sell_operator2": "/=R",
|
||||
"sell_real_num0": 0.3506,
|
||||
"sell_real_num1": 0.8767,
|
||||
"sell_real_num2": 0.0614,
|
||||
}
|
||||
},
|
||||
"Cu": {
|
||||
"buy_params": {
|
||||
"buy_crossed_indicator0": "SMA-110",
|
||||
"buy_crossed_indicator1": "SMA-110",
|
||||
"buy_crossed_indicator2": "SMA-5",
|
||||
"buy_indicator0": "SMA-110",
|
||||
"buy_indicator1": "SMA-55",
|
||||
"buy_indicator2": "SMA-15",
|
||||
"buy_operator0": "<R",
|
||||
"buy_operator1": "<",
|
||||
"buy_operator2": "CA",
|
||||
"buy_real_num0": 0.5,
|
||||
"buy_real_num1": 0.7,
|
||||
"buy_real_num2": 0.9,
|
||||
},
|
||||
"sell_params": {
|
||||
"sell_crossed_indicator0": "SMA-55",
|
||||
"sell_crossed_indicator1": "SMA-50",
|
||||
"sell_crossed_indicator2": "SMA-100",
|
||||
"sell_indicator0": "SMA-5",
|
||||
"sell_indicator1": "SMA-50",
|
||||
"sell_indicator2": "SMA-50",
|
||||
"sell_operator0": "/=R",
|
||||
"sell_operator1": "CUT",
|
||||
"sell_operator2": "DT",
|
||||
"sell_real_num0": 0.4,
|
||||
"sell_real_num1": 0.2,
|
||||
"sell_real_num2": 0.7,
|
||||
}
|
||||
}
|
||||
}
|
||||
# ######################## END SETTINGS ############################
|
||||
|
||||
|
||||
def spell_finder(index, space):
|
||||
return SPELLS[index][space+"_params"]
|
||||
|
||||
|
||||
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):
|
||||
|
||||
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] > dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "=":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "<":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "C":
|
||||
condition = (
|
||||
(qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) |
|
||||
(qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator]))
|
||||
)
|
||||
elif operator == "CA":
|
||||
condition = (
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "CB":
|
||||
condition = (
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == ">R":
|
||||
condition = (
|
||||
dataframe[indicator] > real_num
|
||||
)
|
||||
elif operator == "=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], real_num)
|
||||
)
|
||||
elif operator == "<R":
|
||||
condition = (
|
||||
dataframe[indicator] < real_num
|
||||
)
|
||||
elif operator == "/>R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) > real_num
|
||||
)
|
||||
elif operator == "/=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator].div(
|
||||
dataframe[crossed_indicator]), real_num)
|
||||
)
|
||||
elif operator == "/<R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) < real_num
|
||||
)
|
||||
elif operator == "UT":
|
||||
condition = (
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "DT":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "OT":
|
||||
condition = (
|
||||
|
||||
np.isclose(dataframe[indicator], dataframe[indicator_trend_sma])
|
||||
)
|
||||
elif operator == "CUT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "CDT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "COT":
|
||||
condition = (
|
||||
(
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) |
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
) &
|
||||
(
|
||||
np.isclose(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return condition, dataframe
|
||||
|
||||
|
||||
class DevilStra2(IStrategy):
|
||||
# #################### RESULT PASTE PLACE ####################
|
||||
# 16/16: 108 trades. 75/18/15 Wins/Draws/Losses. Avg profit 7.77%. Median profit 8.89%. Total profit 0.08404983 BTC ( 84.05Σ%). Avg duration 3 days, 6:49:00 min. Objective: -11.22849
|
||||
|
||||
# Buy hyperspace params:
|
||||
buy_params = {
|
||||
"buy_spell": "Zi,Lu,Ra,Ra,La,Si,Pa,Si,Cu,La,De,Lu,De,La,Zi,Zi,Zi,Zi,Zi,Lu,Lu,Lu,Si,La,Ra,Pa,La,Zi,Zi,Gu,Ra,De,Gu,Zi,Ra,Ra,Ra,Cu,Pa,De,De,La,Lu,Lu,Lu,La,Zi,Cu,Ra,Gu,Pa,La,Zi,Zi,Si,Lu,Ra,Cu,Cu,Pa,Si,Gu,De,De,Lu,Gu,Zi,Pa,Lu,Pa,Ra,Gu,Cu,La,Pa,Lu,Zi,La,Zi,Gu,Zi,De,Cu,Ra,Lu,Ra,Gu,Si,Ra,La,La,Lu,Gu,Zi,Si,La,Pa,Pa,Cu,Cu,Zi,Gu,Pa,Zi,Pa,Cu,Lu,Pa,Si,De,Gu,Lu,Lu,Cu,Ra,Si,Pa,Gu,Si,Cu,Pa,Zi,Pa,Zi,Gu,Lu,Ra,Pa,Ra,De,Ra,Pa,Zi,La,Pa,De,Pa,Cu,Gu,De,Lu,La,Ra,Zi,Si,Zi,Zi,Cu,Cu,De,Pa,Pa,Zi,De,Ra,La,Lu,De,Lu,Gu,Cu,Cu,La,De,Gu,Lu,Ra,Pa,Lu,Cu,Pa,Pa,De,Si,Zi,Cu,De,De,De,Lu,Si,Zi,Gu,Si,Si,Ra,Pa,Si,La,La,Lu,Lu,De,Gu,Gu,Zi,Ra,La,Lu,Lu,La,Si,Zi,Si,Zi,Si,Lu,Cu,Zi,Lu,De,La,Ra,Ra,Lu,De,Pa,Zi,Gu,Cu,Zi,Pa,De,Si,Lu,De,Cu,De,Zi,Ra,Gu,De,Si,Lu,Lu,Ra,De,Gu,Cu,Gu,La,De,Lu,Lu,Si,Cu,Lu,Zi,Lu,Cu,Gu,Lu,Lu,Ra,Si,Ra,Pa,Lu,De,Ra,Zi,Gu,Gu,Zi,Lu,Cu,Cu,Cu,Lu",
|
||||
}
|
||||
|
||||
# Sell hyperspace params:
|
||||
sell_params = {
|
||||
"sell_spell": "La,Pa,De,De,La,Si,Si,La,La,La,Si,Pa,Pa,Lu,De,Cu,Cu,Gu,Lu,Ra,Lu,Si,Ra,De,La,Cu,La,La,Gu,La,De,Ra,Ra,Ra,Gu,Lu,Si,Si,Zi,Zi,La,Pa,Pa,Zi,Cu,Gu,Gu,Pa,Gu,Cu,Si,Ra,Ra,La,Gu,De,Si,La,Ra,Pa,Si,Lu,Pa,De,Zi,De,Lu,Si,Gu,De,Lu,De,Ra,Ra,Zi,De,Cu,Zi,Gu,Pa,Ra,De,Pa,De,Pa,Ra,Si,Si,Zi,Cu,Lu,Zi,Ra,De,Ra,Zi,Zi,Pa,Lu,Zi,Cu,Pa,Gu,Pa,Cu,De,Zi,De,De,Pa,Pa,Zi,Lu,Ra,Pa,Ra,Lu,Zi,Gu,Zi,Si,Lu,Ra,Ra,Zi,Lu,Pa,Lu,Si,Pa,Pa,Pa,Si,Zi,La,La,Lu,De,Zi,Gu,Ra,Ra,Ra,Zi,Pa,Zi,Cu,Lu,Gu,Cu,De,Lu,Gu,Lu,Gu,Si,Pa,Pa,Si,La,Gu,Ra,Pa,Si,Si,Si,Cu,Cu,Cu,Si,De,Lu,Gu,Gu,Lu,De,Ra,Gu,Gu,Gu,Cu,La,De,Cu,Zi,Pa,Si,De,Pa,Pa,Pa,La,De,Gu,Zi,La,De,Cu,La,Pa,Ra,Si,Si,Zi,Cu,Ra,Pa,Gu,Pa,Ra,Zi,De,Zi,Gu,Gu,Pa,Cu,Lu,Gu,De,Si,Pa,La,Cu,Zi,Gu,De,Gu,La,Cu,Gu,De,Cu,Cu,Gu,Ra,Lu,Zi,De,La,Ra,Pa,Pa,Si,La,Lu,La,De,De,Ra,De,La,La,Pa,Cu,Lu,Pa,Ra,Pa,Pa,Cu,Zi,Gu,Cu,Gu,La,Si,Ra,Pa",
|
||||
}
|
||||
|
||||
# ROI table:
|
||||
minimal_roi = {
|
||||
"0": 0.574,
|
||||
"1757": 0.158,
|
||||
"3804": 0.089,
|
||||
"6585": 0
|
||||
}
|
||||
|
||||
# Stoploss:
|
||||
stoploss = -0.28
|
||||
# #################### END OF RESULT PLACE ####################
|
||||
|
||||
# 𝖂𝖔𝖗𝖘𝖙, 𝖀𝖓𝖎𝖉𝖊𝖆𝖑, 𝕾𝖚𝖇𝖔𝖕𝖙𝖎𝖒𝖆𝖑, 𝕸𝖆𝖑𝖆𝖕𝖗𝖔𝖕𝖔𝖘 𝕬𝖓𝖉 𝕯𝖎𝖘𝖒𝖆𝖑 𝖙𝖎𝖒𝖊𝖋𝖗𝖆𝖒𝖊 𝖋𝖔𝖗 𝖙𝖍𝖎𝖘 𝖘𝖙𝖗𝖆𝖙𝖊𝖌𝖞:
|
||||
timeframe = '4h'
|
||||
|
||||
spell_pot = [
|
||||
",".join(
|
||||
tuple(
|
||||
random.choices(
|
||||
list(SPELLS.keys()),
|
||||
# TODO: k will be change to len(pairlist)
|
||||
k=PAIR_LIST_LENGHT
|
||||
)
|
||||
)
|
||||
)for i in range(PAIN_RANGE)
|
||||
]
|
||||
|
||||
buy_spell = CategoricalParameter(
|
||||
spell_pot, default=spell_pot[0], space='buy')
|
||||
sell_spell = CategoricalParameter(
|
||||
spell_pot, default=spell_pot[0], space='sell')
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
pairs = self.dp.current_whitelist()
|
||||
pairs_len = len(pairs)
|
||||
pair_index = pairs.index(metadata['pair'])
|
||||
|
||||
buy_spells = self.buy_spell.value.split(",")
|
||||
buy_spells_len = len(buy_spells)
|
||||
|
||||
if pairs_len > buy_spells_len:
|
||||
print(
|
||||
f"First set PAIR_LIST_LENGHT={pairs_len + 1} And re-hyperopt the")
|
||||
print("Buy strategy And paste result in exact place(lines 535~564)")
|
||||
print("IMPORTANT: You Need An 'STATIC' Pairlist On Your Config.json !!!")
|
||||
exit()
|
||||
|
||||
buy_params_index = buy_spells[pair_index]
|
||||
|
||||
params = spell_finder(buy_params_index, 'buy')
|
||||
conditions = list()
|
||||
# TODO: Its not dry code!
|
||||
buy_indicator = params['buy_indicator0']
|
||||
buy_crossed_indicator = params['buy_crossed_indicator0']
|
||||
buy_operator = params['buy_operator0']
|
||||
buy_real_num = params['buy_real_num0']
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
# backup
|
||||
buy_indicator = params['buy_indicator1']
|
||||
buy_crossed_indicator = params['buy_crossed_indicator1']
|
||||
buy_operator = params['buy_operator1']
|
||||
buy_real_num = params['buy_real_num1']
|
||||
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
buy_indicator = params['buy_indicator2']
|
||||
buy_crossed_indicator = params['buy_crossed_indicator2']
|
||||
buy_operator = params['buy_operator2']
|
||||
buy_real_num = params['buy_real_num2']
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
'buy']=1
|
||||
|
||||
# print(len(dataframe.keys()))
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
return dataframe
|
||||
155
Diamond.py
Normal file
155
Diamond.py
Normal file
@@ -0,0 +1,155 @@
|
||||
# 𝐼𝓉 𝒾𝓈 𝒟𝒾𝒶𝓂𝑜𝓃𝒹 𝒮𝓉𝓇𝒶𝓉𝑒𝑔𝓎.
|
||||
# 𝒯𝒽𝒶𝓉 𝓉𝒶𝓀𝑒𝓈 𝒽𝑒𝓇 𝑜𝓌𝓃 𝓇𝒾𝑔𝒽𝓉𝓈 𝓁𝒾𝓀𝑒 𝒜𝒻𝑔𝒽𝒶𝓃𝒾𝓈𝓉𝒶𝓃 𝓌𝑜𝓂𝑒𝓃
|
||||
# 𝒯𝒽𝑜𝓈𝑒 𝓌𝒽𝑜 𝓈𝓉𝒾𝓁𝓁 𝓅𝓇𝑜𝓊𝒹 𝒶𝓃𝒹 𝒽𝑜𝓅𝑒𝒻𝓊𝓁.
|
||||
# 𝒯𝒽𝑜𝓈𝑒 𝓌𝒽𝑜 𝓉𝒽𝑒 𝓂𝑜𝓈𝓉 𝒷𝑒𝒶𝓊𝓉𝒾𝒻𝓊𝓁 𝒸𝓇𝑒𝒶𝓉𝓊𝓇𝑒𝓈 𝒾𝓃 𝓉𝒽𝑒 𝒹𝑒𝓅𝓉𝒽𝓈 𝑜𝒻 𝓉𝒽𝑒 𝒹𝒶𝓇𝓀𝑒𝓈𝓉.
|
||||
# 𝒯𝒽𝑜𝓈𝑒 𝓌𝒽𝑜 𝓈𝒽𝒾𝓃𝑒 𝓁𝒾𝓀𝑒 𝒹𝒾𝒶𝓂𝑜𝓃𝒹𝓈 𝒷𝓊𝓇𝒾𝑒𝒹 𝒾𝓃 𝓉𝒽𝑒 𝒽𝑒𝒶𝓇𝓉 𝑜𝒻 𝓉𝒽𝑒 𝒹𝑒𝓈𝑒𝓇𝓉 ...
|
||||
# 𝒲𝒽𝓎 𝓃𝑜𝓉 𝒽𝑒𝓁𝓅 𝓌𝒽𝑒𝓃 𝓌𝑒 𝒸𝒶𝓃?
|
||||
# 𝐼𝒻 𝓌𝑒 𝒷𝑒𝓁𝒾𝑒𝓋𝑒 𝓉𝒽𝑒𝓇𝑒 𝒾𝓈 𝓃𝑜 𝓂𝒶𝓃 𝓁𝑒𝒻𝓉 𝓌𝒾𝓉𝒽 𝓉𝒽𝑒𝓂
|
||||
# (𝒲𝒽𝒾𝒸𝒽 𝒾𝓈 𝓅𝓇𝑜𝒷𝒶𝒷𝓁𝓎 𝓉𝒽𝑒 𝓅𝓇𝑜𝒹𝓊𝒸𝓉 𝑜𝒻 𝓉𝒽𝑒 𝓉𝒽𝑜𝓊𝑔𝒽𝓉 𝑜𝒻 𝓅𝒶𝒾𝓃𝓁𝑒𝓈𝓈 𝒸𝑜𝓇𝓅𝓈𝑒𝓈)
|
||||
# 𝒲𝒽𝑒𝓇𝑒 𝒽𝒶𝓈 𝑜𝓊𝓇 𝒽𝓊𝓂𝒶𝓃𝒾𝓉𝓎 𝑔𝑜𝓃𝑒?
|
||||
# 𝒲𝒽𝑒𝓇𝑒 𝒽𝒶𝓈 𝒽𝓊𝓂𝒶𝓃𝒾𝓉𝓎 𝑔𝑜𝓃𝑒?
|
||||
# 𝒲𝒽𝓎 𝓃𝑜𝓉 𝒽𝑒𝓁𝓅 𝓌𝒽𝑒𝓃 𝓌𝑒 𝒸𝒶𝓃?
|
||||
# 𝓁𝑒𝓉𝓈 𝓅𝒾𝓅 𝓊𝓃𝒾𝓃𝓈𝓉𝒶𝓁𝓁 𝓉𝒶-𝓁𝒾𝒷 𝑜𝓃 𝒜𝒻𝑔𝒽𝒶𝓃𝒾𝓈𝓉𝒶𝓃
|
||||
|
||||
# IMPORTANT: Diamond strategy is designed to be pure and
|
||||
# cuz of that it have not any indicator population. idea is that
|
||||
# It is just use the pure dataframe ohlcv data for calculation
|
||||
# of buy/sell signals, But you can add your indicators and add
|
||||
# your key names inside catagorical hyperoptable params and
|
||||
# than you be able to hyperopt them as well.
|
||||
# thanks to: @Kroissan, @drakes00 And @xmatthias for his patience and helps
|
||||
# Author: @Mablue (Masoud Azizi)
|
||||
# github: https://github.com/mablue/
|
||||
# * freqtrade backtesting --strategy Diamond
|
||||
|
||||
# freqtrade hyperopt --hyperopt-loss ShortTradeDurHyperOptLoss --spaces buy sell roi trailing stoploss --strategy Diamond -j 2 -e 10
|
||||
# * 3/10: 76 trades. 51/18/7 Wins/Draws/Losses. Avg profit 1.92%. Median profit 2.40%. Total profit 0.04808472 BTC ( 48.08%). Avg duration 5:06:00 min. Objective: 1.75299
|
||||
# freqtrade hyperopt --hyperopt-loss OnlyProfitHyperOptLoss --spaces buy sell roi trailing stoploss --strategy Diamond -j 2 -e 10
|
||||
# * 10/10: 76 trades. 39/34/3 Wins/Draws/Losses. Avg profit 0.61%. Median profit 0.05%. Total profit 0.01528359 BTC ( 15.28%). Avg duration 17:32:00 min. Objective: -0.01528
|
||||
# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces buy sell roi trailing stoploss --strategy Diamond -j 2 -e 10
|
||||
# * 4/10: 15 trades. 10/2/3 Wins/Draws/Losses. Avg profit 1.52%. Median profit 7.99%. Total profit 0.00754274 BTC ( 7.54%). Avg duration 1 day, 0:04:00 min. Objective: -0.90653
|
||||
# freqtrade hyperopt --hyperopt-loss SharpeHyperOptLossDaily --spaces buy sell roi trailing stoploss --strategy Diamond -j 2 -e 10
|
||||
# * 7/10: 130 trades. 68/54/8 Wins/Draws/Losses. Avg profit 0.71%. Median profit 0.06%. Total profit 0.03050369 BTC ( 30.50%). Avg duration 10:07:00 min. Objective: -11.08185
|
||||
# freqtrade hyperopt --hyperopt-loss SortinoHyperOptLoss --spaces buy sell roi trailing stoploss --strategy Diamond -j 2 -e 10
|
||||
# * 2/10: 10 trades. 7/0/3 Wins/Draws/Losses. Avg profit 5.50%. Median profit 7.05%. Total profit 0.01817970 BTC ( 18.18%). Avg duration 0:27:00 min. Objective: -11.72450
|
||||
# freqtrade hyperopt --hyperopt-loss SortinoHyperOptLossDaily --spaces buy sell roi trailing stoploss --strategy Diamond -j 2 -e 10
|
||||
# | * Best | 3/10 | 165 | 98 63 4 | 1.00% | 0.05453885 BTC (54.54%) | 0 days 08:02:00 | 0.00442974 BTC (13.41%) | -41.371 |
|
||||
# | * Best | 7/10 | 101 | 56 42 3 | 0.73% | 0.02444518 BTC (24.45%) | 0 days 13:08:00 | 0.00107122 BTC (3.24%) | -66.7687 |
|
||||
# * 7/10: 101 trades. 56/42/3 Wins/Draws/Losses. Avg profit 0.73%. Median profit 0.13%. Total profit 0.02444518 BTC ( 24.45%). Avg duration 13:08:00 min. Objective: -66.76866
|
||||
# freqtrade hyperopt --hyperopt-loss OnlyProfitHyperOptLoss --spaces buy sell roi trailing stoploss --strategy Diamond -j 2 -e 10
|
||||
# * 7/10: 117 trades. 74/41/2 Wins/Draws/Losses. Avg profit 1.91%. Median profit 1.50%. Total profit 0.07370921 BTC ( 73.71%). Avg duration 9:26:00 min. Objective: -0.07371
|
||||
|
||||
# --- Do not remove these libs ---
|
||||
from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
from pandas import DataFrame
|
||||
# --------------------------------
|
||||
|
||||
# Add your lib to import here
|
||||
import talib.abstract as ta
|
||||
from functools import reduce
|
||||
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||
|
||||
|
||||
class Diamond(IStrategy):
|
||||
# ###################### RESULT PLACE ######################
|
||||
# Config: 5 x UNLIMITED STOCK costume pair list,
|
||||
# hyperopt : 5000 x SortinoHyperOptLossDaily,
|
||||
# 34/5000: 297 trades. 136/156/5 Wins/Draws/Losses. Avg profit 0.49%. Median profit 0.00%. Total profit 45.84477237 USDT ( 33.96Σ%). Avg duration 11:54:00 min. Objective: -46.50379
|
||||
|
||||
# Buy hyperspace params:
|
||||
buy_params = {
|
||||
"buy_fast_key": "high",
|
||||
"buy_horizontal_push": 7,
|
||||
"buy_slow_key": "volume",
|
||||
"buy_vertical_push": 0.942,
|
||||
}
|
||||
|
||||
# Sell hyperspace params:
|
||||
sell_params = {
|
||||
"sell_fast_key": "high",
|
||||
"sell_horizontal_push": 10,
|
||||
"sell_slow_key": "low",
|
||||
"sell_vertical_push": 1.184,
|
||||
}
|
||||
|
||||
# ROI table:
|
||||
minimal_roi = {
|
||||
"0": 0.242,
|
||||
"13": 0.044,
|
||||
"51": 0.02,
|
||||
"170": 0
|
||||
}
|
||||
|
||||
# Stoploss:
|
||||
stoploss = -0.271
|
||||
|
||||
# Trailing stop:
|
||||
trailing_stop = True
|
||||
trailing_stop_positive = 0.011
|
||||
trailing_stop_positive_offset = 0.054
|
||||
trailing_only_offset_is_reached = False
|
||||
# timeframe
|
||||
timeframe = '5m'
|
||||
# #################### END OF RESULT PLACE ####################
|
||||
|
||||
buy_vertical_push = DecimalParameter(0.5, 1.5, decimals=3, default=1, space='buy')
|
||||
buy_horizontal_push = IntParameter(0, 10, default=0, space='buy')
|
||||
buy_fast_key = CategoricalParameter(['open', 'high', 'low', 'close', 'volume',
|
||||
# you can not enable this lines befour you
|
||||
# populate an indicator for them and set
|
||||
# the same key name for it
|
||||
# 'ma_fast', 'ma_slow', {...}
|
||||
], default='ma_fast', space='buy')
|
||||
buy_slow_key = CategoricalParameter(['open', 'high', 'low', 'close', 'volume',
|
||||
# 'ma_fast', 'ma_slow', {...}
|
||||
], default='ma_slow', space='buy')
|
||||
|
||||
sell_vertical_push = DecimalParameter(0.5, 1.5, decimals=3, default=1, space='sell')
|
||||
sell_horizontal_push = IntParameter(0, 10, default=0, space='sell')
|
||||
sell_fast_key = CategoricalParameter(['open', 'high', 'low', 'close', 'volume',
|
||||
# 'ma_fast', 'ma_slow', {...}
|
||||
], default='ma_fast', space='sell')
|
||||
sell_slow_key = CategoricalParameter(['open', 'high', 'low', 'close', 'volume',
|
||||
# 'ma_fast', 'ma_slow', {...}
|
||||
], default='ma_slow', space='sell')
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
# you can add new indicators and enable them inside
|
||||
# hyperoptable categorical params on the top
|
||||
# dataframe['ma_fast'] = ta.SMA(dataframe, timeperiod=9)
|
||||
# dataframe['ma_slow'] = ta.SMA(dataframe, timeperiod=18)
|
||||
# dataframe['{...}'] = ta.{...}(dataframe, timeperiod={...})
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
conditions = []
|
||||
conditions.append(
|
||||
qtpylib.crossed_above
|
||||
(
|
||||
dataframe[self.buy_fast_key.value].shift(self.buy_horizontal_push.value),
|
||||
dataframe[self.buy_slow_key.value] * self.buy_vertical_push.value
|
||||
)
|
||||
)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
'buy']=1
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
conditions = []
|
||||
conditions.append(
|
||||
qtpylib.crossed_below
|
||||
(
|
||||
dataframe[self.sell_fast_key.value].shift(self.sell_horizontal_push.value),
|
||||
dataframe[self.sell_slow_key.value] * self.sell_vertical_push.value
|
||||
)
|
||||
)
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
'sell']=1
|
||||
return dataframe
|
||||
77
Diamond.txt
Normal file
77
Diamond.txt
Normal file
@@ -0,0 +1,77 @@
|
||||
Result for strategy Diamond
|
||||
========================================================== BACKTESTING REPORT ==========================================================
|
||||
| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% |
|
||||
|-----------+--------+----------------+----------------+-------------------+----------------+----------------+-------------------------|
|
||||
| CELR/USDT | 40 | 1.20 | 47.95 | 47.999 | 4.80 | 6:14:00 | 25 15 0 100 |
|
||||
| ETH/USDT | 432 | 0.09 | 39.39 | 39.431 | 3.94 | 14:42:00 | 197 226 9 45.6 |
|
||||
| ROSE/USDT | 60 | 0.64 | 38.12 | 38.154 | 3.82 | 7:32:00 | 29 31 0 100 |
|
||||
| SAND/USDT | 14 | 1.41 | 19.70 | 19.717 | 1.97 | 3:29:00 | 11 3 0 100 |
|
||||
| ADA/USDT | 7 | 0.86 | 5.99 | 6.000 | 0.60 | 9:27:00 | 3 4 0 100 |
|
||||
| AVAX/USDT | 7 | 0.86 | 5.99 | 6.000 | 0.60 | 3:30:00 | 3 4 0 100 |
|
||||
| XRP/USDT | 7 | 0.86 | 5.99 | 6.000 | 0.60 | 2:55:00 | 3 4 0 100 |
|
||||
| SOL/USDT | 4 | 0.86 | 3.43 | 3.435 | 0.34 | 3:36:00 | 2 2 0 100 |
|
||||
| IOTX/USDT | 78 | 0.03 | 2.58 | 2.582 | 0.26 | 8:35:00 | 37 39 2 47.4 |
|
||||
| BNB/USDT | 7 | 0.32 | 2.26 | 2.262 | 0.23 | 6:11:00 | 2 5 0 100 |
|
||||
| GALA/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 |
|
||||
| TRX/USDT | 2 | 0.00 | 0.00 | 0.000 | 0.00 | 12:42:00 | 0 2 0 0 |
|
||||
| BTC/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 |
|
||||
| EGLD/USDT | 300 | -0.13 | -39.93 | -39.973 | -4.00 | 14:28:00 | 134 156 10 44.7 |
|
||||
| ZEC/USDT | 277 | -0.25 | -69.80 | -69.865 | -6.99 | 15:57:00 | 137 130 10 49.5 |
|
||||
| TOTAL | 1235 | 0.05 | 61.68 | 61.742 | 6.17 | 13:32:00 | 583 621 31 47.2 |
|
||||
========================================================== BUY TAG STATS ===========================================================
|
||||
| TAG | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% |
|
||||
|-------+--------+----------------+----------------+-------------------+----------------+----------------+-------------------------|
|
||||
| TOTAL | 1235 | 0.05 | 61.68 | 61.742 | 6.17 | 13:32:00 | 583 621 31 47.2 |
|
||||
======================================================= SELL REASON STATS ========================================================
|
||||
| Sell Reason | Sells | Win Draws Loss Win% | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % |
|
||||
|--------------------+---------+--------------------------+----------------+----------------+-------------------+----------------|
|
||||
| roi | 1202 | 581 621 0 100 | 0.63 | 759.35 | 760.111 | 50.62 |
|
||||
| trailing_stop_loss | 24 | 2 0 22 8.3 | -23.86 | -572.56 | -573.132 | -38.17 |
|
||||
| sell_signal | 4 | 0 0 4 0 | -14.02 | -56.06 | -56.117 | -3.74 |
|
||||
| force_sell | 3 | 0 0 3 0 | -4.85 | -14.56 | -14.574 | -0.97 |
|
||||
| stop_loss | 2 | 0 0 2 0 | -27.25 | -54.49 | -54.546 | -3.63 |
|
||||
======================================================== LEFT OPEN TRADES REPORT =========================================================
|
||||
| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% |
|
||||
|-----------+--------+----------------+----------------+-------------------+----------------+------------------+-------------------------|
|
||||
| ZEC/USDT | 1 | -1.32 | -1.32 | -1.320 | -0.13 | 2:40:00 | 0 0 1 0 |
|
||||
| EGLD/USDT | 1 | -3.25 | -3.25 | -3.251 | -0.33 | 1:20:00 | 0 0 1 0 |
|
||||
| ETH/USDT | 1 | -9.99 | -9.99 | -10.003 | -1.00 | 4 days, 10:50:00 | 0 0 1 0 |
|
||||
| TOTAL | 3 | -4.85 | -14.56 | -14.574 | -1.46 | 1 day, 12:57:00 | 0 0 3 0 |
|
||||
=============== SUMMARY METRICS ================
|
||||
| Metric | Value |
|
||||
|------------------------+---------------------|
|
||||
| Backtesting from | 2021-01-01 00:00:00 |
|
||||
| Backtesting to | 2021-11-20 00:00:00 |
|
||||
| Max open trades | 15 |
|
||||
| | |
|
||||
| Total/Daily Avg Trades | 1235 / 3.82 |
|
||||
| Starting balance | 1000.000 USDT |
|
||||
| Final balance | 1061.742 USDT |
|
||||
| Absolute profit | 61.742 USDT |
|
||||
| Total profit % | 6.17% |
|
||||
| Trades per day | 3.82 |
|
||||
| Avg. daily profit % | 0.02% |
|
||||
| Avg. stake amount | 100.000 USDT |
|
||||
| Total trade volume | 123500.000 USDT |
|
||||
| | |
|
||||
| Best Pair | CELR/USDT 47.95% |
|
||||
| Worst Pair | ZEC/USDT -69.80% |
|
||||
| Best trade | EGLD/USDT 9.32% |
|
||||
| Worst trade | IOTX/USDT -27.25% |
|
||||
| Best day | 18.000 USDT |
|
||||
| Worst day | -55.225 USDT |
|
||||
| Days win/draw/lose | 201 / 100 / 23 |
|
||||
| Avg. Duration Winners | 2:30:00 |
|
||||
| Avg. Duration Loser | 4 days, 7:03:00 |
|
||||
| Rejected Buy signals | 0 |
|
||||
| | |
|
||||
| Min balance | 940.516 USDT |
|
||||
| Max balance | 1218.619 USDT |
|
||||
| Drawdown | 277.83% |
|
||||
| Drawdown | 278.103 USDT |
|
||||
| Drawdown high | 218.619 USDT |
|
||||
| Drawdown low | -59.484 USDT |
|
||||
| Drawdown Start | 2021-05-12 06:00:00 |
|
||||
| Drawdown End | 2021-07-20 03:05:00 |
|
||||
| Market change | 2716.79% |
|
||||
================================================
|
||||
123
Empty.py
Normal file
123
Empty.py
Normal file
@@ -0,0 +1,123 @@
|
||||
# pr#agma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||
# isort: skip_file
|
||||
# --- Do not remove these libs ---
|
||||
from datetime import datetime
|
||||
|
||||
import numpy as np # noqa
|
||||
import pandas as pd # noqa
|
||||
from pandas import DataFrame
|
||||
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
|
||||
# --------------------------------
|
||||
# Add your lib to import here
|
||||
import talib.abstract as ta
|
||||
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||
|
||||
# This class is a sample. Feel free to customize it.
|
||||
class Empty(IStrategy):
|
||||
|
||||
# Strategy interface version - allow new iterations of the strategy interface.
|
||||
# Check the documentation or the Sample strategy to get the latest version.
|
||||
INTERFACE_VERSION = 2
|
||||
|
||||
# ROI table:
|
||||
minimal_roi = {
|
||||
#"0": 0.015
|
||||
"0": 0.5
|
||||
}
|
||||
|
||||
# Stoploss:
|
||||
stoploss = -1
|
||||
trailing_stop = True
|
||||
trailing_stop_positive = 0.001
|
||||
trailing_stop_positive_offset = 0.0175 #0.015
|
||||
trailing_only_offset_is_reached = True
|
||||
|
||||
#max_open_trades = 3
|
||||
|
||||
# Optimal ticker interval for the strategy.
|
||||
timeframe = '5m'
|
||||
|
||||
# Run "populate_indicators()" only for new candle.
|
||||
process_only_new_candles = False
|
||||
|
||||
# These values can be overridden in the "ask_strategy" section in the config.
|
||||
use_sell_signal = True
|
||||
sell_profit_only = False
|
||||
ignore_roi_if_buy_signal = False
|
||||
|
||||
# Number of candles the strategy requires before producing valid signals
|
||||
startup_candle_count: int = 30
|
||||
|
||||
plot_config = {
|
||||
# Main plot indicators (Moving averages, ...)
|
||||
'main_plot': {
|
||||
'bb_lowerband': {'color': 'white'},
|
||||
'bb_upperband': {'color': 'white'},
|
||||
},
|
||||
'subplots': {
|
||||
# Subplots - each dict defines one additional plot
|
||||
"BB": {
|
||||
'bb_width': {'color': 'white'},
|
||||
},
|
||||
"Aaron": {
|
||||
'aroonup': {'color': 'blue'},
|
||||
'aroondown': {'color': 'red'}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def informative_pairs(self):
|
||||
|
||||
return []
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
# MACD
|
||||
#macd = ta.MACD(dataframe)
|
||||
#dataframe['macd'] = macd['macd']
|
||||
#dataframe['macdsignal'] = macd['macdsignal']
|
||||
#dataframe['macdhist'] = macd['macdhist']
|
||||
|
||||
# RSI
|
||||
#dataframe['rsi'] = ta.RSI(dataframe)
|
||||
|
||||
# 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"]
|
||||
)
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
dataframe.loc[
|
||||
(
|
||||
# (
|
||||
# (dataframe['close'] < dataframe['bb_lowerband'])
|
||||
# & (dataframe['bb_width'] >= 0.065)
|
||||
# #& (dataframe['rsi'] < 45)
|
||||
# & (dataframe['volume'] > 0)
|
||||
# )
|
||||
),
|
||||
'buy'] = 1
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
dataframe.loc[
|
||||
(
|
||||
|
||||
),
|
||||
'sell'] = 1
|
||||
return dataframe
|
||||
|
||||
20
EnCirculation.txt
Normal file
20
EnCirculation.txt
Normal file
@@ -0,0 +1,20 @@
|
||||
132,670,764,300 DOGE
|
||||
19,215,937 BTC
|
||||
71,683,856 LTC
|
||||
138,063,286 ETC
|
||||
18,204,913 XMR
|
||||
19,238,231 BCH
|
||||
15,772,013 ZEC
|
||||
50,298,735,565 XRP
|
||||
34,424,965,305 ADA
|
||||
8,734,317,475 MATIC
|
||||
1,139,368,061 DOT
|
||||
362,910,497 SOL
|
||||
549,063,278,876,302 SHIB
|
||||
92,159,192,741 TRX
|
||||
300,677,692 AVAX
|
||||
18,204,913 XMR
|
||||
1,344,947,069 STX
|
||||
13,572,466,120 ZIL
|
||||
|
||||
https://coinmarketcap.com/
|
||||
328
FractalAtr.py
Normal file
328
FractalAtr.py
Normal file
@@ -0,0 +1,328 @@
|
||||
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||
# flake8: noqa: F401
|
||||
# isort: skip_file
|
||||
# --- Do not remove these libs ---
|
||||
import logging
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from pandas import DataFrame
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Optional, Union, Tuple
|
||||
from freqtrade.exchange import timeframe_to_prev_date
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter, stoploss_from_open,
|
||||
IntParameter, IStrategy, merge_informative_pair, informative, stoploss_from_absolute)
|
||||
|
||||
# --------------------------------
|
||||
# Add your lib to import here
|
||||
import talib.abstract as ta
|
||||
import pandas_ta as pta
|
||||
from technical import qtpylib
|
||||
|
||||
class FractalAtr(IStrategy):
|
||||
|
||||
# Strategy interface version - allow new iterations of the strategy interface.
|
||||
# Check the documentation or the Sample strategy to get the latest version.
|
||||
INTERFACE_VERSION = 3
|
||||
|
||||
# Optimal timeframe for the strategy.
|
||||
timeframe = '1m'
|
||||
|
||||
# Can this strategy go short?
|
||||
can_short: bool = False
|
||||
|
||||
# Minimal ROI designed for the strategy.
|
||||
# This attribute will be overridden if the config file contains "minimal_roi".
|
||||
minimal_roi = {
|
||||
"0": 0.5
|
||||
}
|
||||
|
||||
# Optimal stoploss designed for the strategy.
|
||||
# This attribute will be overridden if the config file contains "stoploss".
|
||||
stoploss = -1
|
||||
|
||||
position_adjustment_enable = True
|
||||
use_custom_stoploss = True
|
||||
|
||||
# Trailing stoploss
|
||||
trailing_stop = False
|
||||
|
||||
# Run "populate_indicators()" only for new candle.
|
||||
process_only_new_candles = True
|
||||
|
||||
# These values can be overridden in the config.
|
||||
use_exit_signal = True
|
||||
exit_profit_only = False
|
||||
ignore_roi_if_entry_signal = False
|
||||
|
||||
# Number of candles the strategy requires before producing valid signals
|
||||
startup_candle_count: int = 30
|
||||
|
||||
# Strategy parameters
|
||||
buy_rsi = IntParameter(10, 40, default=30, space="buy")
|
||||
sell_rsi = IntParameter(60, 90, default=70, space="sell")
|
||||
|
||||
# trailing stoploss hyperopt parameters
|
||||
# hard stoploss profit
|
||||
|
||||
pHSL = DecimalParameter(-0.200, -0.040, default=-0.99, decimals=3, space='sell', optimize=False, load=True)
|
||||
# profit threshold 1, trigger point, SL_1 is used
|
||||
pPF_1 = DecimalParameter(0.008, 0.020, default=0.022, decimals=3, space='sell', optimize=True, load=True)
|
||||
pSL_1 = DecimalParameter(0.008, 0.020, default=0.021, decimals=3, space='sell', optimize=True, load=True)
|
||||
|
||||
# profit threshold 2, SL_2 is used
|
||||
pPF_2 = DecimalParameter(0.040, 0.100, default=0.080, decimals=3, space='sell', optimize=True, load=True)
|
||||
pSL_2 = DecimalParameter(0.020, 0.070, default=0.040, decimals=3, space='sell', optimize=True, load=True)
|
||||
|
||||
# Optional order type mapping.
|
||||
order_types = {
|
||||
'entry': 'limit',
|
||||
'exit': 'limit',
|
||||
'stoploss': 'market',
|
||||
'stoploss_on_exchange': False
|
||||
}
|
||||
|
||||
# Optional order time in force.
|
||||
order_time_in_force = {
|
||||
'entry': 'GTC',
|
||||
'exit': 'GTC'
|
||||
}
|
||||
locked_pairs = {}
|
||||
|
||||
def adjust_trade_position(self, trade: Trade, current_time: datetime,
|
||||
current_rate: float, current_profit: float, min_stake: float,
|
||||
max_stake: float, **kwargs):
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe)
|
||||
if True | (len(dataframe) < 1):
|
||||
return None
|
||||
last_candle = dataframe.iloc[-1].squeeze()
|
||||
filled_buys = trade.select_filled_orders('buy')
|
||||
count_of_buys = len(filled_buys)
|
||||
|
||||
condition = (last_candle['enter_long'] == 1) # & (last_candle['close'] <= last_candle['close_1h'])
|
||||
|
||||
# self.protection_nb_buy_lost.value
|
||||
if (0 < count_of_buys <= 2) & (current_profit < - 0.1) & (condition):
|
||||
try:
|
||||
stake_amount = self.config['stake_amount']
|
||||
print("Adjust " + trade.pair + " " + str(current_time) + " " + str(current_profit) + " " + str(count_of_buys) + " "
|
||||
+ str(stake_amount))
|
||||
return stake_amount
|
||||
except Exception as exception:
|
||||
print(exception)
|
||||
return None
|
||||
return None
|
||||
|
||||
def calculateScore(self, last_candle):
|
||||
score = 1 #- (last_candle['percent10'] / 0.01
|
||||
return score
|
||||
|
||||
@informative('1h')
|
||||
def populate_indicators_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
self.will_frac(dataframe)
|
||||
dataframe['bear'] = dataframe['high'].where(dataframe['fractal_sup'] == True, 0)
|
||||
dataframe['bear'] = dataframe['bear'].replace(to_replace=0, method="ffill")
|
||||
dataframe['bull'] = dataframe['low'].where(dataframe['fractal_inf'] == True, 0)
|
||||
dataframe['bull'] = dataframe['bull'].replace(to_replace=0, method="ffill")
|
||||
dataframe['max72'] = ta.MAX(dataframe['close'], timeperiod=72)
|
||||
dataframe['min72'] = ta.MIN(dataframe['close'], timeperiod=72)
|
||||
dataframe['mid72'] = (dataframe['min72'] + (dataframe['max72'] - dataframe['min72']) / 2)
|
||||
dataframe['width_72'] = (dataframe['max72'] - dataframe['min72']) / dataframe['max72']
|
||||
|
||||
dataframe['percent'] = dataframe['close'].pct_change()
|
||||
dataframe['percent5'] = dataframe['close'].pct_change(5)
|
||||
return dataframe
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
self.will_frac(dataframe)
|
||||
dataframe['rsi'] = ta.RSI(dataframe)
|
||||
dataframe['atr'] = ta.ATR(dataframe)
|
||||
dataframe['bear'] = dataframe['high'].where(dataframe['fractal_sup'] == True, 0)
|
||||
dataframe['bear'] = dataframe['bear'].replace(to_replace=0, method="ffill")
|
||||
dataframe['bull'] = dataframe['low'].where(dataframe['fractal_inf'] == True, 0)
|
||||
dataframe['bull'] = dataframe['bull'].replace(to_replace=0, method="ffill")
|
||||
dataframe["percent"] = dataframe["close"].pct_change()
|
||||
dataframe["percent3"] = dataframe["close"].pct_change(3)
|
||||
dataframe["percent10"] = dataframe["close"].pct_change(10)
|
||||
|
||||
dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200)
|
||||
dataframe['max200'] = ta.MAX(dataframe['close'], timeperiod=200)
|
||||
dataframe['atr_relatif'] = ta.ATR(dataframe) / dataframe["min200"]
|
||||
dataframe["close50"] = dataframe["close"].rolling(50).mean()
|
||||
dataframe["close3"] = dataframe["close"].rolling(3).mean()
|
||||
dataframe['rsi_mean'] = dataframe['rsi'].rolling(3).mean()
|
||||
dataframe['atr_relatif_mean'] = dataframe['atr_relatif'].rolling(3).mean()
|
||||
dataframe['width_200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['max200']
|
||||
dataframe['width_close'] = (dataframe['close'] - dataframe['min200']) / dataframe['close']
|
||||
dataframe['200_close'] = dataframe['width_close'] / dataframe['width_200'] * 100
|
||||
dataframe['72h_close'] = (dataframe['close'] - dataframe['min72_1h']) / dataframe['min72_1h'] * 100
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
dataframe.loc[
|
||||
(
|
||||
(qtpylib.crossed_above(dataframe['close'], dataframe['bull']) |
|
||||
qtpylib.crossed_above(dataframe['close'].shift(1), dataframe['bull'].shift(1)) |
|
||||
qtpylib.crossed_above(dataframe['close'].shift(2), dataframe['bull'].shift(2))
|
||||
) &
|
||||
((dataframe['rsi'] < 20) | (dataframe['atr_relatif'] > 0.008)) &
|
||||
# ((dataframe['200_close'] < 25) | (dataframe['width_200'] < 0.10)) &
|
||||
(dataframe['close3'] < dataframe['close50']) & # Make sure Volume is not 0
|
||||
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||
|
||||
), ['buy', 'enter_tag']] = (1, 'buy_fractal')
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
# dataframe.loc[
|
||||
# (
|
||||
# #(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||
# ),
|
||||
# 'exit_long'] = 1
|
||||
return dataframe
|
||||
|
||||
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:
|
||||
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
last_candle = dataframe.iloc[-1].squeeze()
|
||||
last_candle_12 = dataframe.iloc[-13].squeeze()
|
||||
|
||||
allow_to_buy = True #(not self.stop_all) #& (not self.all_down)
|
||||
|
||||
if pair in self.locked_pairs:
|
||||
trade = self.locked_pairs[pair]
|
||||
if (last_candle['close3'] >= last_candle['mid72_1h']):
|
||||
print(pair + ' is locked ' + str(current_time) + " rate=" + str(rate) + " locked_rate=" + str(
|
||||
trade.open_rate) + ' close3=' + str(last_candle['close3']) + ' mid72=' + str(last_candle['mid72_1h'])
|
||||
+ str(trade))
|
||||
allow_to_buy = False
|
||||
# else:
|
||||
# print(pair + ' unlocked ' + str(current_time) + " rate=" + str(rate) + " locked_rate=" + str(
|
||||
# self.locked_pairs[pair]))
|
||||
# del self.locked_pairs[pair]
|
||||
|
||||
if allow_to_buy:
|
||||
print('Buy ' + entry_tag + ' ' + str(current_time) + ' ' + pair + " dispo=" + str(
|
||||
round(self.wallets.get_available_stake_amount())) + " score=" + str(self.calculateScore(last_candle)))
|
||||
return allow_to_buy
|
||||
|
||||
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:
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
last_candle = dataframe.iloc[-1].squeeze()
|
||||
|
||||
string = ""
|
||||
buy_signal = self.getTradeCandle(dataframe, trade)
|
||||
if not buy_signal.empty:
|
||||
buy_signal_candle = buy_signal.iloc[-1]
|
||||
string = str(buy_signal_candle['date']) + ' open=' + str(buy_signal_candle['open']) \
|
||||
+ " score=" + str(self.calculateScore(last_candle))
|
||||
|
||||
print('Sell trade ' + exit_reason + ' ' + str(current_time) + ' ' + pair + " dispo=" + str(
|
||||
round(self.wallets.get_available_stake_amount())) #"+ str(amount) + ' ' + str(rate)
|
||||
+ " open_rate=" + str(trade.open_rate) + " rate=" + str(rate) + " profit" + str(trade.calc_profit(rate, amount))
|
||||
+ " " + string)
|
||||
|
||||
return True
|
||||
|
||||
def custom_exit(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float,
|
||||
current_profit: float, **kwargs) -> 'Optional[Union[str, bool]]':
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
last_candle = dataframe.iloc[-1].squeeze()
|
||||
if (last_candle['percent'] > 0) | (last_candle['percent3'] > -0.002):
|
||||
return None
|
||||
|
||||
days = (current_time - trade.open_date_utc).days
|
||||
hours = (current_time - trade.open_date_utc).seconds / 3600
|
||||
minutes = (current_time - trade.open_date_utc).seconds / 60
|
||||
|
||||
# if (days >= 1) & (current_profit < -0.02):
|
||||
# return 'too_old'
|
||||
|
||||
self.testLockedTrade(trade, current_profit, current_rate, current_time, pair)
|
||||
# if pair in self.locked_pairs:
|
||||
# print(pair + " stoploss")
|
||||
# return "force_stoploss"
|
||||
factor = 10
|
||||
exit_atr = (trade.open_rate + (last_candle['atr'] * factor))
|
||||
if (current_rate > exit_atr):
|
||||
return "exit_atr"
|
||||
|
||||
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
|
||||
current_rate: float, current_profit: float, **kwargs) -> float:
|
||||
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
last_candle = dataframe.iloc[-1].squeeze()
|
||||
if (last_candle['percent'] > 0) | (last_candle['percent3'] > -0.002):
|
||||
return -1
|
||||
|
||||
# print(pair + " " + str(current_time) + " rate=" + str(current_profit))
|
||||
self.testLockedTrade(trade, current_profit, current_rate, current_time, pair)
|
||||
|
||||
# hard stoploss profit
|
||||
HSL = self.pHSL.value
|
||||
PF_1 = self.pPF_1.value
|
||||
SL_1 = self.pSL_1.value
|
||||
PF_2 = self.pPF_2.value
|
||||
SL_2 = self.pSL_2.value
|
||||
|
||||
# For profits between PF_1 and PF_2 the stoploss (sl_profit) used is linearly interpolated
|
||||
# between the values of SL_1 and SL_2. For all profits above PL_2 the sl_profit value
|
||||
# rises linearly with current profit, for profits below PF_1 the hard stoploss profit is used.
|
||||
|
||||
if current_profit > PF_2:
|
||||
sl_profit = SL_2 + (current_profit - PF_2)
|
||||
elif (current_profit > PF_1):
|
||||
sl_profit = SL_1 + ((current_profit - PF_1) * (SL_2 - SL_1) / (PF_2 - PF_1))
|
||||
else:
|
||||
sl_profit = HSL
|
||||
|
||||
return stoploss_from_open(sl_profit, current_profit)
|
||||
|
||||
# def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
|
||||
# current_rate: float, current_profit: float, **kwargs) -> float:
|
||||
# dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
# candle = dataframe.iloc[-1].squeeze()
|
||||
# factor = 10
|
||||
# return stoploss_from_absolute(current_rate - (candle['atr'] * factor), current_rate, is_short=trade.is_short)
|
||||
def getTradeCandle(self, dataframe, trade: 'Trade'):
|
||||
trade_open_date = timeframe_to_prev_date(self.timeframe, trade.open_date_utc)
|
||||
buy_signal = dataframe.loc[dataframe['date'] <= trade_open_date]
|
||||
return buy_signal
|
||||
|
||||
def testLockedTrade(self, trade: 'Trade', current_profit, current_rate, current_time, pair):
|
||||
if current_profit <= -0.1:
|
||||
if pair in self.locked_pairs:
|
||||
trade = self.locked_pairs[pair]
|
||||
if current_rate > trade.open_rate:
|
||||
print(pair + ' unlocked ' + str(current_time) + " rate=" + str(current_rate) + " locked_rate=" + str(
|
||||
trade.open_rate) + ' profit=' + str(current_profit))
|
||||
del self.locked_pairs[pair]
|
||||
# else:
|
||||
# self.locked_pairs[pair] = current_rate
|
||||
else:
|
||||
self.locked_pairs[pair] = trade
|
||||
# self.lock_pair(pair, until=current_time + timedelta(hours=24))
|
||||
|
||||
print(pair + " locked at " + str(current_time) + " rate=" + str(current_rate) + " locked_rate=" + str(
|
||||
trade.open_rate) + ' profit=' + str(current_profit))
|
||||
|
||||
def will_frac(self, df: pd.DataFrame, period: int = 2) -> Tuple[pd.Series, pd.Series]:
|
||||
"""
|
||||
Indicate bearish and bullish fractal patterns using shifted Series.
|
||||
:param df: OHLC data
|
||||
:param period: number of lower (or higher) points on each side of a high (or low)
|
||||
:return: tuple of boolean Series (bearish, bullish) where True marks a fractal pattern
|
||||
"""
|
||||
periods = [p for p in range(-period, period + 1) if p != 0] # default [-2, -1, 1, 2]
|
||||
highs = [df['high'] > df['high'].shift(p) for p in periods]
|
||||
bears = pd.Series(np.logical_and.reduce(highs), index=df.index)
|
||||
lows = [df['low'] < df['low'].shift(p) for p in periods]
|
||||
bulls = pd.Series(np.logical_and.reduce(lows), index=df.index)
|
||||
df['fractal_sup'] = bears
|
||||
df['fractal_inf'] = bulls
|
||||
return df
|
||||
433
FractalAtr2.py
Normal file
433
FractalAtr2.py
Normal file
@@ -0,0 +1,433 @@
|
||||
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||
# flake8: noqa: F401
|
||||
# isort: skip_file
|
||||
# --- Do not remove these libs ---
|
||||
import logging
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from pandas import DataFrame
|
||||
from datetime import datetime, timedelta
|
||||
from typing import Optional, Union, Tuple
|
||||
from freqtrade.exchange import timeframe_to_prev_date
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter, stoploss_from_open,
|
||||
IntParameter, IStrategy, merge_informative_pair, informative, stoploss_from_absolute)
|
||||
|
||||
# --------------------------------
|
||||
# Add your lib to import here
|
||||
import talib.abstract as ta
|
||||
import pandas_ta as pta
|
||||
from technical import qtpylib
|
||||
|
||||
class FractalAtr2(IStrategy):
|
||||
|
||||
# Strategy interface version - allow new iterations of the strategy interface.
|
||||
# Check the documentation or the Sample strategy to get the latest version.
|
||||
INTERFACE_VERSION = 3
|
||||
|
||||
# Optimal timeframe for the strategy.
|
||||
timeframe = '1m'
|
||||
|
||||
# Can this strategy go short?
|
||||
can_short: bool = False
|
||||
|
||||
# Minimal ROI designed for the strategy.
|
||||
# This attribute will be overridden if the config file contains "minimal_roi".
|
||||
minimal_roi = {
|
||||
"0": 0.5
|
||||
}
|
||||
|
||||
# Optimal stoploss designed for the strategy.
|
||||
# This attribute will be overridden if the config file contains "stoploss".
|
||||
stoploss = -1
|
||||
|
||||
position_adjustment_enable = True
|
||||
use_custom_stoploss = True
|
||||
|
||||
# Trailing stoploss
|
||||
trailing_stop = False
|
||||
|
||||
# Run "populate_indicators()" only for new candle.
|
||||
process_only_new_candles = True
|
||||
|
||||
# These values can be overridden in the config.
|
||||
use_exit_signal = True
|
||||
exit_profit_only = False
|
||||
ignore_roi_if_entry_signal = False
|
||||
|
||||
# Number of candles the strategy requires before producing valid signals
|
||||
startup_candle_count: int = 30
|
||||
|
||||
# Strategy parameters
|
||||
buy_rsi = IntParameter(10, 40, default=30, space="buy")
|
||||
sell_rsi = IntParameter(60, 90, default=70, space="sell")
|
||||
|
||||
# trailing stoploss hyperopt parameters
|
||||
# hard stoploss profit
|
||||
|
||||
pHSL = DecimalParameter(-0.200, -0.040, default=-0.99, decimals=3, space='sell', optimize=False, load=True)
|
||||
# profit threshold 1, trigger point, SL_1 is used
|
||||
pPF_1 = DecimalParameter(0.008, 0.020, default=0.022, decimals=3, space='sell', optimize=True, load=True)
|
||||
pSL_1 = DecimalParameter(0.008, 0.020, default=0.021, decimals=3, space='sell', optimize=True, load=True)
|
||||
|
||||
# profit threshold 2, SL_2 is used
|
||||
pPF_2 = DecimalParameter(0.040, 0.100, default=0.080, decimals=3, space='sell', optimize=True, load=True)
|
||||
pSL_2 = DecimalParameter(0.020, 0.070, default=0.040, decimals=3, space='sell', optimize=True, load=True)
|
||||
|
||||
# Optional order type mapping.
|
||||
order_types = {
|
||||
'entry': 'limit',
|
||||
'exit': 'limit',
|
||||
'stoploss': 'market',
|
||||
'stoploss_on_exchange': False
|
||||
}
|
||||
|
||||
# Optional order time in force.
|
||||
order_time_in_force = {
|
||||
'entry': 'GTC',
|
||||
'exit': 'GTC'
|
||||
}
|
||||
locked_pairs = {}
|
||||
max_profit_pairs = {}
|
||||
|
||||
def adjust_trade_position(self, trade: Trade, current_time: datetime,
|
||||
current_rate: float, current_profit: float, min_stake: float,
|
||||
max_stake: float, **kwargs):
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe)
|
||||
if True | (len(dataframe) < 1):
|
||||
return None
|
||||
last_candle = dataframe.iloc[-1].squeeze()
|
||||
filled_buys = trade.select_filled_orders('buy')
|
||||
count_of_buys = len(filled_buys)
|
||||
|
||||
condition = (last_candle['enter_long'] == 1) # & (last_candle['close'] <= last_candle['close_1h'])
|
||||
|
||||
# self.protection_nb_buy_lost.value
|
||||
if (0 < count_of_buys <= 2) & (current_profit < - 0.1) & (condition):
|
||||
try:
|
||||
stake_amount = self.config['stake_amount']
|
||||
print("Adjust " + trade.pair + " " + str(current_time) + " " + str(current_profit) + " " + str(count_of_buys) + " "
|
||||
+ str(stake_amount))
|
||||
return stake_amount
|
||||
except Exception as exception:
|
||||
print(exception)
|
||||
return None
|
||||
return None
|
||||
|
||||
def calculateScore(self, last_candle):
|
||||
score = 1 #- (last_candle['percent10'] / 0.01
|
||||
return score
|
||||
|
||||
@informative('1d')
|
||||
def populate_indicators_1d(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
dataframe['rsi'] = ta.RSI(dataframe)
|
||||
dataframe['atr'] = ta.ATR(dataframe)
|
||||
dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5)
|
||||
# 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_ecart"] = ((dataframe["bb_upperband"] - dataframe["bb_lowerband"]))
|
||||
dataframe["bb_width"] = (
|
||||
(dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"]
|
||||
)
|
||||
return dataframe
|
||||
|
||||
@informative('1h')
|
||||
def populate_indicators_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
self.will_frac(dataframe)
|
||||
dataframe['bear'] = dataframe['high'].where(dataframe['fractal_sup'] == True, 0)
|
||||
dataframe['bear'] = dataframe['bear'].replace(to_replace=0, method="ffill")
|
||||
dataframe['bull'] = dataframe['low'].where(dataframe['fractal_inf'] == True, 0)
|
||||
dataframe['bull'] = dataframe['bull'].replace(to_replace=0, method="ffill")
|
||||
dataframe['max72'] = ta.MAX(dataframe['close'], timeperiod=72)
|
||||
dataframe['min72'] = ta.MIN(dataframe['close'], timeperiod=72)
|
||||
dataframe['mid72'] = (dataframe['min72'] + (dataframe['max72'] - dataframe['min72']) / 2)
|
||||
dataframe['width_72'] = (dataframe['max72'] - dataframe['min72']) / dataframe['max72']
|
||||
|
||||
dataframe['percent'] = dataframe['close'].pct_change()
|
||||
dataframe['percent5'] = dataframe['close'].pct_change(5)
|
||||
return dataframe
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
self.will_frac(dataframe)
|
||||
dataframe['rsi'] = ta.RSI(dataframe)
|
||||
dataframe['atr'] = ta.ATR(dataframe)
|
||||
dataframe['bear'] = dataframe['high'].where(dataframe['fractal_sup'] == True, 0)
|
||||
dataframe['bear'] = dataframe['bear'].replace(to_replace=0, method="ffill")
|
||||
dataframe['bull'] = dataframe['low'].where(dataframe['fractal_inf'] == True, 0)
|
||||
dataframe['bull'] = dataframe['bull'].replace(to_replace=0, method="ffill")
|
||||
dataframe["percent"] = dataframe["close"].pct_change()
|
||||
dataframe["percent3"] = dataframe["close"].pct_change(3)
|
||||
dataframe["percent10"] = dataframe["close"].pct_change(10)
|
||||
dataframe["diff_close1"] = dataframe["close"] - dataframe["close"].shift(1)
|
||||
dataframe["diff_close3"] = dataframe["close"] - dataframe["close"].shift(3)
|
||||
dataframe["diff_close5"] = dataframe["close"] - dataframe["close"].shift(5)
|
||||
dataframe["diff_close10"] = dataframe["close"] - dataframe["close"].shift(10)
|
||||
dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50)
|
||||
dataframe['max50'] = ta.MAX(dataframe['close'], timeperiod=50)
|
||||
|
||||
dataframe['min200'] = ta.MIN(dataframe['close'], timeperiod=200)
|
||||
dataframe['min200_3'] = dataframe['min200'].rolling(3).mean()
|
||||
|
||||
dataframe['max200'] = ta.MAX(dataframe['close'], timeperiod=200)
|
||||
dataframe['atr_relatif'] = ta.ATR(dataframe) / dataframe["min200"]
|
||||
dataframe["close50"] = dataframe["close"].rolling(50).mean()
|
||||
dataframe["close3"] = dataframe["close"].rolling(3).mean()
|
||||
dataframe['rsi_mean'] = dataframe['rsi'].rolling(3).mean()
|
||||
dataframe['atr_relatif_mean'] = dataframe['atr_relatif'].rolling(3).mean()
|
||||
dataframe['width_200'] = (dataframe['max200'] - dataframe['min200']) / dataframe['max200']
|
||||
dataframe['width_close'] = (dataframe['close'] - dataframe['min200']) / dataframe['close']
|
||||
dataframe['200_close'] = dataframe['width_close'] / dataframe['width_200'] * 100
|
||||
dataframe['72h_close'] = (dataframe['close'] - dataframe['min72_1h']) / dataframe['min72_1h'] * 100
|
||||
# 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_ecart"] = ((dataframe["bb_upperband"] - dataframe["bb_lowerband"]))
|
||||
dataframe["bb_width"] = (
|
||||
(dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"]
|
||||
)
|
||||
return dataframe
|
||||
|
||||
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
dataframe.loc[
|
||||
(
|
||||
(qtpylib.crossed_above(dataframe['close'], dataframe['bull']) |
|
||||
qtpylib.crossed_above(dataframe['close'].shift(1), dataframe['bull'].shift(1)) |
|
||||
qtpylib.crossed_above(dataframe['close'].shift(2), dataframe['bull'].shift(2)) |
|
||||
(dataframe['low'] <= dataframe['min200']) |
|
||||
(dataframe['low'] <= dataframe['bb_lowerband_1d'])
|
||||
) &
|
||||
# ((dataframe['rsi'] < 60) | (dataframe['atr_relatif'] > 0.008)) &
|
||||
# ((dataframe['200_close'] < 25) | (dataframe['width_200'] < 0.10)) &
|
||||
(dataframe['open'] < dataframe['bb_upperband_1d']) &
|
||||
(dataframe['bb_width'] >= 0.015) &
|
||||
(dataframe['width_close'] <= 0.015) &
|
||||
(dataframe['open'] < dataframe['close3']) &
|
||||
(dataframe['open'] < dataframe['close50']) &
|
||||
(dataframe['fractal_inf_1h'] == 1) &
|
||||
#((dataframe['fractal_inf_1h'] == 1) | (dataframe['low'] <= dataframe['bb_lowerband_1d'])) &
|
||||
# (dataframe['percent10'] < -0.005) &
|
||||
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||
|
||||
), ['buy', 'enter_tag']] = (1, 'buy_fractal')
|
||||
|
||||
# dataframe.loc[
|
||||
# (
|
||||
# # ((dataframe['200_close'] < 25) | (dataframe['width_200'] < 0.10)) &
|
||||
# # (dataframe['close3'] <= dataframe['width_200']) &
|
||||
# (dataframe['min200'].shift(5) == dataframe['min200']) &
|
||||
# (dataframe['min72_1h'] > dataframe['min200']) &
|
||||
# (dataframe['width_200'] > 0.035) &
|
||||
# (dataframe['width_close'] == 0) &
|
||||
# (dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||
#
|
||||
# ), ['buy', 'enter_tag']] = (1, 'buy_min72')
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
dataframe.loc[
|
||||
(
|
||||
((dataframe['200_close'].shift(3) > 95) | (dataframe['200_close'].shift(2) > 95)
|
||||
| (dataframe['200_close'].shift(1) > 95) | (dataframe['200_close'] > 95)
|
||||
| (dataframe['percent'] < -0.005)
|
||||
# | (dataframe['high'] >= dataframe['max50'])
|
||||
# | ((dataframe['percent3'] < 0) & (dataframe['close3'].shift(1) >= dataframe['close3']))
|
||||
)
|
||||
&
|
||||
(dataframe['percent'] < 0) &
|
||||
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||
),
|
||||
'exit_long'] = 1
|
||||
return dataframe
|
||||
|
||||
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:
|
||||
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
last_candle = dataframe.iloc[-1].squeeze()
|
||||
last_candle_12 = dataframe.iloc[-13].squeeze()
|
||||
|
||||
allow_to_buy = True #(not self.stop_all) #& (not self.all_down)
|
||||
|
||||
if pair in self.locked_pairs:
|
||||
trade = self.locked_pairs[pair]
|
||||
if (last_candle['close3'] >= last_candle['mid72_1h']):
|
||||
print(pair + ' is locked ' + str(current_time) + " rate=" + str(rate) + " locked_rate=" + str(
|
||||
trade.open_rate) + ' close3=' + str(last_candle['close3']) + ' mid72=' + str(last_candle['mid72_1h'])
|
||||
+ str(trade))
|
||||
allow_to_buy = False
|
||||
# else:
|
||||
# print(pair + ' unlocked ' + str(current_time) + " rate=" + str(rate) + " locked_rate=" + str(
|
||||
# self.locked_pairs[pair]))
|
||||
# del self.locked_pairs[pair]
|
||||
|
||||
if allow_to_buy:
|
||||
print('Buy ' + entry_tag + ' ' + str(current_time) + ' ' + pair + " dispo=" + str(
|
||||
round(self.wallets.get_available_stake_amount())) + " score=" + str(self.calculateScore(last_candle)))
|
||||
return allow_to_buy
|
||||
|
||||
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:
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
last_candle = dataframe.iloc[-1].squeeze()
|
||||
|
||||
days = (current_time - trade.open_date_utc).days
|
||||
hours = (current_time - trade.open_date_utc).seconds / 3600
|
||||
minutes = (current_time - trade.open_date_utc).seconds / 60
|
||||
|
||||
allow_to_sell = False #(minutes > 30)
|
||||
profit = trade.calc_profit(rate, amount)
|
||||
if not (pair in self.max_profit_pairs):
|
||||
self.max_profit_pairs[pair] = profit
|
||||
self.max_profit_pairs[pair] = max(self.max_profit_pairs[pair], profit)
|
||||
|
||||
if (self.max_profit_pairs[pair] > 0.5):
|
||||
allow_decrease = 0.2 * self.max_profit_pairs[pair]
|
||||
print("Max profit=" + str(self.max_profit_pairs[pair]) + ' ' + str(profit) + ' ' + str(allow_decrease))
|
||||
if self.max_profit_pairs[pair] - profit < allow_decrease:
|
||||
allow_to_sell = False
|
||||
else:
|
||||
allow_to_sell = True
|
||||
# if last_candle['percent'] <=
|
||||
|
||||
if (profit < - 1.5):
|
||||
print("Stop loss profit=" + str(self.max_profit_pairs[pair]) + ' ' + str(profit))
|
||||
allow_to_sell = True
|
||||
|
||||
string = ""
|
||||
buy_signal = self.getTradeCandle(dataframe, trade)
|
||||
if not buy_signal.empty:
|
||||
buy_signal_candle = buy_signal.iloc[-1]
|
||||
string = str(buy_signal_candle['date']) + ' open=' + str(buy_signal_candle['open']) \
|
||||
+ " score=" + str(self.calculateScore(last_candle))
|
||||
|
||||
if allow_to_sell:
|
||||
print('Sell trade ' + exit_reason + ' ' + str(current_time) + ' ' + pair + " dispo=" + str(
|
||||
round(self.wallets.get_available_stake_amount())) #"+ str(amount) + ' ' + str(rate)
|
||||
+ " open_rate=" + str(trade.open_rate) + " rate=" + str(rate) + " profit=" + str(trade.calc_profit(rate, amount))
|
||||
+ " " + string)
|
||||
del self.max_profit_pairs[pair]
|
||||
else:
|
||||
print('Cancel Sell trade ' + exit_reason + ' ' + str(current_time) + ' ' + pair)
|
||||
return allow_to_sell
|
||||
|
||||
def custom_exit(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float,
|
||||
current_profit: float, **kwargs) -> 'Optional[Union[str, bool]]':
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
last_candle = dataframe.iloc[-1].squeeze()
|
||||
if (last_candle['percent'] > 0) | (last_candle['percent3'] > -0.002):
|
||||
return None
|
||||
|
||||
days = (current_time - trade.open_date_utc).days
|
||||
hours = (current_time - trade.open_date_utc).seconds / 3600
|
||||
minutes = (current_time - trade.open_date_utc).seconds / 60
|
||||
|
||||
if not (pair in self.max_profit_pairs):
|
||||
self.max_profit_pairs[pair] = current_profit
|
||||
self.max_profit_pairs[pair] = max(self.max_profit_pairs[pair], current_profit)
|
||||
|
||||
if (hours >= 2) & (self.max_profit_pairs[pair] < 0.002) & (self.max_profit_pairs[pair] > - 0.002):
|
||||
return "no_change"
|
||||
|
||||
# if (days >= 1) & (current_profit < -0.02):
|
||||
# return 'too_old'
|
||||
|
||||
self.testLockedTrade(trade, current_profit, current_rate, current_time, pair)
|
||||
# if pair in self.locked_pairs:
|
||||
# print(pair + " stoploss")
|
||||
# return "force_stoploss"
|
||||
factor = 10
|
||||
exit_atr = (trade.open_rate + (last_candle['atr'] * factor))
|
||||
if (current_rate > exit_atr):
|
||||
return "exit_atr"
|
||||
|
||||
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
|
||||
current_rate: float, current_profit: float, **kwargs) -> float:
|
||||
|
||||
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
last_candle = dataframe.iloc[-1].squeeze()
|
||||
if (last_candle['percent'] > 0) | (last_candle['percent3'] > -0.002):
|
||||
return -1
|
||||
|
||||
# print(pair + " " + str(current_time) + " rate=" + str(current_profit))
|
||||
self.testLockedTrade(trade, current_profit, current_rate, current_time, pair)
|
||||
|
||||
# hard stoploss profit
|
||||
HSL = self.pHSL.value
|
||||
PF_1 = self.pPF_1.value
|
||||
SL_1 = self.pSL_1.value
|
||||
PF_2 = self.pPF_2.value
|
||||
SL_2 = self.pSL_2.value
|
||||
|
||||
# For profits between PF_1 and PF_2 the stoploss (sl_profit) used is linearly interpolated
|
||||
# between the values of SL_1 and SL_2. For all profits above PL_2 the sl_profit value
|
||||
# rises linearly with current profit, for profits below PF_1 the hard stoploss profit is used.
|
||||
|
||||
if current_profit > PF_2:
|
||||
sl_profit = SL_2 + (current_profit - PF_2)
|
||||
elif (current_profit > PF_1):
|
||||
sl_profit = SL_1 + ((current_profit - PF_1) * (SL_2 - SL_1) / (PF_2 - PF_1))
|
||||
else:
|
||||
sl_profit = HSL
|
||||
|
||||
return stoploss_from_open(sl_profit, current_profit)
|
||||
|
||||
# def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
|
||||
# current_rate: float, current_profit: float, **kwargs) -> float:
|
||||
# dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
|
||||
# candle = dataframe.iloc[-1].squeeze()
|
||||
# factor = 10
|
||||
# return stoploss_from_absolute(current_rate - (candle['atr'] * factor), current_rate, is_short=trade.is_short)
|
||||
def getTradeCandle(self, dataframe, trade: 'Trade'):
|
||||
trade_open_date = timeframe_to_prev_date(self.timeframe, trade.open_date_utc)
|
||||
buy_signal = dataframe.loc[dataframe['date'] <= trade_open_date]
|
||||
return buy_signal
|
||||
|
||||
def testLockedTrade(self, trade: 'Trade', current_profit, current_rate, current_time, pair):
|
||||
return ""
|
||||
if current_profit <= -0.1:
|
||||
if pair in self.locked_pairs:
|
||||
trade = self.locked_pairs[pair]
|
||||
if current_rate > trade.open_rate:
|
||||
print(pair + ' unlocked ' + str(current_time) + " rate=" + str(current_rate) + " locked_rate=" + str(
|
||||
trade.open_rate) + ' profit=' + str(current_profit))
|
||||
del self.locked_pairs[pair]
|
||||
# else:
|
||||
# self.locked_pairs[pair] = current_rate
|
||||
else:
|
||||
self.locked_pairs[pair] = trade
|
||||
# self.lock_pair(pair, until=current_time + timedelta(hours=24))
|
||||
|
||||
print(pair + " locked at " + str(current_time) + " rate=" + str(current_rate) + " locked_rate=" + str(
|
||||
trade.open_rate) + ' profit=' + str(current_profit))
|
||||
|
||||
def will_frac(self, df: pd.DataFrame, period: int = 2) -> Tuple[pd.Series, pd.Series]:
|
||||
"""
|
||||
Indicate bearish and bullish fractal patterns using shifted Series.
|
||||
:param df: OHLC data
|
||||
:param period: number of lower (or higher) points on each side of a high (or low)
|
||||
:return: tuple of boolean Series (bearish, bullish) where True marks a fractal pattern
|
||||
"""
|
||||
periods = [p for p in range(-period, period + 1) if p != 0] # default [-2, -1, 1, 2]
|
||||
highs = [df['high'] > df['high'].shift(p) for p in periods]
|
||||
bears = pd.Series(np.logical_and.reduce(highs), index=df.index)
|
||||
lows = [df['low'] < df['low'].shift(p) for p in periods]
|
||||
bulls = pd.Series(np.logical_and.reduce(lows), index=df.index)
|
||||
df['fractal_sup'] = bears
|
||||
df['fractal_inf'] = bulls
|
||||
return df
|
||||
362
Genetic.py
Normal file
362
Genetic.py
Normal file
@@ -0,0 +1,362 @@
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
from pandas import DataFrame
|
||||
# --------------------------------
|
||||
|
||||
import talib.abstract as ta
|
||||
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||
import numpy as np # noqa
|
||||
|
||||
|
||||
def activate(x):
|
||||
return np.tanh(x) # tanh
|
||||
|
||||
params = {
|
||||
'0-0-0-w': -0.53814,
|
||||
'0-0-bias': -0.96407,
|
||||
'1-0-0-w': -0.49249,
|
||||
'10-0-0-w': 0.08845,
|
||||
'11-0-0-w': -0.14317,
|
||||
'12-0-0-w': 0.00923,
|
||||
'13-0-0-w': 0.30464,
|
||||
'14-0-0-w': -0.35835,
|
||||
'15-0-0-w': -0.49712,
|
||||
'16-0-0-w': 0.76135,
|
||||
'17-0-0-w': -0.75257,
|
||||
'18-0-0-w': -0.04622,
|
||||
'19-0-0-w': 0.10012,
|
||||
'2-0-0-w': -0.23534,
|
||||
'20-0-0-w': -0.04553,
|
||||
'21-0-0-w': -0.35334,
|
||||
'22-0-0-w': 0.17952,
|
||||
'23-0-0-w': 0.44446,
|
||||
'24-0-0-w': -0.15875,
|
||||
'25-0-0-w': 0.97565,
|
||||
'26-0-0-w': -0.89948,
|
||||
'27-0-0-w': 0.61777,
|
||||
'28-0-0-w': -0.60204,
|
||||
'29-0-0-w': -0.85229,
|
||||
'3-0-0-w': 0.47262,
|
||||
'30-0-0-w': -0.52791,
|
||||
'31-0-0-w': 0.98494,
|
||||
'4-0-0-w': -0.54942,
|
||||
'5-0-0-w': 0.40523,
|
||||
'6-0-0-w': 0.4723,
|
||||
'7-0-0-w': 0.63297,
|
||||
'8-0-0-w': 0.07159,
|
||||
'9-0-0-w': -0.86791,
|
||||
'adx-bias': -0.48719,
|
||||
'ao-bias': -0.87518,
|
||||
'aroonosc-bias': -0.56096,
|
||||
'bb_percent-bias': -0.98703,
|
||||
'bb_width-bias': -0.73742,
|
||||
'cci-bias': 0.47039,
|
||||
'end-0-w': -0.81658,
|
||||
'end-bias': 0.74656,
|
||||
'fastd-bias': -0.2793,
|
||||
'fisher_rsi_norm-bias': -0.36065,
|
||||
'kc_percent-bias': 0.76707,
|
||||
'kc_width-bias': 0.5489,
|
||||
'macd-bias': 0.55448,
|
||||
'macdhist-bias': -0.83133,
|
||||
'macdsignal-bias': 0.30828,
|
||||
'mfi-bias': -0.13097,
|
||||
'roc-bias': -0.78885,
|
||||
'rsi-bias': 0.9856,
|
||||
'sar-bias': 0.43812,
|
||||
'sma10-bias': -0.39019,
|
||||
'sma100-bias': 0.03558,
|
||||
'sma21-bias': 0.07457,
|
||||
'sma3-bias': 0.93633,
|
||||
'sma5-bias': -0.93329,
|
||||
'sma50-bias': -0.60637,
|
||||
'tema10-bias': -0.45946,
|
||||
'tema100-bias': 0.1662,
|
||||
'tema21-bias': 0.68466,
|
||||
'tema3-bias': 0.25368,
|
||||
'tema5-bias': -0.88818,
|
||||
'tema50-bias': 0.3019,
|
||||
'uo-bias': 0.71019,
|
||||
'wbb_percent-bias': -0.55964,
|
||||
'wbb_width-bias': 0.23523,
|
||||
|
||||
's-0-0-0-w': 0.85409,
|
||||
's-0-0-bias': -0.04613,
|
||||
's-1-0-0-w': -0.14997,
|
||||
's-10-0-0-w': -0.67008,
|
||||
's-11-0-0-w': -0.40221,
|
||||
's-12-0-0-w': 0.64553,
|
||||
's-13-0-0-w': 0.22838,
|
||||
's-14-0-0-w': 0.99977,
|
||||
's-15-0-0-w': 0.89363,
|
||||
's-16-0-0-w': -0.88212,
|
||||
's-17-0-0-w': -0.71813,
|
||||
's-18-0-0-w': 0.41602,
|
||||
's-19-0-0-w': -0.48389,
|
||||
's-2-0-0-w': 0.09649,
|
||||
's-20-0-0-w': 0.64273,
|
||||
's-21-0-0-w': -0.31671,
|
||||
's-22-0-0-w': 0.9663,
|
||||
's-23-0-0-w': 0.00229,
|
||||
's-24-0-0-w': 0.96244,
|
||||
's-25-0-0-w': -0.24513,
|
||||
's-26-0-0-w': 0.52312,
|
||||
's-27-0-0-w': 0.44742,
|
||||
's-28-0-0-w': -0.03916,
|
||||
's-29-0-0-w': 0.88882,
|
||||
's-3-0-0-w': -0.32112,
|
||||
's-30-0-0-w': -0.70886,
|
||||
's-31-0-0-w': -0.42672,
|
||||
's-4-0-0-w': -0.55265,
|
||||
's-5-0-0-w': 0.56105,
|
||||
's-6-0-0-w': 0.47436,
|
||||
's-7-0-0-w': 0.58136,
|
||||
's-8-0-0-w': -0.48308,
|
||||
's-9-0-0-w': -0.16024,
|
||||
's-adx-bias': -0.4091,
|
||||
's-ao-bias': 0.76889,
|
||||
's-aroonosc-bias': 0.16228,
|
||||
's-bb_percent-bias': 0.19407,
|
||||
's-bb_width-bias': 0.11795,
|
||||
's-cci-bias': 0.8379,
|
||||
's-end-0-w': -0.14648,
|
||||
's-end-bias': -0.85697,
|
||||
's-fastd-bias': -0.00581,
|
||||
's-fisher_rsi_norm-bias': -0.05253,
|
||||
's-kc_percent-bias': -0.3562,
|
||||
's-kc_width-bias': 0.67451,
|
||||
's-macd-bias': -0.17742,
|
||||
's-macdhist-bias': -0.58328,
|
||||
's-macdsignal-bias': -0.79847,
|
||||
's-mfi-bias': -0.48236,
|
||||
's-roc-bias': -0.5914,
|
||||
's-rsi-bias': -0.9618,
|
||||
's-sar-bias': 0.57033,
|
||||
's-sma10-bias': 0.14349,
|
||||
's-sma100-bias': 0.02401,
|
||||
's-sma21-bias': 0.78191,
|
||||
's-sma3-bias': 0.72279,
|
||||
's-sma5-bias': -0.19383,
|
||||
's-sma50-bias': 0.63697,
|
||||
's-tema10-bias': 0.96837,
|
||||
's-tema100-bias': 0.77171,
|
||||
's-tema21-bias': 0.67279,
|
||||
's-tema3-bias': -0.24583,
|
||||
's-tema5-bias': -0.08997,
|
||||
's-tema50-bias': 0.65532,
|
||||
's-uo-bias': 0.67701,
|
||||
's-wbb_percent-bias': -0.658,
|
||||
's-wbb_width-bias': -0.71056
|
||||
}
|
||||
|
||||
network_shape = [1]
|
||||
|
||||
class Genetic(IStrategy):
|
||||
# ROI table:
|
||||
minimal_roi = {
|
||||
"0": 0.21029,
|
||||
"11": 0.05876,
|
||||
"57": 0.02191,
|
||||
"281": 0
|
||||
}
|
||||
|
||||
# Stoploss:
|
||||
stoploss = -0.07693
|
||||
|
||||
# Optimal ticker interval for the strategy
|
||||
ticker_interval = '2h'
|
||||
|
||||
# Trailing stop:
|
||||
trailing_only_offset_is_reached = False
|
||||
trailing_stop = True
|
||||
trailing_stop_positive = 0.01019
|
||||
trailing_stop_positive_offset = 0.01164
|
||||
|
||||
# run "populate_indicators" only for new candle
|
||||
process_only_new_candles = True
|
||||
|
||||
# Experimental settings (configuration will overide these if set)
|
||||
use_sell_signal = True
|
||||
sell_profit_only = True
|
||||
ignore_roi_if_buy_signal = True
|
||||
|
||||
startup_candle_count = 100
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Adds several different TA indicators to the given DataFrame
|
||||
|
||||
Performance Note: For the best performance be frugal on the number of indicators
|
||||
you are using. Let uncomment only the indicator you are using in your strategies
|
||||
or your hyperopt configuration, otherwise you will waste your memory and CPU usage.
|
||||
"""
|
||||
|
||||
# Momentum Indicators
|
||||
# ------------------------------------
|
||||
|
||||
# ADX
|
||||
dataframe['adx'] = ta.ADX(dataframe) / 100
|
||||
|
||||
# # Plus Directional Indicator / Movement
|
||||
# dataframe['plus_dm'] = ta.PLUS_DM(dataframe)
|
||||
# dataframe['plus_di'] = ta.PLUS_DI(dataframe)
|
||||
|
||||
# # Minus Directional Indicator / Movement
|
||||
# dataframe['minus_dm'] = ta.MINUS_DM(dataframe)
|
||||
# dataframe['minus_di'] = ta.MINUS_DI(dataframe)
|
||||
|
||||
# # Aroon, Aroon Oscillator
|
||||
# aroon = ta.AROON(dataframe)
|
||||
# dataframe['aroonup'] = aroon['aroonup']
|
||||
# dataframe['aroondown'] = aroon['aroondown']
|
||||
dataframe['aroonosc'] = ta.AROONOSC(dataframe) / 100
|
||||
|
||||
# # Awesome Oscillator
|
||||
dataframe['ao'] = ((qtpylib.awesome_oscillator(dataframe) > 0).astype(int) - 0.5) * 2
|
||||
|
||||
# # Keltner Channel
|
||||
keltner = qtpylib.keltner_channel(dataframe)
|
||||
dataframe["kc_upperband"] = keltner["upper"]
|
||||
dataframe["kc_lowerband"] = keltner["lower"]
|
||||
dataframe["kc_middleband"] = keltner["mid"]
|
||||
dataframe["kc_percent"] = (
|
||||
(dataframe["close"] - dataframe["kc_lowerband"]) /
|
||||
(dataframe["kc_upperband"] - dataframe["kc_lowerband"])
|
||||
)
|
||||
dataframe["kc_width"] = (
|
||||
(dataframe["kc_upperband"] - dataframe["kc_lowerband"]) / dataframe["kc_middleband"]
|
||||
)
|
||||
|
||||
# # Ultimate Oscillator
|
||||
dataframe['uo'] = ta.ULTOSC(dataframe) / 100
|
||||
|
||||
# # Commodity Channel Index: values [Oversold:-100, Overbought:100]
|
||||
dataframe['cci'] = ta.CCI(dataframe) / 200
|
||||
|
||||
# RSI
|
||||
dataframe['rsi'] = ta.RSI(dataframe) / 100
|
||||
|
||||
# # Inverse Fisher transform on RSI: values [-1.0, 1.0] (https://goo.gl/2JGGoy)
|
||||
rsi = 0.1 * (dataframe['rsi'] * 100 - 50)
|
||||
fisher_rsi = (np.exp(2 * rsi) - 1) / (np.exp(2 * rsi) + 1)
|
||||
|
||||
# # Inverse Fisher transform on RSI normalized: values [0.0, 100.0] (https://goo.gl/2JGGoy)
|
||||
dataframe['fisher_rsi_norm'] = 50 * (fisher_rsi + 1) / 100
|
||||
|
||||
# # Stochastic Slow
|
||||
# stoch = ta.STOCH(dataframe)
|
||||
# dataframe['slowd'] = stoch['slowd']
|
||||
# dataframe['slowk'] = stoch['slowk']
|
||||
|
||||
# Stochastic Fast
|
||||
stoch_fast = ta.STOCHF(dataframe)
|
||||
dataframe['fastd'] = stoch_fast['fastd'] / 100
|
||||
|
||||
# # Stochastic RSI
|
||||
# stoch_rsi = ta.STOCHRSI(dataframe)
|
||||
# dataframe['fastd_rsi'] = stoch_rsi['fastd']
|
||||
# dataframe['fastk_rsi'] = stoch_rsi['fastk']
|
||||
|
||||
# MACD
|
||||
macd = ta.MACD(dataframe)
|
||||
dataframe['macd'] = macd['macd']
|
||||
dataframe['macdsignal'] = macd['macdsignal']
|
||||
dataframe['macdhist'] = macd['macdhist']
|
||||
|
||||
# MFI
|
||||
dataframe['mfi'] = ta.MFI(dataframe) / 100
|
||||
|
||||
# # ROC
|
||||
dataframe['roc'] = ta.ROC(dataframe) / 100
|
||||
|
||||
# Overlap Studies
|
||||
# ------------------------------------
|
||||
|
||||
# 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"]
|
||||
)
|
||||
|
||||
# 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"]
|
||||
)
|
||||
|
||||
# # SMA - Simple Moving Average
|
||||
dataframe['sma3'] = dataframe['close'] / ta.SMA(dataframe, timeperiod=3) - 1
|
||||
dataframe['sma5'] = dataframe['close'] / ta.SMA(dataframe, timeperiod=5) - 1
|
||||
dataframe['sma10'] = dataframe['close'] / ta.SMA(dataframe, timeperiod=10) - 1
|
||||
dataframe['sma21'] = dataframe['close'] / ta.SMA(dataframe, timeperiod=21) - 1
|
||||
dataframe['sma50'] = dataframe['close'] / ta.SMA(dataframe, timeperiod=50) - 1
|
||||
dataframe['sma100'] = dataframe['close'] / ta.SMA(dataframe, timeperiod=100) - 1
|
||||
|
||||
# Parabolic SAR
|
||||
dataframe['sar'] = dataframe['close'] / ta.SAR(dataframe) - 1
|
||||
|
||||
# TEMA - Triple Exponential Moving Average
|
||||
dataframe['tema3'] = dataframe['close'] / ta.TEMA(dataframe, timeperiod=3) - 1
|
||||
dataframe['tema5'] = dataframe['close'] / ta.TEMA(dataframe, timeperiod=5) - 1
|
||||
dataframe['tema10'] = dataframe['close'] / ta.TEMA(dataframe, timeperiod=10) - 1
|
||||
dataframe['tema21'] = dataframe['close'] / ta.TEMA(dataframe, timeperiod=21) - 1
|
||||
dataframe['tema50'] = dataframe['close'] / ta.TEMA(dataframe, timeperiod=50) - 1
|
||||
dataframe['tema100'] = dataframe['close'] / ta.TEMA(dataframe, timeperiod=100) - 1
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Based on TA indicators, populates the buy signal for the given dataframe
|
||||
:param dataframe: DataFrame
|
||||
:return: DataFrame with buy column
|
||||
"""
|
||||
indicators = ['aroonosc', 'ao', 'uo', 'cci', 'rsi', 'fisher_rsi_norm', 'sar',
|
||||
'sma3', 'sma5', 'sma10', 'sma21', 'sma50', 'sma100',
|
||||
'tema3', 'tema5', 'tema10', 'tema21', 'tema50', 'tema100',
|
||||
'fastd', 'adx', 'bb_percent', 'bb_width', 'macd', 'macdsignal', 'macdhist', 'mfi',
|
||||
'wbb_percent', 'wbb_width', 'roc', 'kc_percent', 'kc_width']
|
||||
inputs = []
|
||||
for indicator in indicators:
|
||||
inputs.append(dataframe[indicator] + params[indicator + '-bias'])
|
||||
|
||||
for index, layer_size in enumerate(network_shape):
|
||||
outputs = []
|
||||
for n in range(layer_size):
|
||||
weight = 0
|
||||
for i, input in enumerate(inputs):
|
||||
weight += params['{}-{}-{}-w'.format(i, index, n)] * input
|
||||
weight += params['{}-{}-bias'.format(index, n)]
|
||||
outputs.append(activate(weight))
|
||||
inputs = outputs
|
||||
|
||||
weight = 0
|
||||
for i, input in enumerate(inputs):
|
||||
weight += params['end-{}-w'.format(i)] * input
|
||||
weight += params['end-bias']
|
||||
|
||||
dataframe.loc[activate(weight) > 0, 'buy'] = 1
|
||||
|
||||
# Check that the candle had volume
|
||||
dataframe.loc[dataframe['volume'] <= 0, 'buy'] = 0
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
return dataframe
|
||||
171
GodStra.py
Normal file
171
GodStra.py
Normal file
@@ -0,0 +1,171 @@
|
||||
# GodStra Strategy
|
||||
# Author: @Mablue (Masoud Azizi)
|
||||
# github: https://github.com/mablue/
|
||||
# IMPORTANT:Add to your pairlists inside config.json (Under StaticPairList):
|
||||
# {
|
||||
# "method": "AgeFilter",
|
||||
# "min_days_listed": 30
|
||||
# },
|
||||
# IMPORTANT: INSTALL TA BEFOUR RUN(pip install ta)
|
||||
# IMPORTANT: Use Smallest "max_open_trades" for getting best results inside config.json
|
||||
|
||||
# --- Do not remove these libs ---
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
from pandas import DataFrame
|
||||
# --------------------------------
|
||||
|
||||
# Add your lib to import here
|
||||
# import talib.abstract as ta
|
||||
from ta import add_all_ta_features
|
||||
from ta.utils import dropna
|
||||
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||
from functools import reduce
|
||||
import numpy as np
|
||||
|
||||
|
||||
class GodStra(IStrategy):
|
||||
# 5/66: 9 trades. 8/0/1 Wins/Draws/Losses. Avg profit 21.83%. Median profit 35.52%. Total profit 1060.11476586 USDT ( 196.50Σ%). Avg duration 3440.0 min. Objective: -7.06960
|
||||
# +--------+---------+----------+------------------+--------------+-------------------------------+----------------+-------------+
|
||||
# | Best | Epoch | Trades | Win Draw Loss | Avg profit | Profit | Avg duration | Objective |
|
||||
# |--------+---------+----------+------------------+--------------+-------------------------------+----------------+-------------|
|
||||
# | * Best | 1/500 | 11 | 2 1 8 | 5.22% | 280.74230393 USDT (57.40%) | 2,421.8 m | -2.85206 |
|
||||
# | * Best | 2/500 | 10 | 7 0 3 | 18.76% | 983.46414442 USDT (187.58%) | 360.0 m | -4.32665 |
|
||||
# | * Best | 5/500 | 9 | 8 0 1 | 21.83% | 1,060.11476586 USDT (196.50%) | 3,440.0 m | -7.0696 |
|
||||
|
||||
# Buy hyperspace params:
|
||||
buy_params = {
|
||||
'buy-cross-0': 'volatility_kcc',
|
||||
'buy-indicator-0': 'trend_ichimoku_base',
|
||||
'buy-int-0': 42,
|
||||
'buy-oper-0': '<R',
|
||||
'buy-real-0': 0.06295
|
||||
}
|
||||
|
||||
# Sell hyperspace params:
|
||||
sell_params = {
|
||||
'sell-cross-0': 'volume_mfi',
|
||||
'sell-indicator-0': 'trend_kst_diff',
|
||||
'sell-int-0': 98,
|
||||
'sell-oper-0': '=R',
|
||||
'sell-real-0': 0.8779
|
||||
}
|
||||
|
||||
# ROI table:
|
||||
minimal_roi = {
|
||||
"0": 0.3556,
|
||||
"4818": 0.21275,
|
||||
"6395": 0.09024,
|
||||
"22372": 0
|
||||
}
|
||||
|
||||
# Stoploss:
|
||||
stoploss = -0.34549
|
||||
|
||||
# Trailing stop:
|
||||
trailing_stop = True
|
||||
trailing_stop_positive = 0.22673
|
||||
trailing_stop_positive_offset = 0.2684
|
||||
trailing_only_offset_is_reached = True
|
||||
# Buy hypers
|
||||
timeframe = '12h'
|
||||
print('Add {\n\t"method": "AgeFilter",\n\t"min_days_listed": 30\n},\n to your pairlists in config (Under StaticPairList)')
|
||||
|
||||
def dna_size(self, dct: dict):
|
||||
def int_from_str(st: str):
|
||||
str_int = ''.join([d for d in st if d.isdigit()])
|
||||
if str_int:
|
||||
return int(str_int)
|
||||
return -1 # in case if the parameter somehow doesn't have index
|
||||
return len({int_from_str(digit) for digit in dct.keys()})
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
# Add all ta features
|
||||
dataframe = dropna(dataframe)
|
||||
dataframe = add_all_ta_features(
|
||||
dataframe, open="open", high="high", low="low", close="close", volume="volume",
|
||||
fillna=True)
|
||||
# dataframe.to_csv("df.csv", index=True)
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
conditions = list()
|
||||
# /5: Cuz We have 5 Group of variables inside buy_param
|
||||
for i in range(self.dna_size(self.buy_params)):
|
||||
|
||||
OPR = self.buy_params[f'buy-oper-{i}']
|
||||
IND = self.buy_params[f'buy-indicator-{i}']
|
||||
CRS = self.buy_params[f'buy-cross-{i}']
|
||||
INT = self.buy_params[f'buy-int-{i}']
|
||||
REAL = self.buy_params[f'buy-real-{i}']
|
||||
DFIND = dataframe[IND]
|
||||
DFCRS = dataframe[CRS]
|
||||
|
||||
if OPR == ">":
|
||||
conditions.append(DFIND > DFCRS)
|
||||
elif OPR == "=":
|
||||
conditions.append(np.isclose(DFIND, DFCRS))
|
||||
elif OPR == "<":
|
||||
conditions.append(DFIND < DFCRS)
|
||||
elif OPR == "CA":
|
||||
conditions.append(qtpylib.crossed_above(DFIND, DFCRS))
|
||||
elif OPR == "CB":
|
||||
conditions.append(qtpylib.crossed_below(DFIND, DFCRS))
|
||||
elif OPR == ">I":
|
||||
conditions.append(DFIND > INT)
|
||||
elif OPR == "=I":
|
||||
conditions.append(DFIND == INT)
|
||||
elif OPR == "<I":
|
||||
conditions.append(DFIND < INT)
|
||||
elif OPR == ">R":
|
||||
conditions.append(DFIND > REAL)
|
||||
elif OPR == "=R":
|
||||
conditions.append(np.isclose(DFIND, REAL))
|
||||
elif OPR == "<R":
|
||||
conditions.append(DFIND < REAL)
|
||||
|
||||
#print(conditions)
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
'buy'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
conditions = list()
|
||||
for i in range(self.dna_size(self.sell_params)):
|
||||
OPR = self.sell_params[f'sell-oper-{i}']
|
||||
IND = self.sell_params[f'sell-indicator-{i}']
|
||||
CRS = self.sell_params[f'sell-cross-{i}']
|
||||
INT = self.sell_params[f'sell-int-{i}']
|
||||
REAL = self.sell_params[f'sell-real-{i}']
|
||||
DFIND = dataframe[IND]
|
||||
DFCRS = dataframe[CRS]
|
||||
|
||||
if OPR == ">":
|
||||
conditions.append(DFIND > DFCRS)
|
||||
elif OPR == "=":
|
||||
conditions.append(np.isclose(DFIND, DFCRS))
|
||||
elif OPR == "<":
|
||||
conditions.append(DFIND < DFCRS)
|
||||
elif OPR == "CA":
|
||||
conditions.append(qtpylib.crossed_above(DFIND, DFCRS))
|
||||
elif OPR == "CB":
|
||||
conditions.append(qtpylib.crossed_below(DFIND, DFCRS))
|
||||
elif OPR == ">I":
|
||||
conditions.append(DFIND > INT)
|
||||
elif OPR == "=I":
|
||||
conditions.append(DFIND == INT)
|
||||
elif OPR == "<I":
|
||||
conditions.append(DFIND < INT)
|
||||
elif OPR == ">R":
|
||||
conditions.append(DFIND > REAL)
|
||||
elif OPR == "=R":
|
||||
conditions.append(np.isclose(DFIND, REAL))
|
||||
elif OPR == "<R":
|
||||
conditions.append(DFIND < REAL)
|
||||
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
'sell'] = 1
|
||||
|
||||
return dataframe
|
||||
73
GodStra.txt
Normal file
73
GodStra.txt
Normal file
@@ -0,0 +1,73 @@
|
||||
Result for strategy GodStra
|
||||
============================================================ BACKTESTING REPORT ===========================================================
|
||||
| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% |
|
||||
|-----------+--------+----------------+----------------+-------------------+----------------+-------------------+-------------------------|
|
||||
| CELR/USDT | 29 | 22.26 | 645.61 | 646.251 | 64.63 | 7 days, 22:45:00 | 23 0 6 79.3 |
|
||||
| IOTX/USDT | 22 | 22.29 | 490.44 | 490.932 | 49.09 | 11 days, 4:16:00 | 17 0 5 77.3 |
|
||||
| TRX/USDT | 10 | 15.73 | 157.35 | 157.504 | 15.75 | 12 days, 15:54:00 | 9 1 0 100 |
|
||||
| ROSE/USDT | 8 | 15.41 | 123.24 | 123.365 | 12.34 | 8 days, 6:48:00 | 8 0 0 100 |
|
||||
| SAND/USDT | 2 | 51.72 | 103.45 | 103.552 | 10.36 | 10 days, 3:55:00 | 2 0 0 100 |
|
||||
| GALA/USDT | 2 | 0.42 | 0.84 | 0.846 | 0.08 | 1 day, 11:50:00 | 1 0 1 50.0 |
|
||||
| ZEC/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 |
|
||||
| ADA/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 |
|
||||
| AVAX/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 |
|
||||
| XRP/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 |
|
||||
| ETH/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 |
|
||||
| BNB/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 |
|
||||
| SOL/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 |
|
||||
| EGLD/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 |
|
||||
| BTC/USDT | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 |
|
||||
| TOTAL | 73 | 20.83 | 1520.93 | 1522.449 | 152.24 | 9 days, 11:42:00 | 60 1 12 82.2 |
|
||||
=========================================================== BUY TAG STATS ============================================================
|
||||
| TAG | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% |
|
||||
|-------+--------+----------------+----------------+-------------------+----------------+------------------+-------------------------|
|
||||
| TOTAL | 73 | 20.83 | 1520.93 | 1522.449 | 152.24 | 9 days, 11:42:00 | 60 1 12 82.2 |
|
||||
======================================================= SELL REASON STATS ========================================================
|
||||
| Sell Reason | Sells | Win Draws Loss Win% | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % |
|
||||
|--------------------+---------+--------------------------+----------------+----------------+-------------------+----------------|
|
||||
| trailing_stop_loss | 32 | 32 0 0 100 | 40.32 | 1290.39 | 1291.68 | 86.03 |
|
||||
| roi | 29 | 28 1 0 100 | 22.3 | 646.69 | 647.341 | 43.11 |
|
||||
| stop_loss | 12 | 0 0 12 0 | -34.68 | -416.16 | -416.573 | -27.74 |
|
||||
====================================================== LEFT OPEN TRADES REPORT ======================================================
|
||||
| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% |
|
||||
|--------+--------+----------------+----------------+-------------------+----------------+----------------+-------------------------|
|
||||
| TOTAL | 0 | 0.00 | 0.00 | 0.000 | 0.00 | 0:00 | 0 0 0 0 |
|
||||
=============== SUMMARY METRICS ================
|
||||
| Metric | Value |
|
||||
|------------------------+---------------------|
|
||||
| Backtesting from | 2021-01-01 00:00:00 |
|
||||
| Backtesting to | 2021-11-20 00:00:00 |
|
||||
| Max open trades | 15 |
|
||||
| | |
|
||||
| Total/Daily Avg Trades | 73 / 0.23 |
|
||||
| Starting balance | 1000.000 USDT |
|
||||
| Final balance | 2522.449 USDT |
|
||||
| Absolute profit | 1522.449 USDT |
|
||||
| Total profit % | 152.24% |
|
||||
| Trades per day | 0.23 |
|
||||
| Avg. daily profit % | 0.47% |
|
||||
| Avg. stake amount | 100.000 USDT |
|
||||
| Total trade volume | 7300.000 USDT |
|
||||
| | |
|
||||
| Best Pair | CELR/USDT 645.61% |
|
||||
| Worst Pair | ZEC/USDT 0.00% |
|
||||
| Best trade | IOTX/USDT 164.23% |
|
||||
| Worst trade | IOTX/USDT -34.68% |
|
||||
| Best day | 164.398 USDT |
|
||||
| Worst day | -69.429 USDT |
|
||||
| Days win/draw/lose | 50 / 237 / 10 |
|
||||
| Avg. Duration Winners | 9 days, 11:34:00 |
|
||||
| Avg. Duration Loser | 8 days, 18:02:00 |
|
||||
| Rejected Buy signals | 0 |
|
||||
| | |
|
||||
| Min balance | 1001.510 USDT |
|
||||
| Max balance | 2522.449 USDT |
|
||||
| Drawdown | 96.63% |
|
||||
| Drawdown | 96.722 USDT |
|
||||
| Drawdown high | 1155.213 USDT |
|
||||
| Drawdown low | 1058.490 USDT |
|
||||
| Drawdown Start | 2021-05-28 06:25:00 |
|
||||
| Drawdown End | 2021-06-22 00:20:00 |
|
||||
| Market change | 2716.79% |
|
||||
================================================
|
||||
|
||||
200
GodStraHo.py
Normal file
200
GodStraHo.py
Normal file
@@ -0,0 +1,200 @@
|
||||
# GodStra Strategy Hyperopt
|
||||
# Author: @Mablue (Masoud Azizi)
|
||||
# github: https://github.com/mablue/
|
||||
# IMPORTANT: INSTALL TA BEFOUR RUN:
|
||||
# :~$ pip install ta
|
||||
# freqtrade hyperopt --hyperopt GodStraHo --hyperopt-loss SharpeHyperOptLossDaily --spaces all --strategy GodStra --config config.json -e 100
|
||||
|
||||
# --- Do not remove these libs ---
|
||||
from functools import reduce
|
||||
from typing import Any, Callable, Dict, List
|
||||
|
||||
import numpy as np # noqa
|
||||
import pandas as pd # noqa
|
||||
from pandas import DataFrame
|
||||
from skopt.space import Categorical, Dimension, Integer, Real # noqa
|
||||
|
||||
from freqtrade.optimize.hyperopt_interface import IHyperOpt
|
||||
|
||||
# --------------------------------
|
||||
# Add your lib to import here
|
||||
# import talib.abstract as ta # noqa
|
||||
import talib.abstract as ta
|
||||
from ta import add_all_ta_features
|
||||
from ta.utils import dropna
|
||||
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||
# this is your trading strategy DNA Size
|
||||
# you can change it and see the results...
|
||||
DNA_SIZE = 1
|
||||
|
||||
|
||||
GodGenes = ["open", "high", "low", "close", "volume", "volume_adi", "volume_obv",
|
||||
"volume_cmf", "volume_fi", "volume_mfi", "volume_em", "volume_sma_em", "volume_vpt",
|
||||
"volume_nvi", "volume_vwap", "volatility_atr", "volatility_bbm", "volatility_bbh",
|
||||
"volatility_bbl", "volatility_bbw", "volatility_bbp", "volatility_bbhi",
|
||||
"volatility_bbli", "volatility_kcc", "volatility_kch", "volatility_kcl",
|
||||
"volatility_kcw", "volatility_kcp", "volatility_kchi", "volatility_kcli",
|
||||
"volatility_dcl", "volatility_dch", "volatility_dcm", "volatility_dcw",
|
||||
"volatility_dcp", "volatility_ui", "trend_macd", "trend_macd_signal",
|
||||
"trend_macd_diff", "trend_sma_fast", "trend_sma_slow", "trend_ema_fast",
|
||||
"trend_ema_slow", "trend_adx", "trend_adx_pos", "trend_adx_neg", "trend_vortex_ind_pos",
|
||||
"trend_vortex_ind_neg", "trend_vortex_ind_diff", "trend_trix",
|
||||
"trend_mass_index", "trend_cci", "trend_dpo", "trend_kst",
|
||||
"trend_kst_sig", "trend_kst_diff", "trend_ichimoku_conv",
|
||||
"trend_ichimoku_base", "trend_ichimoku_a", "trend_ichimoku_b",
|
||||
"trend_visual_ichimoku_a", "trend_visual_ichimoku_b", "trend_aroon_up",
|
||||
"trend_aroon_down", "trend_aroon_ind", "trend_psar_up", "trend_psar_down",
|
||||
"trend_psar_up_indicator", "trend_psar_down_indicator", "trend_stc",
|
||||
"momentum_rsi", "momentum_stoch_rsi", "momentum_stoch_rsi_k",
|
||||
"momentum_stoch_rsi_d", "momentum_tsi", "momentum_uo", "momentum_stoch",
|
||||
"momentum_stoch_signal", "momentum_wr", "momentum_ao", "momentum_kama",
|
||||
"momentum_roc", "momentum_ppo", "momentum_ppo_signal", "momentum_ppo_hist",
|
||||
"others_dr", "others_dlr", "others_cr"]
|
||||
|
||||
|
||||
class GodStraHo(IHyperOpt):
|
||||
|
||||
@staticmethod
|
||||
def indicator_space() -> List[Dimension]:
|
||||
"""
|
||||
Define your Hyperopt space for searching buy strategy parameters.
|
||||
"""
|
||||
gene = list()
|
||||
|
||||
for i in range(DNA_SIZE):
|
||||
gene.append(Categorical(GodGenes, name=f'buy-indicator-{i}'))
|
||||
gene.append(Categorical(GodGenes, name=f'buy-cross-{i}'))
|
||||
gene.append(Integer(-1, 101, name=f'buy-int-{i}'))
|
||||
gene.append(Real(-1.1, 1.1, name=f'buy-real-{i}'))
|
||||
# Operations
|
||||
# CA: Crossed Above, CB: Crossed Below,
|
||||
# I: Integer, R: Real, D: Disabled
|
||||
gene.append(Categorical(["D", ">", "<", "=", "CA", "CB",
|
||||
">I", "=I", "<I", ">R", "=R", "<R"], name=f'buy-oper-{i}'))
|
||||
return gene
|
||||
|
||||
@staticmethod
|
||||
def buy_strategy_generator(params: Dict[str, Any]) -> Callable:
|
||||
"""
|
||||
Define the buy strategy parameters to be used by Hyperopt.
|
||||
"""
|
||||
def populate_buy_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Buy strategy Hyperopt will build and use.
|
||||
"""
|
||||
conditions = []
|
||||
# GUARDS AND TRENDS
|
||||
for i in range(DNA_SIZE):
|
||||
|
||||
OPR = params[f'buy-oper-{i}']
|
||||
IND = params[f'buy-indicator-{i}']
|
||||
CRS = params[f'buy-cross-{i}']
|
||||
INT = params[f'buy-int-{i}']
|
||||
REAL = params[f'buy-real-{i}']
|
||||
DFIND = dataframe[IND]
|
||||
DFCRS = dataframe[CRS]
|
||||
|
||||
if OPR == ">":
|
||||
conditions.append(DFIND > DFCRS)
|
||||
elif OPR == "=":
|
||||
conditions.append(np.isclose(DFIND, DFCRS))
|
||||
elif OPR == "<":
|
||||
conditions.append(DFIND < DFCRS)
|
||||
elif OPR == "CA":
|
||||
conditions.append(qtpylib.crossed_above(DFIND, DFCRS))
|
||||
elif OPR == "CB":
|
||||
conditions.append(qtpylib.crossed_below(DFIND, DFCRS))
|
||||
elif OPR == ">I":
|
||||
conditions.append(DFIND > INT)
|
||||
elif OPR == "=I":
|
||||
conditions.append(DFIND == INT)
|
||||
elif OPR == "<I":
|
||||
conditions.append(DFIND < INT)
|
||||
elif OPR == ">R":
|
||||
conditions.append(DFIND > REAL)
|
||||
elif OPR == "=R":
|
||||
conditions.append(np.isclose(DFIND, REAL))
|
||||
elif OPR == "<R":
|
||||
conditions.append(DFIND < REAL)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
'buy'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
return populate_buy_trend
|
||||
|
||||
@ staticmethod
|
||||
def sell_indicator_space() -> List[Dimension]:
|
||||
"""
|
||||
Define your Hyperopt space for searching sell strategy parameters.
|
||||
"""
|
||||
gene = list()
|
||||
|
||||
for i in range(DNA_SIZE):
|
||||
gene.append(Categorical(GodGenes, name=f'sell-indicator-{i}'))
|
||||
gene.append(Categorical(GodGenes, name=f'sell-cross-{i}'))
|
||||
gene.append(Integer(-1, 101, name=f'sell-int-{i}'))
|
||||
gene.append(Real(-0.01, 1.01, name=f'sell-real-{i}'))
|
||||
# Operations
|
||||
# CA: Crossed Above, CB: Crossed Below,
|
||||
# I: Integer, R: Real, D: Disabled
|
||||
gene.append(Categorical(["D", ">", "<", "=", "CA", "CB",
|
||||
">I", "=I", "<I", ">R", "=R", "<R"], name=f'sell-oper-{i}'))
|
||||
return gene
|
||||
|
||||
@ staticmethod
|
||||
def sell_strategy_generator(params: Dict[str, Any]) -> Callable:
|
||||
"""
|
||||
Define the sell strategy parameters to be used by Hyperopt.
|
||||
"""
|
||||
def populate_sell_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
"""
|
||||
Sell strategy Hyperopt will build and use.
|
||||
"""
|
||||
conditions = []
|
||||
|
||||
# GUARDS AND TRENDS
|
||||
for i in range(DNA_SIZE):
|
||||
|
||||
OPR = params[f'sell-oper-{i}']
|
||||
IND = params[f'sell-indicator-{i}']
|
||||
CRS = params[f'sell-cross-{i}']
|
||||
INT = params[f'sell-int-{i}']
|
||||
REAL = params[f'sell-real-{i}']
|
||||
DFIND = dataframe[IND]
|
||||
DFCRS = dataframe[CRS]
|
||||
|
||||
if OPR == ">":
|
||||
conditions.append(DFIND > DFCRS)
|
||||
elif OPR == "=":
|
||||
conditions.append(np.isclose(DFIND, DFCRS))
|
||||
elif OPR == "<":
|
||||
conditions.append(DFIND < DFCRS)
|
||||
elif OPR == "CA":
|
||||
conditions.append(qtpylib.crossed_above(DFIND, DFCRS))
|
||||
elif OPR == "CB":
|
||||
conditions.append(qtpylib.crossed_below(DFIND, DFCRS))
|
||||
elif OPR == ">I":
|
||||
conditions.append(DFIND > INT)
|
||||
elif OPR == "=I":
|
||||
conditions.append(DFIND == INT)
|
||||
elif OPR == "<I":
|
||||
conditions.append(DFIND < INT)
|
||||
elif OPR == ">R":
|
||||
conditions.append(DFIND > REAL)
|
||||
elif OPR == "=R":
|
||||
conditions.append(np.isclose(DFIND, REAL))
|
||||
elif OPR == "<R":
|
||||
conditions.append(DFIND < REAL)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
'sell']=1
|
||||
|
||||
return dataframe
|
||||
|
||||
return populate_sell_trend
|
||||
668
GodStraJD.py
Normal file
668
GodStraJD.py
Normal file
@@ -0,0 +1,668 @@
|
||||
# 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 freqtrade import data
|
||||
from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter
|
||||
|
||||
from numpy.lib import math
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
from pandas import DataFrame
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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
|
||||
# TODO: this gene is removed 'MAVP' cuz or error on periods
|
||||
all_god_genes = {
|
||||
'Overlap Studies': {
|
||||
'BBANDS-0', # Bollinger Bands
|
||||
'BBANDS-1', # Bollinger Bands
|
||||
'BBANDS-2', # Bollinger Bands
|
||||
'DEMA', # Double Exponential Moving Average
|
||||
'EMA', # Exponential Moving Average
|
||||
'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline
|
||||
'KAMA', # Kaufman Adaptive Moving Average
|
||||
'MA', # Moving average
|
||||
'MAMA-0', # MESA Adaptive Moving Average
|
||||
'MAMA-1', # MESA Adaptive Moving Average
|
||||
# TODO: Fix this
|
||||
# 'MAVP', # Moving average with variable period
|
||||
'MIDPOINT', # MidPoint over period
|
||||
'MIDPRICE', # Midpoint Price over period
|
||||
'SAR', # Parabolic SAR
|
||||
'SAREXT', # Parabolic SAR - Extended
|
||||
'SMA', # Simple Moving Average
|
||||
'T3', # Triple Exponential Moving Average (T3)
|
||||
'TEMA', # Triple Exponential Moving Average
|
||||
'TRIMA', # Triangular Moving Average
|
||||
'WMA', # Weighted Moving Average
|
||||
},
|
||||
'Momentum Indicators': {
|
||||
'ADX', # Average Directional Movement Index
|
||||
'ADXR', # Average Directional Movement Index Rating
|
||||
'APO', # Absolute Price Oscillator
|
||||
'AROON-0', # Aroon
|
||||
'AROON-1', # Aroon
|
||||
'AROONOSC', # Aroon Oscillator
|
||||
'BOP', # Balance Of Power
|
||||
'CCI', # Commodity Channel Index
|
||||
'CMO', # Chande Momentum Oscillator
|
||||
'DX', # Directional Movement Index
|
||||
'MACD-0', # Moving Average Convergence/Divergence
|
||||
'MACD-1', # Moving Average Convergence/Divergence
|
||||
'MACD-2', # Moving Average Convergence/Divergence
|
||||
'MACDEXT-0', # MACD with controllable MA type
|
||||
'MACDEXT-1', # MACD with controllable MA type
|
||||
'MACDEXT-2', # MACD with controllable MA type
|
||||
'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MFI', # Money Flow Index
|
||||
'MINUS_DI', # Minus Directional Indicator
|
||||
'MINUS_DM', # Minus Directional Movement
|
||||
'MOM', # Momentum
|
||||
'PLUS_DI', # Plus Directional Indicator
|
||||
'PLUS_DM', # Plus Directional Movement
|
||||
'PPO', # Percentage Price Oscillator
|
||||
'ROC', # Rate of change : ((price/prevPrice)-1)*100
|
||||
# Rate of change Percentage: (price-prevPrice)/prevPrice
|
||||
'ROCP',
|
||||
'ROCR', # Rate of change ratio: (price/prevPrice)
|
||||
# Rate of change ratio 100 scale: (price/prevPrice)*100
|
||||
'ROCR100',
|
||||
'RSI', # Relative Strength Index
|
||||
'STOCH-0', # Stochastic
|
||||
'STOCH-1', # Stochastic
|
||||
'STOCHF-0', # Stochastic Fast
|
||||
'STOCHF-1', # Stochastic Fast
|
||||
'STOCHRSI-0', # Stochastic Relative Strength Index
|
||||
'STOCHRSI-1', # Stochastic Relative Strength Index
|
||||
# 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA
|
||||
'TRIX',
|
||||
'ULTOSC', # Ultimate Oscillator
|
||||
'WILLR', # Williams' %R
|
||||
},
|
||||
'Volume Indicators': {
|
||||
'AD', # Chaikin A/D Line
|
||||
'ADOSC', # Chaikin A/D Oscillator
|
||||
'OBV', # On Balance Volume
|
||||
},
|
||||
'Volatility Indicators': {
|
||||
'ATR', # Average True Range
|
||||
'NATR', # Normalized Average True Range
|
||||
'TRANGE', # True Range
|
||||
},
|
||||
'Price Transform': {
|
||||
'AVGPRICE', # Average Price
|
||||
'MEDPRICE', # Median Price
|
||||
'TYPPRICE', # Typical Price
|
||||
'WCLPRICE', # Weighted Close Price
|
||||
},
|
||||
'Cycle Indicators': {
|
||||
'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period
|
||||
'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase
|
||||
'HT_PHASOR-0', # Hilbert Transform - Phasor Components
|
||||
'HT_PHASOR-1', # Hilbert Transform - Phasor Components
|
||||
'HT_SINE-0', # Hilbert Transform - SineWave
|
||||
'HT_SINE-1', # Hilbert Transform - SineWave
|
||||
'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode
|
||||
},
|
||||
'Pattern Recognition': {
|
||||
'CDL2CROWS', # Two Crows
|
||||
'CDL3BLACKCROWS', # Three Black Crows
|
||||
'CDL3INSIDE', # Three Inside Up/Down
|
||||
'CDL3LINESTRIKE', # Three-Line Strike
|
||||
'CDL3OUTSIDE', # Three Outside Up/Down
|
||||
'CDL3STARSINSOUTH', # Three Stars In The South
|
||||
'CDL3WHITESOLDIERS', # Three Advancing White Soldiers
|
||||
'CDLABANDONEDBABY', # Abandoned Baby
|
||||
'CDLADVANCEBLOCK', # Advance Block
|
||||
'CDLBELTHOLD', # Belt-hold
|
||||
'CDLBREAKAWAY', # Breakaway
|
||||
'CDLCLOSINGMARUBOZU', # Closing Marubozu
|
||||
'CDLCONCEALBABYSWALL', # Concealing Baby Swallow
|
||||
'CDLCOUNTERATTACK', # Counterattack
|
||||
'CDLDARKCLOUDCOVER', # Dark Cloud Cover
|
||||
'CDLDOJI', # Doji
|
||||
'CDLDOJISTAR', # Doji Star
|
||||
'CDLDRAGONFLYDOJI', # Dragonfly Doji
|
||||
'CDLENGULFING', # Engulfing Pattern
|
||||
'CDLEVENINGDOJISTAR', # Evening Doji Star
|
||||
'CDLEVENINGSTAR', # Evening Star
|
||||
'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines
|
||||
'CDLGRAVESTONEDOJI', # Gravestone Doji
|
||||
'CDLHAMMER', # Hammer
|
||||
'CDLHANGINGMAN', # Hanging Man
|
||||
'CDLHARAMI', # Harami Pattern
|
||||
'CDLHARAMICROSS', # Harami Cross Pattern
|
||||
'CDLHIGHWAVE', # High-Wave Candle
|
||||
'CDLHIKKAKE', # Hikkake Pattern
|
||||
'CDLHIKKAKEMOD', # Modified Hikkake Pattern
|
||||
'CDLHOMINGPIGEON', # Homing Pigeon
|
||||
'CDLIDENTICAL3CROWS', # Identical Three Crows
|
||||
'CDLINNECK', # In-Neck Pattern
|
||||
'CDLINVERTEDHAMMER', # Inverted Hammer
|
||||
'CDLKICKING', # Kicking
|
||||
'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu
|
||||
'CDLLADDERBOTTOM', # Ladder Bottom
|
||||
'CDLLONGLEGGEDDOJI', # Long Legged Doji
|
||||
'CDLLONGLINE', # Long Line Candle
|
||||
'CDLMARUBOZU', # Marubozu
|
||||
'CDLMATCHINGLOW', # Matching Low
|
||||
'CDLMATHOLD', # Mat Hold
|
||||
'CDLMORNINGDOJISTAR', # Morning Doji Star
|
||||
'CDLMORNINGSTAR', # Morning Star
|
||||
'CDLONNECK', # On-Neck Pattern
|
||||
'CDLPIERCING', # Piercing Pattern
|
||||
'CDLRICKSHAWMAN', # Rickshaw Man
|
||||
'CDLRISEFALL3METHODS', # Rising/Falling Three Methods
|
||||
'CDLSEPARATINGLINES', # Separating Lines
|
||||
'CDLSHOOTINGSTAR', # Shooting Star
|
||||
'CDLSHORTLINE', # Short Line Candle
|
||||
'CDLSPINNINGTOP', # Spinning Top
|
||||
'CDLSTALLEDPATTERN', # Stalled Pattern
|
||||
'CDLSTICKSANDWICH', # Stick Sandwich
|
||||
# Takuri (Dragonfly Doji with very long lower shadow)
|
||||
'CDLTAKURI',
|
||||
'CDLTASUKIGAP', # Tasuki Gap
|
||||
'CDLTHRUSTING', # Thrusting Pattern
|
||||
'CDLTRISTAR', # Tristar Pattern
|
||||
'CDLUNIQUE3RIVER', # Unique 3 River
|
||||
'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows
|
||||
'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods
|
||||
|
||||
},
|
||||
'Statistic Functions': {
|
||||
'BETA', # Beta
|
||||
'CORREL', # Pearson's Correlation Coefficient (r)
|
||||
'LINEARREG', # Linear Regression
|
||||
'LINEARREG_ANGLE', # Linear Regression Angle
|
||||
'LINEARREG_INTERCEPT', # Linear Regression Intercept
|
||||
'LINEARREG_SLOPE', # Linear Regression Slope
|
||||
'STDDEV', # Standard Deviation
|
||||
'TSF', # Time Series Forecast
|
||||
'VAR', # Variance
|
||||
}
|
||||
|
||||
}
|
||||
god_genes = set()
|
||||
########################### SETTINGS ##############################
|
||||
|
||||
# god_genes = {'SMA'}
|
||||
god_genes |= all_god_genes['Overlap Studies']
|
||||
god_genes |= all_god_genes['Momentum Indicators']
|
||||
god_genes |= all_god_genes['Volume Indicators']
|
||||
god_genes |= all_god_genes['Volatility Indicators']
|
||||
god_genes |= all_god_genes['Price Transform']
|
||||
god_genes |= all_god_genes['Cycle Indicators']
|
||||
god_genes |= all_god_genes['Pattern Recognition']
|
||||
god_genes |= all_god_genes['Statistic Functions']
|
||||
|
||||
timeperiods = [5, 6, 12, 15, 50, 55, 100, 110]
|
||||
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 = 4
|
||||
DECIMALS = 1
|
||||
########################### END SETTINGS ##########################
|
||||
# DATAFRAME = DataFrame()
|
||||
|
||||
god_genes = list(god_genes)
|
||||
# print('selected indicators for optimzatin: \n', god_genes)
|
||||
|
||||
god_genes_with_timeperiod = list()
|
||||
for god_gene in god_genes:
|
||||
for timeperiod in timeperiods:
|
||||
god_genes_with_timeperiod.append(f'{god_gene}-{timeperiod}')
|
||||
|
||||
# Let give somethings to CatagoricalParam to Play with them
|
||||
# When just one thing is inside catagorical lists
|
||||
# TODO: its Not True Way :)
|
||||
if len(god_genes) == 1:
|
||||
god_genes = god_genes*2
|
||||
if len(timeperiods) == 1:
|
||||
timeperiods = timeperiods*2
|
||||
if len(operators) == 1:
|
||||
operators = operators*2
|
||||
|
||||
|
||||
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):
|
||||
|
||||
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] > dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "=":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "<":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "C":
|
||||
condition = (
|
||||
(qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) |
|
||||
(qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator]))
|
||||
)
|
||||
elif operator == "CA":
|
||||
condition = (
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "CB":
|
||||
condition = (
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == ">R":
|
||||
condition = (
|
||||
dataframe[indicator] > real_num
|
||||
)
|
||||
elif operator == "=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], real_num)
|
||||
)
|
||||
elif operator == "<R":
|
||||
condition = (
|
||||
dataframe[indicator] < real_num
|
||||
)
|
||||
elif operator == "/>R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) > real_num
|
||||
)
|
||||
elif operator == "/=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator].div(
|
||||
dataframe[crossed_indicator]), real_num)
|
||||
)
|
||||
elif operator == "/<R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) < real_num
|
||||
)
|
||||
elif operator == "UT":
|
||||
condition = (
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "DT":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "OT":
|
||||
condition = (
|
||||
|
||||
np.isclose(dataframe[indicator], dataframe[indicator_trend_sma])
|
||||
)
|
||||
elif operator == "CUT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "CDT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "COT":
|
||||
condition = (
|
||||
(
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) |
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
) &
|
||||
(
|
||||
np.isclose(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return condition, dataframe
|
||||
|
||||
|
||||
class GodStraJD(IStrategy):
|
||||
# #################### RESULTS PASTE PLACE ####################
|
||||
# ROI table:
|
||||
minimal_roi = {
|
||||
"0": 0.598,
|
||||
"644": 0.166,
|
||||
"3269": 0.115,
|
||||
"7289": 0
|
||||
}
|
||||
|
||||
# Stoploss:
|
||||
stoploss = -0.128
|
||||
# Buy hypers
|
||||
timeframe = '4h'
|
||||
|
||||
# Trailing stoploss
|
||||
trailing_stop = True
|
||||
trailing_stop_positive = 0.15
|
||||
trailing_stop_positive_offset = 0.20
|
||||
trailing_only_offset_is_reached = True
|
||||
|
||||
# #################### END OF RESULT PLACE ####################
|
||||
|
||||
# TODO: Its not dry code!
|
||||
# Buy Hyperoptable Parameters/Spaces.
|
||||
buy_crossed_indicator0 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="ADD-20", space='buy')
|
||||
buy_crossed_indicator1 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="ASIN-6", space='buy')
|
||||
buy_crossed_indicator2 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy')
|
||||
|
||||
buy_indicator0 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="SMA-100", space='buy')
|
||||
buy_indicator1 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="WILLR-50", space='buy')
|
||||
buy_indicator2 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy')
|
||||
|
||||
buy_operator0 = CategoricalParameter(operators, default="/<R", space='buy')
|
||||
buy_operator1 = CategoricalParameter(operators, default="<R", space='buy')
|
||||
buy_operator2 = CategoricalParameter(operators, default="CB", space='buy')
|
||||
|
||||
buy_real_num0 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.89009, space='buy')
|
||||
buy_real_num1 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.56953, space='buy')
|
||||
buy_real_num2 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.38365, space='buy')
|
||||
|
||||
# Sell Hyperoptable Parameters/Spaces.
|
||||
sell_crossed_indicator0 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLSHOOTINGSTAR-150", space='sell')
|
||||
sell_crossed_indicator1 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="MAMA-1-100", space='sell')
|
||||
sell_crossed_indicator2 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLMATHOLD-6", space='sell')
|
||||
|
||||
sell_indicator0 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLUPSIDEGAP2CROWS-5", space='sell')
|
||||
sell_indicator1 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLHARAMICROSS-150", space='sell')
|
||||
sell_indicator2 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDL2CROWS-5", space='sell')
|
||||
|
||||
sell_operator0 = CategoricalParameter(
|
||||
operators, default="<R", space='sell')
|
||||
sell_operator1 = CategoricalParameter(operators, default="D", space='sell')
|
||||
sell_operator2 = CategoricalParameter(
|
||||
operators, default="/>R", space='sell')
|
||||
|
||||
sell_real_num0 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.09731, space='sell')
|
||||
sell_real_num1 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.81657, space='sell')
|
||||
sell_real_num2 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.87267, space='sell')
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
'''
|
||||
It's good to calculate all indicators in all time periods here and so optimize the strategy.
|
||||
But this strategy can take much time to generate anything that may not use in his optimization.
|
||||
I just calculate the specific indicators in specific time period inside buy and sell strategy populator methods if needed.
|
||||
Also, this method (populate_indicators) just calculates default value of hyperoptable params
|
||||
so using this method have not big benefits instade of calculating useable things inside buy and sell trand populators
|
||||
'''
|
||||
|
||||
# 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"]
|
||||
)
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
|
||||
# TODO: Its not dry code!
|
||||
buy_indicator = self.buy_indicator0.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator0.value
|
||||
buy_operator = self.buy_operator0.value
|
||||
buy_real_num = self.buy_real_num0.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
# backup
|
||||
buy_indicator = self.buy_indicator1.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator1.value
|
||||
buy_operator = self.buy_operator1.value
|
||||
buy_real_num = self.buy_real_num1.value
|
||||
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
buy_indicator = self.buy_indicator2.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator2.value
|
||||
buy_operator = self.buy_operator2.value
|
||||
buy_real_num = self.buy_real_num2.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['close'] < dataframe['bb_lowerband'])
|
||||
& (dataframe['bb_width'] >= 0.15)
|
||||
& (dataframe['volume'] > 0)
|
||||
) |
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
'buy']=1
|
||||
|
||||
# print(len(dataframe.keys()))
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
# TODO: Its not dry code!
|
||||
sell_indicator = self.sell_indicator0.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator0.value
|
||||
sell_operator = self.sell_operator0.value
|
||||
sell_real_num = self.sell_real_num0.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
sell_indicator = self.sell_indicator1.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator1.value
|
||||
sell_operator = self.sell_operator1.value
|
||||
sell_real_num = self.sell_real_num1.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
sell_indicator = self.sell_indicator2.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator2.value
|
||||
sell_operator = self.sell_operator2.value
|
||||
sell_real_num = self.sell_real_num2.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
'sell']=1
|
||||
return dataframe
|
||||
858
GodStraJD1.py
Normal file
858
GodStraJD1.py
Normal file
@@ -0,0 +1,858 @@
|
||||
# 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 freqtrade import data
|
||||
from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter
|
||||
|
||||
from numpy.lib import math
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
from pandas import DataFrame
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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
|
||||
# TODO: this gene is removed 'MAVP' cuz or error on periods
|
||||
all_god_genes = {
|
||||
'Overlap Studies': {
|
||||
'BBANDS-0', # Bollinger Bands
|
||||
'BBANDS-1', # Bollinger Bands
|
||||
'BBANDS-2', # Bollinger Bands
|
||||
'DEMA', # Double Exponential Moving Average
|
||||
'EMA', # Exponential Moving Average
|
||||
'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline
|
||||
'KAMA', # Kaufman Adaptive Moving Average
|
||||
'MA', # Moving average
|
||||
'MAMA-0', # MESA Adaptive Moving Average
|
||||
'MAMA-1', # MESA Adaptive Moving Average
|
||||
# TODO: Fix this
|
||||
# 'MAVP', # Moving average with variable period
|
||||
'MIDPOINT', # MidPoint over period
|
||||
'MIDPRICE', # Midpoint Price over period
|
||||
'SAR', # Parabolic SAR
|
||||
'SAREXT', # Parabolic SAR - Extended
|
||||
'SMA', # Simple Moving Average
|
||||
'T3', # Triple Exponential Moving Average (T3)
|
||||
'TEMA', # Triple Exponential Moving Average
|
||||
'TRIMA', # Triangular Moving Average
|
||||
'WMA', # Weighted Moving Average
|
||||
},
|
||||
'Momentum Indicators': {
|
||||
'ADX', # Average Directional Movement Index
|
||||
'ADXR', # Average Directional Movement Index Rating
|
||||
'APO', # Absolute Price Oscillator
|
||||
'AROON-0', # Aroon
|
||||
'AROON-1', # Aroon
|
||||
'AROONOSC', # Aroon Oscillator
|
||||
'BOP', # Balance Of Power
|
||||
'CCI', # Commodity Channel Index
|
||||
'CMO', # Chande Momentum Oscillator
|
||||
'DX', # Directional Movement Index
|
||||
'MACD-0', # Moving Average Convergence/Divergence
|
||||
'MACD-1', # Moving Average Convergence/Divergence
|
||||
'MACD-2', # Moving Average Convergence/Divergence
|
||||
'MACDEXT-0', # MACD with controllable MA type
|
||||
'MACDEXT-1', # MACD with controllable MA type
|
||||
'MACDEXT-2', # MACD with controllable MA type
|
||||
'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MFI', # Money Flow Index
|
||||
'MINUS_DI', # Minus Directional Indicator
|
||||
'MINUS_DM', # Minus Directional Movement
|
||||
'MOM', # Momentum
|
||||
'PLUS_DI', # Plus Directional Indicator
|
||||
'PLUS_DM', # Plus Directional Movement
|
||||
'PPO', # Percentage Price Oscillator
|
||||
'ROC', # Rate of change : ((price/prevPrice)-1)*100
|
||||
# Rate of change Percentage: (price-prevPrice)/prevPrice
|
||||
'ROCP',
|
||||
'ROCR', # Rate of change ratio: (price/prevPrice)
|
||||
# Rate of change ratio 100 scale: (price/prevPrice)*100
|
||||
'ROCR100',
|
||||
'RSI', # Relative Strength Index
|
||||
'STOCH-0', # Stochastic
|
||||
'STOCH-1', # Stochastic
|
||||
'STOCHF-0', # Stochastic Fast
|
||||
'STOCHF-1', # Stochastic Fast
|
||||
'STOCHRSI-0', # Stochastic Relative Strength Index
|
||||
'STOCHRSI-1', # Stochastic Relative Strength Index
|
||||
# 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA
|
||||
'TRIX',
|
||||
'ULTOSC', # Ultimate Oscillator
|
||||
'WILLR', # Williams' %R
|
||||
},
|
||||
'Volume Indicators': {
|
||||
'AD', # Chaikin A/D Line
|
||||
'ADOSC', # Chaikin A/D Oscillator
|
||||
'OBV', # On Balance Volume
|
||||
},
|
||||
'Volatility Indicators': {
|
||||
'ATR', # Average True Range
|
||||
'NATR', # Normalized Average True Range
|
||||
'TRANGE', # True Range
|
||||
},
|
||||
'Price Transform': {
|
||||
'AVGPRICE', # Average Price
|
||||
'MEDPRICE', # Median Price
|
||||
'TYPPRICE', # Typical Price
|
||||
'WCLPRICE', # Weighted Close Price
|
||||
},
|
||||
'Cycle Indicators': {
|
||||
'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period
|
||||
'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase
|
||||
'HT_PHASOR-0', # Hilbert Transform - Phasor Components
|
||||
'HT_PHASOR-1', # Hilbert Transform - Phasor Components
|
||||
'HT_SINE-0', # Hilbert Transform - SineWave
|
||||
'HT_SINE-1', # Hilbert Transform - SineWave
|
||||
'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode
|
||||
},
|
||||
'Pattern Recognition': {
|
||||
'CDL2CROWS', # Two Crows
|
||||
'CDL3BLACKCROWS', # Three Black Crows
|
||||
'CDL3INSIDE', # Three Inside Up/Down
|
||||
'CDL3LINESTRIKE', # Three-Line Strike
|
||||
'CDL3OUTSIDE', # Three Outside Up/Down
|
||||
'CDL3STARSINSOUTH', # Three Stars In The South
|
||||
'CDL3WHITESOLDIERS', # Three Advancing White Soldiers
|
||||
'CDLABANDONEDBABY', # Abandoned Baby
|
||||
'CDLADVANCEBLOCK', # Advance Block
|
||||
'CDLBELTHOLD', # Belt-hold
|
||||
'CDLBREAKAWAY', # Breakaway
|
||||
'CDLCLOSINGMARUBOZU', # Closing Marubozu
|
||||
'CDLCONCEALBABYSWALL', # Concealing Baby Swallow
|
||||
'CDLCOUNTERATTACK', # Counterattack
|
||||
'CDLDARKCLOUDCOVER', # Dark Cloud Cover
|
||||
'CDLDOJI', # Doji
|
||||
'CDLDOJISTAR', # Doji Star
|
||||
'CDLDRAGONFLYDOJI', # Dragonfly Doji
|
||||
'CDLENGULFING', # Engulfing Pattern
|
||||
'CDLEVENINGDOJISTAR', # Evening Doji Star
|
||||
'CDLEVENINGSTAR', # Evening Star
|
||||
'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines
|
||||
'CDLGRAVESTONEDOJI', # Gravestone Doji
|
||||
'CDLHAMMER', # Hammer
|
||||
'CDLHANGINGMAN', # Hanging Man
|
||||
'CDLHARAMI', # Harami Pattern
|
||||
'CDLHARAMICROSS', # Harami Cross Pattern
|
||||
'CDLHIGHWAVE', # High-Wave Candle
|
||||
'CDLHIKKAKE', # Hikkake Pattern
|
||||
'CDLHIKKAKEMOD', # Modified Hikkake Pattern
|
||||
'CDLHOMINGPIGEON', # Homing Pigeon
|
||||
'CDLIDENTICAL3CROWS', # Identical Three Crows
|
||||
'CDLINNECK', # In-Neck Pattern
|
||||
'CDLINVERTEDHAMMER', # Inverted Hammer
|
||||
'CDLKICKING', # Kicking
|
||||
'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu
|
||||
'CDLLADDERBOTTOM', # Ladder Bottom
|
||||
'CDLLONGLEGGEDDOJI', # Long Legged Doji
|
||||
'CDLLONGLINE', # Long Line Candle
|
||||
'CDLMARUBOZU', # Marubozu
|
||||
'CDLMATCHINGLOW', # Matching Low
|
||||
'CDLMATHOLD', # Mat Hold
|
||||
'CDLMORNINGDOJISTAR', # Morning Doji Star
|
||||
'CDLMORNINGSTAR', # Morning Star
|
||||
'CDLONNECK', # On-Neck Pattern
|
||||
'CDLPIERCING', # Piercing Pattern
|
||||
'CDLRICKSHAWMAN', # Rickshaw Man
|
||||
'CDLRISEFALL3METHODS', # Rising/Falling Three Methods
|
||||
'CDLSEPARATINGLINES', # Separating Lines
|
||||
'CDLSHOOTINGSTAR', # Shooting Star
|
||||
'CDLSHORTLINE', # Short Line Candle
|
||||
'CDLSPINNINGTOP', # Spinning Top
|
||||
'CDLSTALLEDPATTERN', # Stalled Pattern
|
||||
'CDLSTICKSANDWICH', # Stick Sandwich
|
||||
# Takuri (Dragonfly Doji with very long lower shadow)
|
||||
'CDLTAKURI',
|
||||
'CDLTASUKIGAP', # Tasuki Gap
|
||||
'CDLTHRUSTING', # Thrusting Pattern
|
||||
'CDLTRISTAR', # Tristar Pattern
|
||||
'CDLUNIQUE3RIVER', # Unique 3 River
|
||||
'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows
|
||||
'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods
|
||||
|
||||
},
|
||||
'Statistic Functions': {
|
||||
'BETA', # Beta
|
||||
'CORREL', # Pearson's Correlation Coefficient (r)
|
||||
'LINEARREG', # Linear Regression
|
||||
'LINEARREG_ANGLE', # Linear Regression Angle
|
||||
'LINEARREG_INTERCEPT', # Linear Regression Intercept
|
||||
'LINEARREG_SLOPE', # Linear Regression Slope
|
||||
'STDDEV', # Standard Deviation
|
||||
'TSF', # Time Series Forecast
|
||||
'VAR', # Variance
|
||||
}
|
||||
|
||||
}
|
||||
god_genes = set()
|
||||
########################### SETTINGS ##############################
|
||||
|
||||
# god_genes = {'SMA'}
|
||||
god_genes |= all_god_genes['Overlap Studies']
|
||||
god_genes |= all_god_genes['Momentum Indicators']
|
||||
god_genes |= all_god_genes['Volume Indicators']
|
||||
god_genes |= all_god_genes['Volatility Indicators']
|
||||
god_genes |= all_god_genes['Price Transform']
|
||||
god_genes |= all_god_genes['Cycle Indicators']
|
||||
god_genes |= all_god_genes['Pattern Recognition']
|
||||
god_genes |= all_god_genes['Statistic Functions']
|
||||
|
||||
timeperiods = [5, 6, 12, 15, 50, 55, 100, 110]
|
||||
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 = 1
|
||||
########################### END SETTINGS ##########################
|
||||
# DATAFRAME = DataFrame()
|
||||
|
||||
god_genes = list(god_genes)
|
||||
# print('selected indicators for optimzatin: \n', god_genes)
|
||||
|
||||
god_genes_with_timeperiod = list()
|
||||
for god_gene in god_genes:
|
||||
for timeperiod in timeperiods:
|
||||
god_genes_with_timeperiod.append(f'{god_gene}-{timeperiod}')
|
||||
|
||||
# Let give somethings to CatagoricalParam to Play with them
|
||||
# When just one thing is inside catagorical lists
|
||||
# TODO: its Not True Way :)
|
||||
if len(god_genes) == 1:
|
||||
god_genes = god_genes*2
|
||||
if len(timeperiods) == 1:
|
||||
timeperiods = timeperiods*2
|
||||
if len(operators) == 1:
|
||||
operators = operators*2
|
||||
|
||||
|
||||
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):
|
||||
|
||||
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] > dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "=":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "<":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "C":
|
||||
condition = (
|
||||
(qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) |
|
||||
(qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator]))
|
||||
)
|
||||
elif operator == "CA":
|
||||
condition = (
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "CB":
|
||||
condition = (
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == ">R":
|
||||
condition = (
|
||||
dataframe[indicator] > real_num
|
||||
)
|
||||
elif operator == "=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], real_num)
|
||||
)
|
||||
elif operator == "<R":
|
||||
condition = (
|
||||
dataframe[indicator] < real_num
|
||||
)
|
||||
elif operator == "/>R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) > real_num
|
||||
)
|
||||
elif operator == "/=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator].div(
|
||||
dataframe[crossed_indicator]), real_num)
|
||||
)
|
||||
elif operator == "/<R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) < real_num
|
||||
)
|
||||
elif operator == "UT":
|
||||
condition = (
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "DT":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "OT":
|
||||
condition = (
|
||||
|
||||
np.isclose(dataframe[indicator], dataframe[indicator_trend_sma])
|
||||
)
|
||||
elif operator == "CUT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "CDT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "COT":
|
||||
condition = (
|
||||
(
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) |
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
) &
|
||||
(
|
||||
np.isclose(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return condition, dataframe
|
||||
|
||||
|
||||
class GodStraJD1(IStrategy):
|
||||
# #################### RESULTS PASTE PLACE ####################
|
||||
# ROI table:
|
||||
minimal_roi = {
|
||||
"0": 0.598,
|
||||
"644": 0.166,
|
||||
"3269": 0.115,
|
||||
"7289": 0
|
||||
}
|
||||
|
||||
# Stoploss:
|
||||
stoploss = -0.128
|
||||
# Buy hypers
|
||||
timeframe = '4h'
|
||||
# Trailing stoploss
|
||||
trailing_stop = True
|
||||
trailing_stop_positive = 0.15
|
||||
trailing_stop_positive_offset = 0.20
|
||||
trailing_only_offset_is_reached = True
|
||||
|
||||
|
||||
# #################### END OF RESULT PLACE ####################
|
||||
|
||||
# TODO: Its not dry code!
|
||||
# Buy Hyperoptable Parameters/Spaces.
|
||||
buy_crossed_indicator0 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="ADD-20", space='buy')
|
||||
buy_crossed_indicator1 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="ASIN-6", space='buy')
|
||||
buy_crossed_indicator2 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy')
|
||||
|
||||
buy_indicator0 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="SMA-100", space='buy')
|
||||
buy_indicator1 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="WILLR-50", space='buy')
|
||||
buy_indicator2 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy')
|
||||
|
||||
buy_operator0 = CategoricalParameter(operators, default="/<R", space='buy')
|
||||
buy_operator1 = CategoricalParameter(operators, default="<R", space='buy')
|
||||
buy_operator2 = CategoricalParameter(operators, default="CB", space='buy')
|
||||
|
||||
buy_real_num0 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.89009, space='buy')
|
||||
buy_real_num1 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.56953, space='buy')
|
||||
buy_real_num2 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.38365, space='buy')
|
||||
|
||||
# Sell Hyperoptable Parameters/Spaces.
|
||||
sell_crossed_indicator0 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLSHOOTINGSTAR-150", space='sell')
|
||||
sell_crossed_indicator1 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="MAMA-1-100", space='sell')
|
||||
sell_crossed_indicator2 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLMATHOLD-6", space='sell')
|
||||
|
||||
sell_indicator0 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLUPSIDEGAP2CROWS-5", space='sell')
|
||||
sell_indicator1 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLHARAMICROSS-150", space='sell')
|
||||
sell_indicator2 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDL2CROWS-5", space='sell')
|
||||
|
||||
sell_operator0 = CategoricalParameter(
|
||||
operators, default="<R", space='sell')
|
||||
sell_operator1 = CategoricalParameter(operators, default="D", space='sell')
|
||||
sell_operator2 = CategoricalParameter(
|
||||
operators, default="/>R", space='sell')
|
||||
|
||||
sell_real_num0 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.09731, space='sell')
|
||||
sell_real_num1 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.81657, space='sell')
|
||||
sell_real_num2 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.87267, space='sell')
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
'''
|
||||
It's good to calculate all indicators in all time periods here and so optimize the strategy.
|
||||
But this strategy can take much time to generate anything that may not use in his optimization.
|
||||
I just calculate the specific indicators in specific time period inside buy and sell strategy populator methods if needed.
|
||||
Also, this method (populate_indicators) just calculates default value of hyperoptable params
|
||||
so using this method have not big benefits instade of calculating useable things inside buy and sell trand populators
|
||||
'''
|
||||
# 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"]
|
||||
)
|
||||
|
||||
# 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"]
|
||||
)
|
||||
|
||||
# # EMA - Exponential Moving Average
|
||||
# dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
|
||||
# TODO: Its not dry code!
|
||||
buy_indicator = self.buy_indicator0.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator0.value
|
||||
buy_operator = self.buy_operator0.value
|
||||
buy_real_num = self.buy_real_num0.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
# backup
|
||||
buy_indicator = self.buy_indicator1.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator1.value
|
||||
buy_operator = self.buy_operator1.value
|
||||
buy_real_num = self.buy_real_num1.value
|
||||
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
buy_indicator = self.buy_indicator2.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator2.value
|
||||
buy_operator = self.buy_operator2.value
|
||||
buy_real_num = self.buy_real_num2.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['close'] < dataframe['bb_lowerband'])
|
||||
& (dataframe['bb_width'] >= 0.14)
|
||||
& (dataframe['volume'] > 0)
|
||||
) |
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
'buy']=1
|
||||
# print(len(dataframe.keys()))
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
# TODO: Its not dry code!
|
||||
sell_indicator = self.sell_indicator0.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator0.value
|
||||
sell_operator = self.sell_operator0.value
|
||||
sell_real_num = self.sell_real_num0.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
sell_indicator = self.sell_indicator1.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator1.value
|
||||
sell_operator = self.sell_operator1.value
|
||||
sell_real_num = self.sell_real_num1.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
sell_indicator = self.sell_indicator2.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator2.value
|
||||
sell_operator = self.sell_operator2.value
|
||||
sell_real_num = self.sell_real_num2.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
#dataframe.loc[(dataframe['close'] < dataframe['bb_lowerband']),'sell']=1
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
(
|
||||
reduce(lambda x, y: x & y, conditions)
|
||||
# (
|
||||
# # StrategyHelperLocal.four_red_candles(dataframe) &
|
||||
# # dataframe['bb_width'] >= 0.025
|
||||
# (
|
||||
# ((dataframe['open'] - dataframe['close'].shift(4)) / dataframe['open'] > 0.01) |
|
||||
# ((dataframe['open'] - dataframe['close'].shift(5)) / dataframe['open'] > 0.01) |
|
||||
# ((dataframe['open'] - dataframe['close'].shift(6)) / dataframe['open'] > 0.01) |
|
||||
# ((dataframe['open'] - dataframe['close'].shift(7)) / dataframe['open'] > 0.01)
|
||||
# )
|
||||
# )
|
||||
),
|
||||
'sell']=1
|
||||
return dataframe
|
||||
|
||||
|
||||
class StrategyHelperLocal:
|
||||
"""
|
||||
simple helper class to predefine a couple of patterns for our
|
||||
strategy
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def two_green_candles(dataframe):
|
||||
"""
|
||||
evaluates if we are having 7 green candles in a row
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'] < dataframe['close']) &
|
||||
(dataframe['open'].shift(1) < dataframe['close'].shift(1))
|
||||
# (dataframe['open'].shift(2) < dataframe['close'].shift(2))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def no_more_three_green_candles(dataframe):
|
||||
"""
|
||||
evaluates if we are having not more than 3 green candles in a row
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:return:
|
||||
"""
|
||||
return not (
|
||||
(dataframe['open'] < dataframe['close']) &
|
||||
(dataframe['open'].shift(1) < dataframe['close'].shift(1)) &
|
||||
(dataframe['open'].shift(2) < dataframe['close'].shift(2)) &
|
||||
(dataframe['open'].shift(3) < dataframe['close'].shift(3))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def seven_green_candles(dataframe):
|
||||
"""
|
||||
evaluates if we are having 7 green candles in a row
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'] < dataframe['close']) &
|
||||
(dataframe['open'].shift(1) < dataframe['close'].shift(1)) &
|
||||
(dataframe['open'].shift(2) < dataframe['close'].shift(2)) &
|
||||
(dataframe['open'].shift(3) < dataframe['close'].shift(3)) &
|
||||
(dataframe['open'].shift(4) < dataframe['close'].shift(4)) &
|
||||
(dataframe['open'].shift(5) < dataframe['close'].shift(5)) &
|
||||
(dataframe['open'].shift(6) < dataframe['close'].shift(6)) &
|
||||
(dataframe['open'].shift(7) < dataframe['close'].shift(7))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def eight_green_candles(dataframe):
|
||||
"""
|
||||
evaluates if we are having 8 green candles in a row
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'] < dataframe['close']) &
|
||||
(dataframe['open'].shift(1) < dataframe['close'].shift(1)) &
|
||||
(dataframe['open'].shift(2) < dataframe['close'].shift(2)) &
|
||||
(dataframe['open'].shift(3) < dataframe['close'].shift(3)) &
|
||||
(dataframe['open'].shift(4) < dataframe['close'].shift(4)) &
|
||||
(dataframe['open'].shift(5) < dataframe['close'].shift(5)) &
|
||||
(dataframe['open'].shift(6) < dataframe['close'].shift(6)) &
|
||||
(dataframe['open'].shift(7) < dataframe['close'].shift(7)) &
|
||||
(dataframe['open'].shift(8) < dataframe['close'].shift(8))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def two_red_candles(dataframe, shift=0):
|
||||
"""
|
||||
evaluates if we are having 8 red candles in a row
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:param shift: shift the pattern by n
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) &
|
||||
(dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift))
|
||||
# (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) &
|
||||
# (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) &
|
||||
# (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) &
|
||||
# (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) &
|
||||
# (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def four_red_candles(dataframe, shift=0):
|
||||
"""
|
||||
evaluates if we are having 8 red candles in a row
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:param shift: shift the pattern by n
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) &
|
||||
(dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) &
|
||||
(dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) &
|
||||
(dataframe['open'].shift(3 + shift) > dataframe['close'].shift(3 + shift)) &
|
||||
(dataframe['open'].shift(4 + shift) > dataframe['close'].shift(4 + shift))
|
||||
# (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) &
|
||||
# (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) &
|
||||
# (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) &
|
||||
# (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def two_green_one_red_candle(dataframe):
|
||||
"""
|
||||
evaluates if we are having a red candle and 4 previous green
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'] < dataframe['close']) &
|
||||
(dataframe['open'].shift(1) < dataframe['close'].shift(1)) &
|
||||
(dataframe['open'].shift(2) > dataframe['close'].shift(2))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def four_green_one_red_candle(dataframe):
|
||||
"""
|
||||
evaluates if we are having a red candle and 4 previous green
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'] > dataframe['close']) &
|
||||
(dataframe['open'].shift(1) < dataframe['close'].shift(1)) &
|
||||
(dataframe['open'].shift(2) < dataframe['close'].shift(2)) &
|
||||
(dataframe['open'].shift(3) < dataframe['close'].shift(3)) &
|
||||
(dataframe['open'].shift(4) < dataframe['close'].shift(4))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def four_red_one_green_candle(dataframe):
|
||||
"""
|
||||
evaluates if we are having a green candle and 4 previous red
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'] < dataframe['close']) &
|
||||
(dataframe['open'].shift(1) > dataframe['close'].shift(1)) &
|
||||
(dataframe['open'].shift(2) > dataframe['close'].shift(2)) &
|
||||
(dataframe['open'].shift(3) > dataframe['close'].shift(3)) &
|
||||
(dataframe['open'].shift(4) > dataframe['close'].shift(4))
|
||||
)
|
||||
848
GodStraJD2.py
Normal file
848
GodStraJD2.py
Normal file
@@ -0,0 +1,848 @@
|
||||
# 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 freqtrade import data
|
||||
from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter
|
||||
|
||||
from numpy.lib import math
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
from pandas import DataFrame
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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
|
||||
# TODO: this gene is removed 'MAVP' cuz or error on periods
|
||||
all_god_genes = {
|
||||
'Overlap Studies': {
|
||||
'BBANDS-0', # Bollinger Bands
|
||||
'BBANDS-1', # Bollinger Bands
|
||||
'BBANDS-2', # Bollinger Bands
|
||||
'DEMA', # Double Exponential Moving Average
|
||||
'EMA', # Exponential Moving Average
|
||||
'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline
|
||||
'KAMA', # Kaufman Adaptive Moving Average
|
||||
'MA', # Moving average
|
||||
'MAMA-0', # MESA Adaptive Moving Average
|
||||
'MAMA-1', # MESA Adaptive Moving Average
|
||||
# TODO: Fix this
|
||||
# 'MAVP', # Moving average with variable period
|
||||
'MIDPOINT', # MidPoint over period
|
||||
'MIDPRICE', # Midpoint Price over period
|
||||
'SAR', # Parabolic SAR
|
||||
'SAREXT', # Parabolic SAR - Extended
|
||||
'SMA', # Simple Moving Average
|
||||
'T3', # Triple Exponential Moving Average (T3)
|
||||
'TEMA', # Triple Exponential Moving Average
|
||||
'TRIMA', # Triangular Moving Average
|
||||
'WMA', # Weighted Moving Average
|
||||
},
|
||||
'Momentum Indicators': {
|
||||
'ADX', # Average Directional Movement Index
|
||||
'ADXR', # Average Directional Movement Index Rating
|
||||
'APO', # Absolute Price Oscillator
|
||||
'AROON-0', # Aroon
|
||||
'AROON-1', # Aroon
|
||||
'AROONOSC', # Aroon Oscillator
|
||||
'BOP', # Balance Of Power
|
||||
'CCI', # Commodity Channel Index
|
||||
'CMO', # Chande Momentum Oscillator
|
||||
'DX', # Directional Movement Index
|
||||
'MACD-0', # Moving Average Convergence/Divergence
|
||||
'MACD-1', # Moving Average Convergence/Divergence
|
||||
'MACD-2', # Moving Average Convergence/Divergence
|
||||
'MACDEXT-0', # MACD with controllable MA type
|
||||
'MACDEXT-1', # MACD with controllable MA type
|
||||
'MACDEXT-2', # MACD with controllable MA type
|
||||
'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MFI', # Money Flow Index
|
||||
'MINUS_DI', # Minus Directional Indicator
|
||||
'MINUS_DM', # Minus Directional Movement
|
||||
'MOM', # Momentum
|
||||
'PLUS_DI', # Plus Directional Indicator
|
||||
'PLUS_DM', # Plus Directional Movement
|
||||
'PPO', # Percentage Price Oscillator
|
||||
'ROC', # Rate of change : ((price/prevPrice)-1)*100
|
||||
# Rate of change Percentage: (price-prevPrice)/prevPrice
|
||||
'ROCP',
|
||||
'ROCR', # Rate of change ratio: (price/prevPrice)
|
||||
# Rate of change ratio 100 scale: (price/prevPrice)*100
|
||||
'ROCR100',
|
||||
'RSI', # Relative Strength Index
|
||||
'STOCH-0', # Stochastic
|
||||
'STOCH-1', # Stochastic
|
||||
'STOCHF-0', # Stochastic Fast
|
||||
'STOCHF-1', # Stochastic Fast
|
||||
'STOCHRSI-0', # Stochastic Relative Strength Index
|
||||
'STOCHRSI-1', # Stochastic Relative Strength Index
|
||||
# 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA
|
||||
'TRIX',
|
||||
'ULTOSC', # Ultimate Oscillator
|
||||
'WILLR', # Williams' %R
|
||||
},
|
||||
'Volume Indicators': {
|
||||
'AD', # Chaikin A/D Line
|
||||
'ADOSC', # Chaikin A/D Oscillator
|
||||
'OBV', # On Balance Volume
|
||||
},
|
||||
'Volatility Indicators': {
|
||||
'ATR', # Average True Range
|
||||
'NATR', # Normalized Average True Range
|
||||
'TRANGE', # True Range
|
||||
},
|
||||
'Price Transform': {
|
||||
'AVGPRICE', # Average Price
|
||||
'MEDPRICE', # Median Price
|
||||
'TYPPRICE', # Typical Price
|
||||
'WCLPRICE', # Weighted Close Price
|
||||
},
|
||||
'Cycle Indicators': {
|
||||
'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period
|
||||
'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase
|
||||
'HT_PHASOR-0', # Hilbert Transform - Phasor Components
|
||||
'HT_PHASOR-1', # Hilbert Transform - Phasor Components
|
||||
'HT_SINE-0', # Hilbert Transform - SineWave
|
||||
'HT_SINE-1', # Hilbert Transform - SineWave
|
||||
'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode
|
||||
},
|
||||
'Pattern Recognition': {
|
||||
'CDL2CROWS', # Two Crows
|
||||
'CDL3BLACKCROWS', # Three Black Crows
|
||||
'CDL3INSIDE', # Three Inside Up/Down
|
||||
'CDL3LINESTRIKE', # Three-Line Strike
|
||||
'CDL3OUTSIDE', # Three Outside Up/Down
|
||||
'CDL3STARSINSOUTH', # Three Stars In The South
|
||||
'CDL3WHITESOLDIERS', # Three Advancing White Soldiers
|
||||
'CDLABANDONEDBABY', # Abandoned Baby
|
||||
'CDLADVANCEBLOCK', # Advance Block
|
||||
'CDLBELTHOLD', # Belt-hold
|
||||
'CDLBREAKAWAY', # Breakaway
|
||||
'CDLCLOSINGMARUBOZU', # Closing Marubozu
|
||||
'CDLCONCEALBABYSWALL', # Concealing Baby Swallow
|
||||
'CDLCOUNTERATTACK', # Counterattack
|
||||
'CDLDARKCLOUDCOVER', # Dark Cloud Cover
|
||||
'CDLDOJI', # Doji
|
||||
'CDLDOJISTAR', # Doji Star
|
||||
'CDLDRAGONFLYDOJI', # Dragonfly Doji
|
||||
'CDLENGULFING', # Engulfing Pattern
|
||||
'CDLEVENINGDOJISTAR', # Evening Doji Star
|
||||
'CDLEVENINGSTAR', # Evening Star
|
||||
'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines
|
||||
'CDLGRAVESTONEDOJI', # Gravestone Doji
|
||||
'CDLHAMMER', # Hammer
|
||||
'CDLHANGINGMAN', # Hanging Man
|
||||
'CDLHARAMI', # Harami Pattern
|
||||
'CDLHARAMICROSS', # Harami Cross Pattern
|
||||
'CDLHIGHWAVE', # High-Wave Candle
|
||||
'CDLHIKKAKE', # Hikkake Pattern
|
||||
'CDLHIKKAKEMOD', # Modified Hikkake Pattern
|
||||
'CDLHOMINGPIGEON', # Homing Pigeon
|
||||
'CDLIDENTICAL3CROWS', # Identical Three Crows
|
||||
'CDLINNECK', # In-Neck Pattern
|
||||
'CDLINVERTEDHAMMER', # Inverted Hammer
|
||||
'CDLKICKING', # Kicking
|
||||
'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu
|
||||
'CDLLADDERBOTTOM', # Ladder Bottom
|
||||
'CDLLONGLEGGEDDOJI', # Long Legged Doji
|
||||
'CDLLONGLINE', # Long Line Candle
|
||||
'CDLMARUBOZU', # Marubozu
|
||||
'CDLMATCHINGLOW', # Matching Low
|
||||
'CDLMATHOLD', # Mat Hold
|
||||
'CDLMORNINGDOJISTAR', # Morning Doji Star
|
||||
'CDLMORNINGSTAR', # Morning Star
|
||||
'CDLONNECK', # On-Neck Pattern
|
||||
'CDLPIERCING', # Piercing Pattern
|
||||
'CDLRICKSHAWMAN', # Rickshaw Man
|
||||
'CDLRISEFALL3METHODS', # Rising/Falling Three Methods
|
||||
'CDLSEPARATINGLINES', # Separating Lines
|
||||
'CDLSHOOTINGSTAR', # Shooting Star
|
||||
'CDLSHORTLINE', # Short Line Candle
|
||||
'CDLSPINNINGTOP', # Spinning Top
|
||||
'CDLSTALLEDPATTERN', # Stalled Pattern
|
||||
'CDLSTICKSANDWICH', # Stick Sandwich
|
||||
# Takuri (Dragonfly Doji with very long lower shadow)
|
||||
'CDLTAKURI',
|
||||
'CDLTASUKIGAP', # Tasuki Gap
|
||||
'CDLTHRUSTING', # Thrusting Pattern
|
||||
'CDLTRISTAR', # Tristar Pattern
|
||||
'CDLUNIQUE3RIVER', # Unique 3 River
|
||||
'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows
|
||||
'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods
|
||||
|
||||
},
|
||||
'Statistic Functions': {
|
||||
'BETA', # Beta
|
||||
'CORREL', # Pearson's Correlation Coefficient (r)
|
||||
'LINEARREG', # Linear Regression
|
||||
'LINEARREG_ANGLE', # Linear Regression Angle
|
||||
'LINEARREG_INTERCEPT', # Linear Regression Intercept
|
||||
'LINEARREG_SLOPE', # Linear Regression Slope
|
||||
'STDDEV', # Standard Deviation
|
||||
'TSF', # Time Series Forecast
|
||||
'VAR', # Variance
|
||||
}
|
||||
|
||||
}
|
||||
god_genes = set()
|
||||
########################### SETTINGS ##############################
|
||||
|
||||
# god_genes = {'SMA'}
|
||||
god_genes |= all_god_genes['Overlap Studies']
|
||||
god_genes |= all_god_genes['Momentum Indicators']
|
||||
god_genes |= all_god_genes['Volume Indicators']
|
||||
god_genes |= all_god_genes['Volatility Indicators']
|
||||
god_genes |= all_god_genes['Price Transform']
|
||||
god_genes |= all_god_genes['Cycle Indicators']
|
||||
god_genes |= all_god_genes['Pattern Recognition']
|
||||
god_genes |= all_god_genes['Statistic Functions']
|
||||
|
||||
timeperiods = [5, 6, 12, 15, 50, 55, 100, 110]
|
||||
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 = 1
|
||||
########################### END SETTINGS ##########################
|
||||
# DATAFRAME = DataFrame()
|
||||
|
||||
god_genes = list(god_genes)
|
||||
# print('selected indicators for optimzatin: \n', god_genes)
|
||||
|
||||
god_genes_with_timeperiod = list()
|
||||
for god_gene in god_genes:
|
||||
for timeperiod in timeperiods:
|
||||
god_genes_with_timeperiod.append(f'{god_gene}-{timeperiod}')
|
||||
|
||||
# Let give somethings to CatagoricalParam to Play with them
|
||||
# When just one thing is inside catagorical lists
|
||||
# TODO: its Not True Way :)
|
||||
if len(god_genes) == 1:
|
||||
god_genes = god_genes*2
|
||||
if len(timeperiods) == 1:
|
||||
timeperiods = timeperiods*2
|
||||
if len(operators) == 1:
|
||||
operators = operators*2
|
||||
|
||||
|
||||
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):
|
||||
|
||||
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] > dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "=":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "<":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "C":
|
||||
condition = (
|
||||
(qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) |
|
||||
(qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator]))
|
||||
)
|
||||
elif operator == "CA":
|
||||
condition = (
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "CB":
|
||||
condition = (
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == ">R":
|
||||
condition = (
|
||||
dataframe[indicator] > real_num
|
||||
)
|
||||
elif operator == "=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], real_num)
|
||||
)
|
||||
elif operator == "<R":
|
||||
condition = (
|
||||
dataframe[indicator] < real_num
|
||||
)
|
||||
elif operator == "/>R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) > real_num
|
||||
)
|
||||
elif operator == "/=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator].div(
|
||||
dataframe[crossed_indicator]), real_num)
|
||||
)
|
||||
elif operator == "/<R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) < real_num
|
||||
)
|
||||
elif operator == "UT":
|
||||
condition = (
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "DT":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "OT":
|
||||
condition = (
|
||||
|
||||
np.isclose(dataframe[indicator], dataframe[indicator_trend_sma])
|
||||
)
|
||||
elif operator == "CUT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "CDT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "COT":
|
||||
condition = (
|
||||
(
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) |
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
) &
|
||||
(
|
||||
np.isclose(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return condition, dataframe
|
||||
|
||||
|
||||
class GodStraJD2(IStrategy):
|
||||
# #################### RESULTS PASTE PLACE ####################
|
||||
# ROI table:
|
||||
minimal_roi = {
|
||||
"0": 0.598,
|
||||
"644": 0.166,
|
||||
"3269": 0.115,
|
||||
"7289": 0
|
||||
}
|
||||
|
||||
# Stoploss:
|
||||
stoploss = -0.128
|
||||
# Buy hypers
|
||||
timeframe = '4h'
|
||||
|
||||
# Trailing stoploss
|
||||
trailing_stop = True
|
||||
trailing_stop_positive = 0.15
|
||||
trailing_stop_positive_offset = 0.20
|
||||
trailing_only_offset_is_reached = True
|
||||
|
||||
# #################### END OF RESULT PLACE ####################
|
||||
|
||||
# TODO: Its not dry code!
|
||||
# Buy Hyperoptable Parameters/Spaces.
|
||||
buy_crossed_indicator0 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="ADD-20", space='buy')
|
||||
buy_crossed_indicator1 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="ASIN-6", space='buy')
|
||||
buy_crossed_indicator2 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy')
|
||||
|
||||
buy_indicator0 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="SMA-100", space='buy')
|
||||
buy_indicator1 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="WILLR-50", space='buy')
|
||||
buy_indicator2 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy')
|
||||
|
||||
buy_operator0 = CategoricalParameter(operators, default="/<R", space='buy')
|
||||
buy_operator1 = CategoricalParameter(operators, default="<R", space='buy')
|
||||
buy_operator2 = CategoricalParameter(operators, default="CB", space='buy')
|
||||
|
||||
buy_real_num0 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.89009, space='buy')
|
||||
buy_real_num1 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.56953, space='buy')
|
||||
buy_real_num2 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.38365, space='buy')
|
||||
|
||||
# Sell Hyperoptable Parameters/Spaces.
|
||||
sell_crossed_indicator0 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLSHOOTINGSTAR-150", space='sell')
|
||||
sell_crossed_indicator1 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="MAMA-1-100", space='sell')
|
||||
sell_crossed_indicator2 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLMATHOLD-6", space='sell')
|
||||
|
||||
sell_indicator0 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLUPSIDEGAP2CROWS-5", space='sell')
|
||||
sell_indicator1 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLHARAMICROSS-150", space='sell')
|
||||
sell_indicator2 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDL2CROWS-5", space='sell')
|
||||
|
||||
sell_operator0 = CategoricalParameter(
|
||||
operators, default="<R", space='sell')
|
||||
sell_operator1 = CategoricalParameter(operators, default="D", space='sell')
|
||||
sell_operator2 = CategoricalParameter(
|
||||
operators, default="/>R", space='sell')
|
||||
|
||||
sell_real_num0 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.09731, space='sell')
|
||||
sell_real_num1 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.81657, space='sell')
|
||||
sell_real_num2 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.87267, space='sell')
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
'''
|
||||
It's good to calculate all indicators in all time periods here and so optimize the strategy.
|
||||
But this strategy can take much time to generate anything that may not use in his optimization.
|
||||
I just calculate the specific indicators in specific time period inside buy and sell strategy populator methods if needed.
|
||||
Also, this method (populate_indicators) just calculates default value of hyperoptable params
|
||||
so using this method have not big benefits instade of calculating useable things inside buy and sell trand populators
|
||||
'''
|
||||
# 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"]
|
||||
)
|
||||
|
||||
# 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"]
|
||||
)
|
||||
|
||||
# # EMA - Exponential Moving Average
|
||||
# dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
|
||||
# TODO: Its not dry code!
|
||||
buy_indicator = self.buy_indicator0.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator0.value
|
||||
buy_operator = self.buy_operator0.value
|
||||
buy_real_num = self.buy_real_num0.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
# backup
|
||||
buy_indicator = self.buy_indicator1.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator1.value
|
||||
buy_operator = self.buy_operator1.value
|
||||
buy_real_num = self.buy_real_num1.value
|
||||
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
buy_indicator = self.buy_indicator2.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator2.value
|
||||
buy_operator = self.buy_operator2.value
|
||||
buy_real_num = self.buy_real_num2.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['close'] < dataframe['bb_lowerband'])
|
||||
& (dataframe['bb_width'] >= 0.13)
|
||||
& (dataframe['volume'] > 0)
|
||||
) |
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
'buy']=1
|
||||
# print(len(dataframe.keys()))
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
# TODO: Its not dry code!
|
||||
sell_indicator = self.sell_indicator0.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator0.value
|
||||
sell_operator = self.sell_operator0.value
|
||||
sell_real_num = self.sell_real_num0.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
sell_indicator = self.sell_indicator1.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator1.value
|
||||
sell_operator = self.sell_operator1.value
|
||||
sell_real_num = self.sell_real_num1.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
sell_indicator = self.sell_indicator2.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator2.value
|
||||
sell_operator = self.sell_operator2.value
|
||||
sell_real_num = self.sell_real_num2.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
#dataframe.loc[(dataframe['close'] < dataframe['bb_lowerband']),'sell']=1
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
(
|
||||
reduce(lambda x, y: x & y, conditions)
|
||||
),
|
||||
'sell']=1
|
||||
return dataframe
|
||||
|
||||
|
||||
class StrategyHelperLocal:
|
||||
"""
|
||||
simple helper class to predefine a couple of patterns for our
|
||||
strategy
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def two_green_candles(dataframe):
|
||||
"""
|
||||
evaluates if we are having 7 green candles in a row
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'] < dataframe['close']) &
|
||||
(dataframe['open'].shift(1) < dataframe['close'].shift(1))
|
||||
# (dataframe['open'].shift(2) < dataframe['close'].shift(2))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def no_more_three_green_candles(dataframe):
|
||||
"""
|
||||
evaluates if we are having not more than 3 green candles in a row
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:return:
|
||||
"""
|
||||
return not (
|
||||
(dataframe['open'] < dataframe['close']) &
|
||||
(dataframe['open'].shift(1) < dataframe['close'].shift(1)) &
|
||||
(dataframe['open'].shift(2) < dataframe['close'].shift(2)) &
|
||||
(dataframe['open'].shift(3) < dataframe['close'].shift(3))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def seven_green_candles(dataframe):
|
||||
"""
|
||||
evaluates if we are having 7 green candles in a row
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'] < dataframe['close']) &
|
||||
(dataframe['open'].shift(1) < dataframe['close'].shift(1)) &
|
||||
(dataframe['open'].shift(2) < dataframe['close'].shift(2)) &
|
||||
(dataframe['open'].shift(3) < dataframe['close'].shift(3)) &
|
||||
(dataframe['open'].shift(4) < dataframe['close'].shift(4)) &
|
||||
(dataframe['open'].shift(5) < dataframe['close'].shift(5)) &
|
||||
(dataframe['open'].shift(6) < dataframe['close'].shift(6)) &
|
||||
(dataframe['open'].shift(7) < dataframe['close'].shift(7))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def eight_green_candles(dataframe):
|
||||
"""
|
||||
evaluates if we are having 8 green candles in a row
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'] < dataframe['close']) &
|
||||
(dataframe['open'].shift(1) < dataframe['close'].shift(1)) &
|
||||
(dataframe['open'].shift(2) < dataframe['close'].shift(2)) &
|
||||
(dataframe['open'].shift(3) < dataframe['close'].shift(3)) &
|
||||
(dataframe['open'].shift(4) < dataframe['close'].shift(4)) &
|
||||
(dataframe['open'].shift(5) < dataframe['close'].shift(5)) &
|
||||
(dataframe['open'].shift(6) < dataframe['close'].shift(6)) &
|
||||
(dataframe['open'].shift(7) < dataframe['close'].shift(7)) &
|
||||
(dataframe['open'].shift(8) < dataframe['close'].shift(8))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def two_red_candles(dataframe, shift=0):
|
||||
"""
|
||||
evaluates if we are having 8 red candles in a row
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:param shift: shift the pattern by n
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) &
|
||||
(dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift))
|
||||
# (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) &
|
||||
# (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) &
|
||||
# (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) &
|
||||
# (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) &
|
||||
# (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def four_red_candles(dataframe, shift=0):
|
||||
"""
|
||||
evaluates if we are having 8 red candles in a row
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:param shift: shift the pattern by n
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) &
|
||||
(dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) &
|
||||
(dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) &
|
||||
(dataframe['open'].shift(3 + shift) > dataframe['close'].shift(3 + shift)) &
|
||||
(dataframe['open'].shift(4 + shift) > dataframe['close'].shift(4 + shift))
|
||||
# (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) &
|
||||
# (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) &
|
||||
# (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) &
|
||||
# (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def two_green_one_red_candle(dataframe):
|
||||
"""
|
||||
evaluates if we are having a red candle and 4 previous green
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'] < dataframe['close']) &
|
||||
(dataframe['open'].shift(1) < dataframe['close'].shift(1)) &
|
||||
(dataframe['open'].shift(2) > dataframe['close'].shift(2))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def four_green_one_red_candle(dataframe):
|
||||
"""
|
||||
evaluates if we are having a red candle and 4 previous green
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'] > dataframe['close']) &
|
||||
(dataframe['open'].shift(1) < dataframe['close'].shift(1)) &
|
||||
(dataframe['open'].shift(2) < dataframe['close'].shift(2)) &
|
||||
(dataframe['open'].shift(3) < dataframe['close'].shift(3)) &
|
||||
(dataframe['open'].shift(4) < dataframe['close'].shift(4))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def four_red_one_green_candle(dataframe):
|
||||
"""
|
||||
evaluates if we are having a green candle and 4 previous red
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'] < dataframe['close']) &
|
||||
(dataframe['open'].shift(1) > dataframe['close'].shift(1)) &
|
||||
(dataframe['open'].shift(2) > dataframe['close'].shift(2)) &
|
||||
(dataframe['open'].shift(3) > dataframe['close'].shift(3)) &
|
||||
(dataframe['open'].shift(4) > dataframe['close'].shift(4))
|
||||
)
|
||||
863
GodStraJD3.py
Normal file
863
GodStraJD3.py
Normal file
@@ -0,0 +1,863 @@
|
||||
# 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 freqtrade import data
|
||||
from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter
|
||||
|
||||
from numpy.lib import math
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
from pandas import DataFrame
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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
|
||||
# TODO: this gene is removed 'MAVP' cuz or error on periods
|
||||
all_god_genes = {
|
||||
'Overlap Studies': {
|
||||
'BBANDS-0', # Bollinger Bands
|
||||
'BBANDS-1', # Bollinger Bands
|
||||
'BBANDS-2', # Bollinger Bands
|
||||
'DEMA', # Double Exponential Moving Average
|
||||
'EMA', # Exponential Moving Average
|
||||
'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline
|
||||
'KAMA', # Kaufman Adaptive Moving Average
|
||||
'MA', # Moving average
|
||||
'MAMA-0', # MESA Adaptive Moving Average
|
||||
'MAMA-1', # MESA Adaptive Moving Average
|
||||
# TODO: Fix this
|
||||
# 'MAVP', # Moving average with variable period
|
||||
'MIDPOINT', # MidPoint over period
|
||||
'MIDPRICE', # Midpoint Price over period
|
||||
'SAR', # Parabolic SAR
|
||||
'SAREXT', # Parabolic SAR - Extended
|
||||
'SMA', # Simple Moving Average
|
||||
'T3', # Triple Exponential Moving Average (T3)
|
||||
'TEMA', # Triple Exponential Moving Average
|
||||
'TRIMA', # Triangular Moving Average
|
||||
'WMA', # Weighted Moving Average
|
||||
},
|
||||
'Momentum Indicators': {
|
||||
'ADX', # Average Directional Movement Index
|
||||
'ADXR', # Average Directional Movement Index Rating
|
||||
'APO', # Absolute Price Oscillator
|
||||
'AROON-0', # Aroon
|
||||
'AROON-1', # Aroon
|
||||
'AROONOSC', # Aroon Oscillator
|
||||
'BOP', # Balance Of Power
|
||||
'CCI', # Commodity Channel Index
|
||||
'CMO', # Chande Momentum Oscillator
|
||||
'DX', # Directional Movement Index
|
||||
'MACD-0', # Moving Average Convergence/Divergence
|
||||
'MACD-1', # Moving Average Convergence/Divergence
|
||||
'MACD-2', # Moving Average Convergence/Divergence
|
||||
'MACDEXT-0', # MACD with controllable MA type
|
||||
'MACDEXT-1', # MACD with controllable MA type
|
||||
'MACDEXT-2', # MACD with controllable MA type
|
||||
'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MFI', # Money Flow Index
|
||||
'MINUS_DI', # Minus Directional Indicator
|
||||
'MINUS_DM', # Minus Directional Movement
|
||||
'MOM', # Momentum
|
||||
'PLUS_DI', # Plus Directional Indicator
|
||||
'PLUS_DM', # Plus Directional Movement
|
||||
'PPO', # Percentage Price Oscillator
|
||||
'ROC', # Rate of change : ((price/prevPrice)-1)*100
|
||||
# Rate of change Percentage: (price-prevPrice)/prevPrice
|
||||
'ROCP',
|
||||
'ROCR', # Rate of change ratio: (price/prevPrice)
|
||||
# Rate of change ratio 100 scale: (price/prevPrice)*100
|
||||
'ROCR100',
|
||||
'RSI', # Relative Strength Index
|
||||
'STOCH-0', # Stochastic
|
||||
'STOCH-1', # Stochastic
|
||||
'STOCHF-0', # Stochastic Fast
|
||||
'STOCHF-1', # Stochastic Fast
|
||||
'STOCHRSI-0', # Stochastic Relative Strength Index
|
||||
'STOCHRSI-1', # Stochastic Relative Strength Index
|
||||
# 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA
|
||||
'TRIX',
|
||||
'ULTOSC', # Ultimate Oscillator
|
||||
'WILLR', # Williams' %R
|
||||
},
|
||||
'Volume Indicators': {
|
||||
'AD', # Chaikin A/D Line
|
||||
'ADOSC', # Chaikin A/D Oscillator
|
||||
'OBV', # On Balance Volume
|
||||
},
|
||||
'Volatility Indicators': {
|
||||
'ATR', # Average True Range
|
||||
'NATR', # Normalized Average True Range
|
||||
'TRANGE', # True Range
|
||||
},
|
||||
'Price Transform': {
|
||||
'AVGPRICE', # Average Price
|
||||
'MEDPRICE', # Median Price
|
||||
'TYPPRICE', # Typical Price
|
||||
'WCLPRICE', # Weighted Close Price
|
||||
},
|
||||
'Cycle Indicators': {
|
||||
'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period
|
||||
'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase
|
||||
'HT_PHASOR-0', # Hilbert Transform - Phasor Components
|
||||
'HT_PHASOR-1', # Hilbert Transform - Phasor Components
|
||||
'HT_SINE-0', # Hilbert Transform - SineWave
|
||||
'HT_SINE-1', # Hilbert Transform - SineWave
|
||||
'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode
|
||||
},
|
||||
'Pattern Recognition': {
|
||||
'CDL2CROWS', # Two Crows
|
||||
'CDL3BLACKCROWS', # Three Black Crows
|
||||
'CDL3INSIDE', # Three Inside Up/Down
|
||||
'CDL3LINESTRIKE', # Three-Line Strike
|
||||
'CDL3OUTSIDE', # Three Outside Up/Down
|
||||
'CDL3STARSINSOUTH', # Three Stars In The South
|
||||
'CDL3WHITESOLDIERS', # Three Advancing White Soldiers
|
||||
'CDLABANDONEDBABY', # Abandoned Baby
|
||||
'CDLADVANCEBLOCK', # Advance Block
|
||||
'CDLBELTHOLD', # Belt-hold
|
||||
'CDLBREAKAWAY', # Breakaway
|
||||
'CDLCLOSINGMARUBOZU', # Closing Marubozu
|
||||
'CDLCONCEALBABYSWALL', # Concealing Baby Swallow
|
||||
'CDLCOUNTERATTACK', # Counterattack
|
||||
'CDLDARKCLOUDCOVER', # Dark Cloud Cover
|
||||
'CDLDOJI', # Doji
|
||||
'CDLDOJISTAR', # Doji Star
|
||||
'CDLDRAGONFLYDOJI', # Dragonfly Doji
|
||||
'CDLENGULFING', # Engulfing Pattern
|
||||
'CDLEVENINGDOJISTAR', # Evening Doji Star
|
||||
'CDLEVENINGSTAR', # Evening Star
|
||||
'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines
|
||||
'CDLGRAVESTONEDOJI', # Gravestone Doji
|
||||
'CDLHAMMER', # Hammer
|
||||
'CDLHANGINGMAN', # Hanging Man
|
||||
'CDLHARAMI', # Harami Pattern
|
||||
'CDLHARAMICROSS', # Harami Cross Pattern
|
||||
'CDLHIGHWAVE', # High-Wave Candle
|
||||
'CDLHIKKAKE', # Hikkake Pattern
|
||||
'CDLHIKKAKEMOD', # Modified Hikkake Pattern
|
||||
'CDLHOMINGPIGEON', # Homing Pigeon
|
||||
'CDLIDENTICAL3CROWS', # Identical Three Crows
|
||||
'CDLINNECK', # In-Neck Pattern
|
||||
'CDLINVERTEDHAMMER', # Inverted Hammer
|
||||
'CDLKICKING', # Kicking
|
||||
'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu
|
||||
'CDLLADDERBOTTOM', # Ladder Bottom
|
||||
'CDLLONGLEGGEDDOJI', # Long Legged Doji
|
||||
'CDLLONGLINE', # Long Line Candle
|
||||
'CDLMARUBOZU', # Marubozu
|
||||
'CDLMATCHINGLOW', # Matching Low
|
||||
'CDLMATHOLD', # Mat Hold
|
||||
'CDLMORNINGDOJISTAR', # Morning Doji Star
|
||||
'CDLMORNINGSTAR', # Morning Star
|
||||
'CDLONNECK', # On-Neck Pattern
|
||||
'CDLPIERCING', # Piercing Pattern
|
||||
'CDLRICKSHAWMAN', # Rickshaw Man
|
||||
'CDLRISEFALL3METHODS', # Rising/Falling Three Methods
|
||||
'CDLSEPARATINGLINES', # Separating Lines
|
||||
'CDLSHOOTINGSTAR', # Shooting Star
|
||||
'CDLSHORTLINE', # Short Line Candle
|
||||
'CDLSPINNINGTOP', # Spinning Top
|
||||
'CDLSTALLEDPATTERN', # Stalled Pattern
|
||||
'CDLSTICKSANDWICH', # Stick Sandwich
|
||||
# Takuri (Dragonfly Doji with very long lower shadow)
|
||||
'CDLTAKURI',
|
||||
'CDLTASUKIGAP', # Tasuki Gap
|
||||
'CDLTHRUSTING', # Thrusting Pattern
|
||||
'CDLTRISTAR', # Tristar Pattern
|
||||
'CDLUNIQUE3RIVER', # Unique 3 River
|
||||
'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows
|
||||
'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods
|
||||
|
||||
},
|
||||
'Statistic Functions': {
|
||||
'BETA', # Beta
|
||||
'CORREL', # Pearson's Correlation Coefficient (r)
|
||||
'LINEARREG', # Linear Regression
|
||||
'LINEARREG_ANGLE', # Linear Regression Angle
|
||||
'LINEARREG_INTERCEPT', # Linear Regression Intercept
|
||||
'LINEARREG_SLOPE', # Linear Regression Slope
|
||||
'STDDEV', # Standard Deviation
|
||||
'TSF', # Time Series Forecast
|
||||
'VAR', # Variance
|
||||
}
|
||||
|
||||
}
|
||||
god_genes = set()
|
||||
########################### SETTINGS ##############################
|
||||
|
||||
# god_genes = {'SMA'}
|
||||
god_genes |= all_god_genes['Overlap Studies']
|
||||
god_genes |= all_god_genes['Momentum Indicators']
|
||||
god_genes |= all_god_genes['Volume Indicators']
|
||||
god_genes |= all_god_genes['Volatility Indicators']
|
||||
god_genes |= all_god_genes['Price Transform']
|
||||
god_genes |= all_god_genes['Cycle Indicators']
|
||||
god_genes |= all_god_genes['Pattern Recognition']
|
||||
god_genes |= all_god_genes['Statistic Functions']
|
||||
|
||||
timeperiods = [5, 6, 12, 15, 50, 55, 100, 110]
|
||||
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 = 1
|
||||
########################### END SETTINGS ##########################
|
||||
# DATAFRAME = DataFrame()
|
||||
|
||||
god_genes = list(god_genes)
|
||||
# print('selected indicators for optimzatin: \n', god_genes)
|
||||
|
||||
god_genes_with_timeperiod = list()
|
||||
for god_gene in god_genes:
|
||||
for timeperiod in timeperiods:
|
||||
god_genes_with_timeperiod.append(f'{god_gene}-{timeperiod}')
|
||||
|
||||
# Let give somethings to CatagoricalParam to Play with them
|
||||
# When just one thing is inside catagorical lists
|
||||
# TODO: its Not True Way :)
|
||||
if len(god_genes) == 1:
|
||||
god_genes = god_genes*2
|
||||
if len(timeperiods) == 1:
|
||||
timeperiods = timeperiods*2
|
||||
if len(operators) == 1:
|
||||
operators = operators*2
|
||||
|
||||
|
||||
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):
|
||||
|
||||
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] > dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "=":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "<":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "C":
|
||||
condition = (
|
||||
(qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) |
|
||||
(qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator]))
|
||||
)
|
||||
elif operator == "CA":
|
||||
condition = (
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "CB":
|
||||
condition = (
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == ">R":
|
||||
condition = (
|
||||
dataframe[indicator] > real_num
|
||||
)
|
||||
elif operator == "=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], real_num)
|
||||
)
|
||||
elif operator == "<R":
|
||||
condition = (
|
||||
dataframe[indicator] < real_num
|
||||
)
|
||||
elif operator == "/>R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) > real_num
|
||||
)
|
||||
elif operator == "/=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator].div(
|
||||
dataframe[crossed_indicator]), real_num)
|
||||
)
|
||||
elif operator == "/<R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) < real_num
|
||||
)
|
||||
elif operator == "UT":
|
||||
condition = (
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "DT":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "OT":
|
||||
condition = (
|
||||
|
||||
np.isclose(dataframe[indicator], dataframe[indicator_trend_sma])
|
||||
)
|
||||
elif operator == "CUT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "CDT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "COT":
|
||||
condition = (
|
||||
(
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) |
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
) &
|
||||
(
|
||||
np.isclose(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return condition, dataframe
|
||||
|
||||
|
||||
class GodStraJD3(IStrategy):
|
||||
# #################### RESULTS PASTE PLACE ####################
|
||||
# ROI table:
|
||||
minimal_roi = {
|
||||
"0": 0.598,
|
||||
"644": 0.166,
|
||||
"3269": 0.115,
|
||||
"7289": 0
|
||||
}
|
||||
|
||||
# Stoploss:
|
||||
stoploss = -0.128
|
||||
# Buy hypers
|
||||
timeframe = '4h'
|
||||
|
||||
# Trailing stoploss
|
||||
trailing_stop = True
|
||||
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': 'white'},
|
||||
'bb_upperband': {'color': 'white'},
|
||||
},
|
||||
'subplots': {
|
||||
# Subplots - each dict defines one additional plot
|
||||
"BB": {
|
||||
'bbwitth': {'color': 'blue'},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# #################### END OF RESULT PLACE ####################
|
||||
|
||||
# TODO: Its not dry code!
|
||||
# Buy Hyperoptable Parameters/Spaces.
|
||||
buy_crossed_indicator0 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="ADD-20", space='buy')
|
||||
buy_crossed_indicator1 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="ASIN-6", space='buy')
|
||||
buy_crossed_indicator2 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy')
|
||||
|
||||
buy_indicator0 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="SMA-100", space='buy')
|
||||
buy_indicator1 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="WILLR-50", space='buy')
|
||||
buy_indicator2 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy')
|
||||
|
||||
buy_operator0 = CategoricalParameter(operators, default="/<R", space='buy')
|
||||
buy_operator1 = CategoricalParameter(operators, default="<R", space='buy')
|
||||
buy_operator2 = CategoricalParameter(operators, default="CB", space='buy')
|
||||
|
||||
buy_real_num0 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.89009, space='buy')
|
||||
buy_real_num1 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.56953, space='buy')
|
||||
buy_real_num2 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.38365, space='buy')
|
||||
|
||||
# Sell Hyperoptable Parameters/Spaces.
|
||||
sell_crossed_indicator0 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLSHOOTINGSTAR-150", space='sell')
|
||||
sell_crossed_indicator1 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="MAMA-1-100", space='sell')
|
||||
sell_crossed_indicator2 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLMATHOLD-6", space='sell')
|
||||
|
||||
sell_indicator0 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLUPSIDEGAP2CROWS-5", space='sell')
|
||||
sell_indicator1 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDLHARAMICROSS-150", space='sell')
|
||||
sell_indicator2 = CategoricalParameter(
|
||||
god_genes_with_timeperiod, default="CDL2CROWS-5", space='sell')
|
||||
|
||||
sell_operator0 = CategoricalParameter(
|
||||
operators, default="<R", space='sell')
|
||||
sell_operator1 = CategoricalParameter(operators, default="D", space='sell')
|
||||
sell_operator2 = CategoricalParameter(
|
||||
operators, default="/>R", space='sell')
|
||||
|
||||
sell_real_num0 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.09731, space='sell')
|
||||
sell_real_num1 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.81657, space='sell')
|
||||
sell_real_num2 = DecimalParameter(
|
||||
0, 1, decimals=DECIMALS, default=0.87267, space='sell')
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
'''
|
||||
It's good to calculate all indicators in all time periods here and so optimize the strategy.
|
||||
But this strategy can take much time to generate anything that may not use in his optimization.
|
||||
I just calculate the specific indicators in specific time period inside buy and sell strategy populator methods if needed.
|
||||
Also, this method (populate_indicators) just calculates default value of hyperoptable params
|
||||
so using this method have not big benefits instade of calculating useable things inside buy and sell trand populators
|
||||
'''
|
||||
# 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"]
|
||||
)
|
||||
|
||||
# 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"]
|
||||
)
|
||||
|
||||
# # EMA - Exponential Moving Average
|
||||
# dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
|
||||
# TODO: Its not dry code!
|
||||
buy_indicator = self.buy_indicator0.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator0.value
|
||||
buy_operator = self.buy_operator0.value
|
||||
buy_real_num = self.buy_real_num0.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
# backup
|
||||
buy_indicator = self.buy_indicator1.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator1.value
|
||||
buy_operator = self.buy_operator1.value
|
||||
buy_real_num = self.buy_real_num1.value
|
||||
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
buy_indicator = self.buy_indicator2.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator2.value
|
||||
buy_operator = self.buy_operator2.value
|
||||
buy_real_num = self.buy_real_num2.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['close'] < dataframe['bb_lowerband'])
|
||||
& (dataframe['bb_width'] >= 0.12)
|
||||
& (dataframe['volume'] > 0)
|
||||
) |
|
||||
reduce(lambda x, y: x & y, conditions),
|
||||
'buy']=1
|
||||
# print(len(dataframe.keys()))
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
# TODO: Its not dry code!
|
||||
sell_indicator = self.sell_indicator0.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator0.value
|
||||
sell_operator = self.sell_operator0.value
|
||||
sell_real_num = self.sell_real_num0.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
sell_indicator = self.sell_indicator1.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator1.value
|
||||
sell_operator = self.sell_operator1.value
|
||||
sell_real_num = self.sell_real_num1.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
sell_indicator = self.sell_indicator2.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator2.value
|
||||
sell_operator = self.sell_operator2.value
|
||||
sell_real_num = self.sell_real_num2.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
#dataframe.loc[(dataframe['close'] < dataframe['bb_lowerband']),'sell']=1
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
(
|
||||
reduce(lambda x, y: x & y, conditions)
|
||||
),
|
||||
'sell']=1
|
||||
return dataframe
|
||||
|
||||
|
||||
class StrategyHelperLocal:
|
||||
"""
|
||||
simple helper class to predefine a couple of patterns for our
|
||||
strategy
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def two_green_candles(dataframe):
|
||||
"""
|
||||
evaluates if we are having 7 green candles in a row
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'] < dataframe['close']) &
|
||||
(dataframe['open'].shift(1) < dataframe['close'].shift(1))
|
||||
# (dataframe['open'].shift(2) < dataframe['close'].shift(2))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def no_more_three_green_candles(dataframe):
|
||||
"""
|
||||
evaluates if we are having not more than 3 green candles in a row
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:return:
|
||||
"""
|
||||
return not (
|
||||
(dataframe['open'] < dataframe['close']) &
|
||||
(dataframe['open'].shift(1) < dataframe['close'].shift(1)) &
|
||||
(dataframe['open'].shift(2) < dataframe['close'].shift(2)) &
|
||||
(dataframe['open'].shift(3) < dataframe['close'].shift(3))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def seven_green_candles(dataframe):
|
||||
"""
|
||||
evaluates if we are having 7 green candles in a row
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'] < dataframe['close']) &
|
||||
(dataframe['open'].shift(1) < dataframe['close'].shift(1)) &
|
||||
(dataframe['open'].shift(2) < dataframe['close'].shift(2)) &
|
||||
(dataframe['open'].shift(3) < dataframe['close'].shift(3)) &
|
||||
(dataframe['open'].shift(4) < dataframe['close'].shift(4)) &
|
||||
(dataframe['open'].shift(5) < dataframe['close'].shift(5)) &
|
||||
(dataframe['open'].shift(6) < dataframe['close'].shift(6)) &
|
||||
(dataframe['open'].shift(7) < dataframe['close'].shift(7))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def eight_green_candles(dataframe):
|
||||
"""
|
||||
evaluates if we are having 8 green candles in a row
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'] < dataframe['close']) &
|
||||
(dataframe['open'].shift(1) < dataframe['close'].shift(1)) &
|
||||
(dataframe['open'].shift(2) < dataframe['close'].shift(2)) &
|
||||
(dataframe['open'].shift(3) < dataframe['close'].shift(3)) &
|
||||
(dataframe['open'].shift(4) < dataframe['close'].shift(4)) &
|
||||
(dataframe['open'].shift(5) < dataframe['close'].shift(5)) &
|
||||
(dataframe['open'].shift(6) < dataframe['close'].shift(6)) &
|
||||
(dataframe['open'].shift(7) < dataframe['close'].shift(7)) &
|
||||
(dataframe['open'].shift(8) < dataframe['close'].shift(8))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def two_red_candles(dataframe, shift=0):
|
||||
"""
|
||||
evaluates if we are having 8 red candles in a row
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:param shift: shift the pattern by n
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) &
|
||||
(dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift))
|
||||
# (dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) &
|
||||
# (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) &
|
||||
# (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) &
|
||||
# (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) &
|
||||
# (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def four_red_candles(dataframe, shift=0):
|
||||
"""
|
||||
evaluates if we are having 8 red candles in a row
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:param shift: shift the pattern by n
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'].shift(shift) > dataframe['close'].shift(shift)) &
|
||||
(dataframe['open'].shift(1 + shift) > dataframe['close'].shift(1 + shift)) &
|
||||
(dataframe['open'].shift(2 + shift) > dataframe['close'].shift(2 + shift)) &
|
||||
(dataframe['open'].shift(3 + shift) > dataframe['close'].shift(3 + shift)) &
|
||||
(dataframe['open'].shift(4 + shift) > dataframe['close'].shift(4 + shift))
|
||||
# (dataframe['open'].shift(5 + shift) > dataframe['close'].shift(5 + shift)) &
|
||||
# (dataframe['open'].shift(6 + shift) > dataframe['close'].shift(6 + shift)) &
|
||||
# (dataframe['open'].shift(7 + shift) > dataframe['close'].shift(7 + shift)) &
|
||||
# (dataframe['open'].shift(8 + shift) > dataframe['close'].shift(8 + shift))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def two_green_one_red_candle(dataframe):
|
||||
"""
|
||||
evaluates if we are having a red candle and 4 previous green
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'] < dataframe['close']) &
|
||||
(dataframe['open'].shift(1) < dataframe['close'].shift(1)) &
|
||||
(dataframe['open'].shift(2) > dataframe['close'].shift(2))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def four_green_one_red_candle(dataframe):
|
||||
"""
|
||||
evaluates if we are having a red candle and 4 previous green
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'] > dataframe['close']) &
|
||||
(dataframe['open'].shift(1) < dataframe['close'].shift(1)) &
|
||||
(dataframe['open'].shift(2) < dataframe['close'].shift(2)) &
|
||||
(dataframe['open'].shift(3) < dataframe['close'].shift(3)) &
|
||||
(dataframe['open'].shift(4) < dataframe['close'].shift(4))
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def four_red_one_green_candle(dataframe):
|
||||
"""
|
||||
evaluates if we are having a green candle and 4 previous red
|
||||
:param self:
|
||||
:param dataframe:
|
||||
:return:
|
||||
"""
|
||||
return (
|
||||
(dataframe['open'] < dataframe['close']) &
|
||||
(dataframe['open'].shift(1) > dataframe['close'].shift(1)) &
|
||||
(dataframe['open'].shift(2) > dataframe['close'].shift(2)) &
|
||||
(dataframe['open'].shift(3) > dataframe['close'].shift(3)) &
|
||||
(dataframe['open'].shift(4) > dataframe['close'].shift(4))
|
||||
)
|
||||
51
GodStraJD3_1.json
Normal file
51
GodStraJD3_1.json
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_1",
|
||||
"params": {
|
||||
"trailing": {
|
||||
"trailing_stop": true,
|
||||
"trailing_stop_positive": 0.15,
|
||||
"trailing_stop_positive_offset": 0.2,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_crossed_indicator0": "CDLINNECK-6",
|
||||
"buy_crossed_indicator1": "DEMA-12",
|
||||
"buy_crossed_indicator2": "CDLHAMMER-12",
|
||||
"buy_indicator0": "CDLXSIDEGAP3METHODS-55",
|
||||
"buy_indicator1": "HT_DCPERIOD-55",
|
||||
"buy_indicator2": "LINEARREG_INTERCEPT-6",
|
||||
"buy_operator0": "=R",
|
||||
"buy_operator1": ">R",
|
||||
"buy_operator2": ">R",
|
||||
"buy_real_num0": 0.0,
|
||||
"buy_real_num1": 0.1,
|
||||
"buy_real_num2": 0.3
|
||||
},
|
||||
"sell": {
|
||||
"sell_crossed_indicator0": "AVGPRICE-100",
|
||||
"sell_crossed_indicator1": "CDLGAPSIDESIDEWHITE-6",
|
||||
"sell_crossed_indicator2": "PLUS_DI-15",
|
||||
"sell_indicator0": "BBANDS-2-50",
|
||||
"sell_indicator1": "PLUS_DM-6",
|
||||
"sell_indicator2": "MIDPOINT-100",
|
||||
"sell_operator0": "/=R",
|
||||
"sell_operator1": "CUT",
|
||||
"sell_operator2": "CUT",
|
||||
"sell_real_num0": 0.1,
|
||||
"sell_real_num1": 0.2,
|
||||
"sell_real_num2": 1.0
|
||||
},
|
||||
"protection": {},
|
||||
"roi": {
|
||||
"0": 0.594,
|
||||
"1344": 0.201,
|
||||
"3068": 0.081,
|
||||
"5986": 0
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -0.116
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-01-03 05:11:14.667810+00:00"
|
||||
}
|
||||
1033
GodStraJD3_1.py
Normal file
1033
GodStraJD3_1.py
Normal file
File diff suppressed because it is too large
Load Diff
84
GodStraJD3_2.json
Normal file
84
GodStraJD3_2.json
Normal file
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_2",
|
||||
"params": {
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.15,
|
||||
"trailing_stop_positive_offset": 0.2,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_indicator0": "CDLSHOOTINGSTAR-110",
|
||||
"buy_crossed_indicator0": "CDLTASUKIGAP-5",
|
||||
"buy_operator0": ">",
|
||||
"buy_real_num0": 1.0,
|
||||
"buy_indicator1": "MACDFIX-2-12",
|
||||
"buy_crossed_indicator1": "CDLSPINNINGTOP-6",
|
||||
"buy_operator1": "<",
|
||||
"buy_real_num1": 0.2,
|
||||
"buy_indicator2": "DEMA-110",
|
||||
"buy_crossed_indicator2": "CDL3WHITESOLDIERS-110",
|
||||
"buy_operator2": "/<R",
|
||||
"buy_real_num2": 0.7
|
||||
},
|
||||
"sell": {
|
||||
"sell_crossed_indicator0": "HT_DCPERIOD-5",
|
||||
"sell_crossed_indicator1": "HT_PHASOR-1-6",
|
||||
"sell_crossed_indicator2": "VAR-50",
|
||||
"sell_indicator0": "CDL3LINESTRIKE-15",
|
||||
"sell_indicator1": "CDLGAPSIDESIDEWHITE-110",
|
||||
"sell_indicator2": "CDLHIGHWAVE-12",
|
||||
"sell_operator0": "=",
|
||||
"sell_operator1": "DT",
|
||||
"sell_operator2": "/>R",
|
||||
"sell_real_num0": 0.9,
|
||||
"sell_real_num1": 0.6,
|
||||
"sell_real_num2": 0.3
|
||||
},
|
||||
"protections": [
|
||||
{
|
||||
"method": "CooldownPeriod",
|
||||
"stop_duration_candles": 5
|
||||
},
|
||||
{
|
||||
"method": "MaxDrawdown",
|
||||
"lookback_period_candles": 48,
|
||||
"trade_limit": 2,
|
||||
"stop_duration_candles": 100,
|
||||
"max_allowed_drawdown": 0.1
|
||||
},
|
||||
{
|
||||
"method": "StoplossGuard",
|
||||
"lookback_period_candles": 24,
|
||||
"trade_limit": 4,
|
||||
"stop_duration_candles": 2,
|
||||
"only_per_pair": false
|
||||
},
|
||||
{
|
||||
"method": "LowProfitPairs",
|
||||
"lookback_period_candles": 6,
|
||||
"trade_limit": 2,
|
||||
"stop_duration_candles": 60,
|
||||
"required_profit": 0.02
|
||||
},
|
||||
{
|
||||
"method": "LowProfitPairs",
|
||||
"lookback_period_candles": 24,
|
||||
"trade_limit": 4,
|
||||
"stop_duration_candles": 2,
|
||||
"required_profit": 0.01
|
||||
}
|
||||
],
|
||||
"roi": {
|
||||
"0": 0.893,
|
||||
"1606": 0.31,
|
||||
"4383": 0.122,
|
||||
"10010": 0
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-01-02 04:52:51.009356+00:00"
|
||||
}
|
||||
84
GodStraJD3_2.jsonOLD
Normal file
84
GodStraJD3_2.jsonOLD
Normal file
@@ -0,0 +1,84 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_2",
|
||||
"params": {
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.15,
|
||||
"trailing_stop_positive_offset": 0.2,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_indicator0": "CDLSHOOTINGSTAR-110",
|
||||
"buy_crossed_indicator0": "CDLTASUKIGAP-5",
|
||||
"buy_operator0": ">",
|
||||
"buy_real_num0": 1.0,
|
||||
"buy_indicator1": "MACDFIX-2-12",
|
||||
"buy_crossed_indicator1": "CDLSPINNINGTOP-6",
|
||||
"buy_operator1": "<",
|
||||
"buy_real_num1": 0.2,
|
||||
"buy_indicator2": "DEMA-110",
|
||||
"buy_crossed_indicator2": "CDL3WHITESOLDIERS-110",
|
||||
"buy_operator2": "/<R",
|
||||
"buy_real_num2": 0.7
|
||||
},
|
||||
"sell": {
|
||||
"sell_crossed_indicator0": "HT_DCPERIOD-5",
|
||||
"sell_crossed_indicator1": "HT_PHASOR-1-6",
|
||||
"sell_crossed_indicator2": "VAR-50",
|
||||
"sell_indicator0": "CDL3LINESTRIKE-15",
|
||||
"sell_indicator1": "CDLGAPSIDESIDEWHITE-110",
|
||||
"sell_indicator2": "CDLHIGHWAVE-12",
|
||||
"sell_operator0": "=",
|
||||
"sell_operator1": "DT",
|
||||
"sell_operator2": "/>R",
|
||||
"sell_real_num0": 0.9,
|
||||
"sell_real_num1": 0.6,
|
||||
"sell_real_num2": 0.3
|
||||
},
|
||||
"protections": [
|
||||
{
|
||||
"method": "CooldownPeriod",
|
||||
"stop_duration_candles": 5
|
||||
},
|
||||
{
|
||||
"method": "MaxDrawdown",
|
||||
"lookback_period_candles": 48,
|
||||
"trade_limit": 2,
|
||||
"stop_duration_candles": 100,
|
||||
"max_allowed_drawdown": 0.1
|
||||
},
|
||||
{
|
||||
"method": "StoplossGuard",
|
||||
"lookback_period_candles": 24,
|
||||
"trade_limit": 4,
|
||||
"stop_duration_candles": 2,
|
||||
"only_per_pair": false
|
||||
},
|
||||
{
|
||||
"method": "LowProfitPairs",
|
||||
"lookback_period_candles": 6,
|
||||
"trade_limit": 2,
|
||||
"stop_duration_candles": 60,
|
||||
"required_profit": 0.02
|
||||
},
|
||||
{
|
||||
"method": "LowProfitPairs",
|
||||
"lookback_period_candles": 24,
|
||||
"trade_limit": 4,
|
||||
"stop_duration_candles": 2,
|
||||
"required_profit": 0.01
|
||||
}
|
||||
],
|
||||
"roi": {
|
||||
"0": 0.893,
|
||||
"1606": 0.31,
|
||||
"4383": 0.122,
|
||||
"10010": 0
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -2
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-01-02 04:52:51.009356+00:00"
|
||||
}
|
||||
1078
GodStraJD3_2.py
Normal file
1078
GodStraJD3_2.py
Normal file
File diff suppressed because it is too large
Load Diff
1111
GodStraJD3_3.py
Normal file
1111
GodStraJD3_3.py
Normal file
File diff suppressed because it is too large
Load Diff
41
GodStraJD3_4.json
Normal file
41
GodStraJD3_4.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_4",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.145,
|
||||
"trailing_stop_positive_offset": 0.146,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_crossed_indicator0": "T3-10",
|
||||
"buy_crossed_indicator1": "HT_SINE-1-50",
|
||||
"buy_crossed_indicator2": "PLUS_DI-20",
|
||||
"buy_indicator0": "TEMA-50",
|
||||
"buy_indicator1": "ADXR-50",
|
||||
"buy_indicator2": "CDLSEPARATINGLINES-50",
|
||||
"buy_operator0": "/<R",
|
||||
"buy_operator1": "D",
|
||||
"buy_operator2": "CA",
|
||||
"buy_real_num0": 0.68,
|
||||
"buy_real_num1": 0.38,
|
||||
"buy_real_num2": 1.0
|
||||
},
|
||||
"sell": {},
|
||||
"protection": {
|
||||
"lookback": 151,
|
||||
"protection_max_allowed_dd": 0.94,
|
||||
"protection_stop": 58,
|
||||
"protection_stoploss_stop": 10,
|
||||
"trade_limit": 1
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-03-24 06:01:13.737412+00:00"
|
||||
}
|
||||
48
GodStraJD3_4.jsonBest
Normal file
48
GodStraJD3_4.jsonBest
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_4",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 1
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -2.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.15,
|
||||
"trailing_stop_positive_offset": 0.2,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_crossed_indicator0": "MINUS_DM-5",
|
||||
"buy_crossed_indicator1": "DX-5",
|
||||
"buy_crossed_indicator2": "LINEARREG-50",
|
||||
"buy_indicator0": "MA-20",
|
||||
"buy_indicator1": "STOCH-1-10",
|
||||
"buy_indicator2": "CDLDRAGONFLYDOJI-5",
|
||||
"buy_operator0": "/<R",
|
||||
"buy_operator1": ">",
|
||||
"buy_operator2": "/<R",
|
||||
"buy_real_num0": 0.1,
|
||||
"buy_real_num1": 0.0,
|
||||
"buy_real_num2": 0.5
|
||||
},
|
||||
"sell": {
|
||||
"sell_crossed_indicator0": "TRANGE-12",
|
||||
"sell_crossed_indicator1": "CDLEVENINGDOJISTAR-55",
|
||||
"sell_crossed_indicator2": "HT_PHASOR-0-15",
|
||||
"sell_indicator0": "HT_PHASOR-0-15",
|
||||
"sell_indicator1": "AROON-1-110",
|
||||
"sell_indicator2": "ADX-6",
|
||||
"sell_operator0": "<R",
|
||||
"sell_operator1": "/=R",
|
||||
"sell_operator2": "/=R",
|
||||
"sell_real_num0": 0.8,
|
||||
"sell_real_num1": 0.4,
|
||||
"sell_real_num2": 0.4
|
||||
},
|
||||
"protection": {}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-01-11 21:45:43.286063+00:00"
|
||||
}
|
||||
48
GodStraJD3_4.jsonOld
Normal file
48
GodStraJD3_4.jsonOld
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_4",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 1
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -2.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.15,
|
||||
"trailing_stop_positive_offset": 0.2,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_crossed_indicator0": "MIDPOINT-6",
|
||||
"buy_crossed_indicator1": "ROCR-5",
|
||||
"buy_crossed_indicator2": "CDLHARAMI-100",
|
||||
"buy_indicator0": "WCLPRICE-6",
|
||||
"buy_indicator1": "AVGPRICE-100",
|
||||
"buy_indicator2": "CDL3OUTSIDE-15",
|
||||
"buy_operator0": ">R",
|
||||
"buy_operator1": "<",
|
||||
"buy_operator2": "CA",
|
||||
"buy_real_num0": 0.0,
|
||||
"buy_real_num1": 0.8,
|
||||
"buy_real_num2": 0.5
|
||||
},
|
||||
"sell": {
|
||||
"sell_crossed_indicator0": "TRANGE-12",
|
||||
"sell_crossed_indicator1": "CDLEVENINGDOJISTAR-55",
|
||||
"sell_crossed_indicator2": "HT_PHASOR-0-15",
|
||||
"sell_indicator0": "HT_PHASOR-0-15",
|
||||
"sell_indicator1": "AROON-1-110",
|
||||
"sell_indicator2": "ADX-6",
|
||||
"sell_operator0": "<R",
|
||||
"sell_operator1": "/=R",
|
||||
"sell_operator2": "/=R",
|
||||
"sell_real_num0": 0.8,
|
||||
"sell_real_num1": 0.4,
|
||||
"sell_real_num2": 0.4
|
||||
},
|
||||
"protection": {}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-01-10 03:09:19.259745+00:00"
|
||||
}
|
||||
985
GodStraJD3_4.py
Normal file
985
GodStraJD3_4.py
Normal file
@@ -0,0 +1,985 @@
|
||||
# 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 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
|
||||
from pandas import DataFrame
|
||||
import time
|
||||
import calendar
|
||||
from freqtrade.loggers import setup_logging
|
||||
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
|
||||
# TODO: this gene is removed 'MAVP' cuz or error on periods
|
||||
all_god_genes = {
|
||||
'Overlap Studies': {
|
||||
'BBANDS-0', # Bollinger Bands
|
||||
'BBANDS-1', # Bollinger Bands
|
||||
'BBANDS-2', # Bollinger Bands
|
||||
'DEMA', # Double Exponential Moving Average
|
||||
'EMA', # Exponential Moving Average
|
||||
'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline
|
||||
'KAMA', # Kaufman Adaptive Moving Average
|
||||
'MA', # Moving average
|
||||
'MAMA-0', # MESA Adaptive Moving Average
|
||||
'MAMA-1', # MESA Adaptive Moving Average
|
||||
# TODO: Fix this
|
||||
# 'MAVP', # Moving average with variable period
|
||||
'MIDPOINT', # MidPoint over period
|
||||
'MIDPRICE', # Midpoint Price over period
|
||||
'SAR', # Parabolic SAR
|
||||
'SAREXT', # Parabolic SAR - Extended
|
||||
'SMA', # Simple Moving Average
|
||||
'T3', # Triple Exponential Moving Average (T3)
|
||||
'TEMA', # Triple Exponential Moving Average
|
||||
'TRIMA', # Triangular Moving Average
|
||||
'WMA', # Weighted Moving Average
|
||||
},
|
||||
'Momentum Indicators': {
|
||||
'ADX', # Average Directional Movement Index
|
||||
'ADXR', # Average Directional Movement Index Rating
|
||||
'APO', # Absolute Price Oscillator
|
||||
'AROON-0', # Aroon
|
||||
'AROON-1', # Aroon
|
||||
'AROONOSC', # Aroon Oscillator
|
||||
'BOP', # Balance Of Power
|
||||
'CCI', # Commodity Channel Index
|
||||
'CMO', # Chande Momentum Oscillator
|
||||
'DX', # Directional Movement Index
|
||||
'MACD-0', # Moving Average Convergence/Divergence
|
||||
'MACD-1', # Moving Average Convergence/Divergence
|
||||
'MACD-2', # Moving Average Convergence/Divergence
|
||||
'MACDEXT-0', # MACD with controllable MA type
|
||||
'MACDEXT-1', # MACD with controllable MA type
|
||||
'MACDEXT-2', # MACD with controllable MA type
|
||||
'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MFI', # Money Flow Index
|
||||
'MINUS_DI', # Minus Directional Indicator
|
||||
'MINUS_DM', # Minus Directional Movement
|
||||
'MOM', # Momentum
|
||||
'PLUS_DI', # Plus Directional Indicator
|
||||
'PLUS_DM', # Plus Directional Movement
|
||||
'PPO', # Percentage Price Oscillator
|
||||
'ROC', # Rate of change : ((price/prevPrice)-1)*100
|
||||
# Rate of change Percentage: (price-prevPrice)/prevPrice
|
||||
'ROCP',
|
||||
'ROCR', # Rate of change ratio: (price/prevPrice)
|
||||
# Rate of change ratio 100 scale: (price/prevPrice)*100
|
||||
'ROCR100',
|
||||
'RSI', # Relative Strength Index
|
||||
'STOCH-0', # Stochastic
|
||||
'STOCH-1', # Stochastic
|
||||
'STOCHF-0', # Stochastic Fast
|
||||
'STOCHF-1', # Stochastic Fast
|
||||
'STOCHRSI-0', # Stochastic Relative Strength Index
|
||||
'STOCHRSI-1', # Stochastic Relative Strength Index
|
||||
# 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA
|
||||
'TRIX',
|
||||
'ULTOSC', # Ultimate Oscillator
|
||||
'WILLR', # Williams' %R
|
||||
},
|
||||
'Volume Indicators': {
|
||||
'AD', # Chaikin A/D Line
|
||||
'ADOSC', # Chaikin A/D Oscillator
|
||||
'OBV', # On Balance Volume
|
||||
},
|
||||
'Volatility Indicators': {
|
||||
'ATR', # Average True Range
|
||||
'NATR', # Normalized Average True Range
|
||||
'TRANGE', # True Range
|
||||
},
|
||||
'Price Transform': {
|
||||
'AVGPRICE', # Average Price
|
||||
'MEDPRICE', # Median Price
|
||||
'TYPPRICE', # Typical Price
|
||||
'WCLPRICE', # Weighted Close Price
|
||||
},
|
||||
'Cycle Indicators': {
|
||||
'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period
|
||||
'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase
|
||||
'HT_PHASOR-0', # Hilbert Transform - Phasor Components
|
||||
'HT_PHASOR-1', # Hilbert Transform - Phasor Components
|
||||
'HT_SINE-0', # Hilbert Transform - SineWave
|
||||
'HT_SINE-1', # Hilbert Transform - SineWave
|
||||
'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode
|
||||
},
|
||||
'Pattern Recognition': {
|
||||
'CDL2CROWS', # Two Crows
|
||||
'CDL3BLACKCROWS', # Three Black Crows
|
||||
'CDL3INSIDE', # Three Inside Up/Down
|
||||
'CDL3LINESTRIKE', # Three-Line Strike
|
||||
'CDL3OUTSIDE', # Three Outside Up/Down
|
||||
'CDL3STARSINSOUTH', # Three Stars In The South
|
||||
'CDL3WHITESOLDIERS', # Three Advancing White Soldiers
|
||||
'CDLABANDONEDBABY', # Abandoned Baby
|
||||
'CDLADVANCEBLOCK', # Advance Block
|
||||
'CDLBELTHOLD', # Belt-hold
|
||||
'CDLBREAKAWAY', # Breakaway
|
||||
'CDLCLOSINGMARUBOZU', # Closing Marubozu
|
||||
'CDLCONCEALBABYSWALL', # Concealing Baby Swallow
|
||||
'CDLCOUNTERATTACK', # Counterattack
|
||||
'CDLDARKCLOUDCOVER', # Dark Cloud Cover
|
||||
'CDLDOJI', # Doji
|
||||
'CDLDOJISTAR', # Doji Star
|
||||
'CDLDRAGONFLYDOJI', # Dragonfly Doji
|
||||
'CDLENGULFING', # Engulfing Pattern
|
||||
'CDLEVENINGDOJISTAR', # Evening Doji Star
|
||||
'CDLEVENINGSTAR', # Evening Star
|
||||
'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines
|
||||
'CDLGRAVESTONEDOJI', # Gravestone Doji
|
||||
'CDLHAMMER', # Hammer
|
||||
'CDLHANGINGMAN', # Hanging Man
|
||||
'CDLHARAMI', # Harami Pattern
|
||||
'CDLHARAMICROSS', # Harami Cross Pattern
|
||||
'CDLHIGHWAVE', # High-Wave Candle
|
||||
'CDLHIKKAKE', # Hikkake Pattern
|
||||
'CDLHIKKAKEMOD', # Modified Hikkake Pattern
|
||||
'CDLHOMINGPIGEON', # Homing Pigeon
|
||||
'CDLIDENTICAL3CROWS', # Identical Three Crows
|
||||
'CDLINNECK', # In-Neck Pattern
|
||||
'CDLINVERTEDHAMMER', # Inverted Hammer
|
||||
'CDLKICKING', # Kicking
|
||||
'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu
|
||||
'CDLLADDERBOTTOM', # Ladder Bottom
|
||||
'CDLLONGLEGGEDDOJI', # Long Legged Doji
|
||||
'CDLLONGLINE', # Long Line Candle
|
||||
'CDLMARUBOZU', # Marubozu
|
||||
'CDLMATCHINGLOW', # Matching Low
|
||||
'CDLMATHOLD', # Mat Hold
|
||||
'CDLMORNINGDOJISTAR', # Morning Doji Star
|
||||
'CDLMORNINGSTAR', # Morning Star
|
||||
'CDLONNECK', # On-Neck Pattern
|
||||
'CDLPIERCING', # Piercing Pattern
|
||||
'CDLRICKSHAWMAN', # Rickshaw Man
|
||||
'CDLRISEFALL3METHODS', # Rising/Falling Three Methods
|
||||
'CDLSEPARATINGLINES', # Separating Lines
|
||||
'CDLSHOOTINGSTAR', # Shooting Star
|
||||
'CDLSHORTLINE', # Short Line Candle
|
||||
'CDLSPINNINGTOP', # Spinning Top
|
||||
'CDLSTALLEDPATTERN', # Stalled Pattern
|
||||
'CDLSTICKSANDWICH', # Stick Sandwich
|
||||
# Takuri (Dragonfly Doji with very long lower shadow)
|
||||
'CDLTAKURI',
|
||||
'CDLTASUKIGAP', # Tasuki Gap
|
||||
'CDLTHRUSTING', # Thrusting Pattern
|
||||
'CDLTRISTAR', # Tristar Pattern
|
||||
'CDLUNIQUE3RIVER', # Unique 3 River
|
||||
'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows
|
||||
'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods
|
||||
|
||||
},
|
||||
'Statistic Functions': {
|
||||
'BETA', # Beta
|
||||
'CORREL', # Pearson's Correlation Coefficient (r)
|
||||
'LINEARREG', # Linear Regression
|
||||
'LINEARREG_ANGLE', # Linear Regression Angle
|
||||
'LINEARREG_INTERCEPT', # Linear Regression Intercept
|
||||
'LINEARREG_SLOPE', # Linear Regression Slope
|
||||
'STDDEV', # Standard Deviation
|
||||
'TSF', # Time Series Forecast
|
||||
'VAR', # Variance
|
||||
}
|
||||
|
||||
}
|
||||
god_genes = set()
|
||||
########################### SETTINGS ##############################
|
||||
|
||||
# god_genes = {'SMA'}
|
||||
god_genes |= all_god_genes['Overlap Studies']
|
||||
god_genes |= all_god_genes['Momentum Indicators']
|
||||
god_genes |= all_god_genes['Volume Indicators']
|
||||
god_genes |= all_god_genes['Volatility Indicators']
|
||||
god_genes |= all_god_genes['Price Transform']
|
||||
god_genes |= all_god_genes['Cycle Indicators']
|
||||
god_genes |= all_god_genes['Pattern Recognition']
|
||||
god_genes |= all_god_genes['Statistic Functions']
|
||||
|
||||
#timeperiods = [5, 6, 12, 15, 50, 55, 100, 110]
|
||||
timeperiods = [5, 10, 20, 50, 100]
|
||||
|
||||
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
|
||||
########################### END SETTINGS ##########################
|
||||
# DATAFRAME = DataFrame()
|
||||
|
||||
god_genes = list(god_genes)
|
||||
# print('selected indicators for optimzatin: \n', god_genes)
|
||||
|
||||
god_genes_with_timeperiod = list()
|
||||
for god_gene in god_genes:
|
||||
for timeperiod in timeperiods:
|
||||
# print(f'{god_gene}-{timeperiod}')
|
||||
god_genes_with_timeperiod.append(f'{god_gene}-{timeperiod}')
|
||||
|
||||
# Let give somethings to CatagoricalParam to Play with them
|
||||
# When just one thing is inside catagorical lists
|
||||
# TODO: its Not True Way :)
|
||||
if len(god_genes) == 1:
|
||||
god_genes = god_genes*2
|
||||
if len(timeperiods) == 1:
|
||||
timeperiods = timeperiods*2
|
||||
if len(operators) == 1:
|
||||
operators = operators*2
|
||||
|
||||
|
||||
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):
|
||||
|
||||
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] > dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "=":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "<":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "C":
|
||||
condition = (
|
||||
(qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) |
|
||||
(qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator]))
|
||||
)
|
||||
elif operator == "CA":
|
||||
condition = (
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "CB":
|
||||
condition = (
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == ">R":
|
||||
condition = (
|
||||
dataframe[indicator] > real_num
|
||||
)
|
||||
elif operator == "=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], real_num)
|
||||
)
|
||||
elif operator == "<R":
|
||||
condition = (
|
||||
dataframe[indicator] < real_num
|
||||
)
|
||||
elif operator == "/>R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) > real_num
|
||||
)
|
||||
elif operator == "/=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator].div(
|
||||
dataframe[crossed_indicator]), real_num)
|
||||
)
|
||||
elif operator == "/<R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) < real_num
|
||||
)
|
||||
elif operator == "UT":
|
||||
condition = (
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "DT":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "OT":
|
||||
condition = (
|
||||
|
||||
np.isclose(dataframe[indicator], dataframe[indicator_trend_sma])
|
||||
)
|
||||
elif operator == "CUT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "CDT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "COT":
|
||||
condition = (
|
||||
(
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) |
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
) &
|
||||
(
|
||||
np.isclose(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return condition, dataframe
|
||||
|
||||
|
||||
class GodStraJD3_4(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'},
|
||||
# 'min': {'color': 'white'},
|
||||
# 'max': {'color': 'white'},
|
||||
'sma20': {'color': 'cyan'}
|
||||
},
|
||||
'subplots': {
|
||||
# Subplots - each dict defines one additional plot
|
||||
"BB": {
|
||||
'bb_width': {'color': 'white'},
|
||||
'bb_min': {'color': 'red'},
|
||||
},
|
||||
"Ind": {
|
||||
"PLUS_DM-20": {'color': 'green'},
|
||||
"CDLTAKURI-5": {'color': 'blue'}
|
||||
},
|
||||
# "Ind2": {
|
||||
# 'MINUS_DM-5': {'color': 'green'},
|
||||
# 'DX-5': {'color': 'blue'},
|
||||
# 'LINEARREG-50': {'color': 'red'}
|
||||
# },
|
||||
# "Profit": {
|
||||
# 'profit': {'color': 'pink'},
|
||||
# },
|
||||
"Rsi": {
|
||||
'rsi': {'color': 'pink'},
|
||||
},
|
||||
# "rolling": {
|
||||
# 'bb_rolling': {'color': '#87e470'},
|
||||
# "bb_rolling_min": {'color': '#ac3e2a'}
|
||||
# },
|
||||
"percent": {
|
||||
"percent": {'color': 'green'},
|
||||
"percent3": {'color': 'blue'},
|
||||
"percent5": {'color': 'red'}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# #################### 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
|
||||
|
||||
# TODO: Its not dry code!
|
||||
# Buy Hyperoptable Parameters/Spaces.
|
||||
buy_crossed_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="ADD-20", space='buy')
|
||||
buy_crossed_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="ASIN-6", space='buy')
|
||||
buy_crossed_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy')
|
||||
|
||||
buy_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="SMA-100", space='buy')
|
||||
buy_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="WILLR-50", space='buy')
|
||||
buy_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy')
|
||||
|
||||
buy_operator0 = CategoricalParameter(operators, default="/<R", space='buy')
|
||||
buy_operator1 = CategoricalParameter(operators, default="<R", space='buy')
|
||||
buy_operator2 = CategoricalParameter(operators, default="CB", space='buy')
|
||||
|
||||
buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.89009, space='buy')
|
||||
buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.56953, space='buy')
|
||||
buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.38365, space='buy')
|
||||
|
||||
# buy_shift_bb_lowerband = IntParameter(0, 10, default=2, space='buy')
|
||||
|
||||
# Sell Hyperoptable Parameters/Spaces.
|
||||
# sell_crossed_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="CDLSHOOTINGSTAR-150", space='sell')
|
||||
# sell_crossed_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="MAMA-1-100", space='sell')
|
||||
# sell_crossed_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLMATHOLD-6", space='sell')
|
||||
#
|
||||
# sell_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="CDLUPSIDEGAP2CROWS-5", space='sell')
|
||||
# sell_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="CDLHARAMICROSS-150", space='sell')
|
||||
# sell_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDL2CROWS-5", space='sell')
|
||||
#
|
||||
# sell_operator0 = CategoricalParameter(operators, default="<R", space='sell')
|
||||
# sell_operator1 = CategoricalParameter(operators, default="D", space='sell')
|
||||
# sell_operator2 = CategoricalParameter(operators, default="/>R", space='sell')
|
||||
#
|
||||
# sell_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.09731, space='sell')
|
||||
# sell_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.81657, space='sell')
|
||||
# sell_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.87267, space='sell')
|
||||
|
||||
protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection')
|
||||
protection_stop = IntParameter(0, 100, default=48, space='protection')
|
||||
protection_stoploss_stop = IntParameter(0, 100, default=48, space='protection')
|
||||
lookback = IntParameter(0, 200, default=48, space='protection')
|
||||
trade_limit = IntParameter(0, 10, default=2, space='protection')
|
||||
|
||||
# buy_cond1_num0 = DecimalParameter(0, 10, decimals=DECIMALS, default=1, space='buy')
|
||||
#buy_cond1_num1 = DecimalParameter(0, 10, decimals=DECIMALS, default=2, space='buy')
|
||||
# buy_bbwidth_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.035, space='buy')
|
||||
#buy_bbwidth_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.055, space='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
|
||||
},
|
||||
# {
|
||||
# "method": "StoplossGuard",
|
||||
# "lookback_period_candles": 24,
|
||||
# "trade_limit": 4,
|
||||
# "stop_duration_candles": 2,
|
||||
# "only_per_pair": False
|
||||
# },
|
||||
# {
|
||||
# "method": "LowProfitPairs",
|
||||
# "lookback_period_candles": 6,
|
||||
# "trade_limit": 2,
|
||||
# "stop_duration_candles": 60,
|
||||
# "required_profit": 0.02
|
||||
# },
|
||||
# {
|
||||
# "method": "LowProfitPairs",
|
||||
# "lookback_period_candles": 24,
|
||||
# "trade_limit": 4,
|
||||
# "stop_duration_candles": 2,
|
||||
# "required_profit": 0.01
|
||||
# }
|
||||
]
|
||||
|
||||
# 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()
|
||||
#
|
||||
# # print("proposed_stake=", proposed_stake, " max_stake=", max_stake)
|
||||
# if current_candle['bb_width'] > 0.065:
|
||||
# # print("use more stake", pair, " ", proposed_stake * 2)
|
||||
# return min(max_stake, proposed_stake * 2)
|
||||
#
|
||||
# if current_candle['bb_width'] > 0.045:
|
||||
# # 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 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.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 (current_profit > self.sell_percent.value) & (last_candle['percent3'] < - self.sell_percent3.value) \
|
||||
# & ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_candels.value):
|
||||
# return "quick_gain_param"
|
||||
|
||||
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, "4h") 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:
|
||||
# MACD
|
||||
# macd = ta.MACD(dataframe)
|
||||
# dataframe['macd'] = macd['macd']
|
||||
# dataframe['macdsignal'] = macd['macdsignal']
|
||||
# dataframe['macdhist'] = macd['macdhist']
|
||||
|
||||
# # # Plus Directional Indicator / Movement
|
||||
# dataframe['plus_dm'] = ta.PLUS_DM(dataframe)
|
||||
# dataframe['plus_di'] = ta.PLUS_DI(dataframe)
|
||||
#
|
||||
# # Minus Directional Indicator / Movement
|
||||
# dataframe['adx'] = ta.ADX(dataframe)
|
||||
dataframe[self.buy_indicator0.value] = gene_calculator(dataframe, self.buy_indicator0.value)
|
||||
dataframe[self.buy_crossed_indicator0.value] = gene_calculator(dataframe, self.buy_crossed_indicator0.value)
|
||||
dataframe[self.buy_indicator1.value] = gene_calculator(dataframe, self.buy_indicator1.value)
|
||||
dataframe[self.buy_crossed_indicator1.value] = gene_calculator(dataframe, self.buy_crossed_indicator1.value)
|
||||
# dataframe[self.buy_indicator2.value] = gene_calculator(dataframe, self.buy_indicator2.value)
|
||||
# dataframe[self.buy_crossed_indicator2.value] = gene_calculator(dataframe, self.buy_crossed_indicator2.value)
|
||||
|
||||
# dataframe['MINUS_DM-5'] = ta.MINUS_DM(dataframe, timeperiod=5)
|
||||
# dataframe['LINEARREG-50'] = ta.LINEARREG(dataframe, timeperiod=50)
|
||||
# dataframe['MA-20'] = ta.MA(dataframe, timeperiod=20)
|
||||
# stoch = ta.STOCH(dataframe, timeperiod=10)
|
||||
# # print(stoch)
|
||||
# dataframe['STOCH-1-10'] = stoch['slowd']
|
||||
# dataframe['CDLDRAGONFLYDOJI-5'] = ta.CDLDRAGONFLYDOJI(dataframe, timeperiod=5)
|
||||
|
||||
# dataframe['minus_di'] = ta.MINUS_DI(dataframe)
|
||||
|
||||
# dataframe['min'] = ta.MIN(dataframe)
|
||||
# dataframe['max'] = ta.MAX(dataframe)
|
||||
|
||||
# # Aroon, Aroon Oscillator
|
||||
# aroon = ta.AROON(dataframe)
|
||||
# dataframe['aroonup'] = aroon['aroonup']
|
||||
# dataframe['aroondown'] = aroon['aroondown']
|
||||
# dataframe['aroonosc'] = ta.AROONOSC(dataframe)
|
||||
|
||||
dataframe['profit'] = 0
|
||||
# RSI
|
||||
dataframe['rsi'] = ta.RSI(dataframe)
|
||||
|
||||
# # EMA - Exponential Moving Average
|
||||
# dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
|
||||
# dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5)
|
||||
# dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10)
|
||||
# dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21)
|
||||
# dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)
|
||||
# dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100)
|
||||
|
||||
# # SMA - Simple Moving Average
|
||||
# dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3)
|
||||
# dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5)
|
||||
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['sma200'] = ta.SMA(dataframe, timeperiod=200)
|
||||
# dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95
|
||||
# dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98
|
||||
# dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500)
|
||||
# dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9
|
||||
# dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95
|
||||
# dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2
|
||||
dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"]
|
||||
# dataframe["sum_percent"] = dataframe["sum_percent"].shift(1) + dataframe["percent"]
|
||||
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()
|
||||
dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200)
|
||||
dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20)
|
||||
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_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36)
|
||||
|
||||
# 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"]
|
||||
)
|
||||
|
||||
# # 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="4h")
|
||||
|
||||
informative["percent"] = (informative["close"] - informative["open"]) / informative["open"]
|
||||
informative["percent5"] = informative["percent"].rolling(5).sum()
|
||||
informative["percent3"] = informative["percent"].rolling(3).sum()
|
||||
# print('informative', metadata['pair'], informative.tail(1))
|
||||
dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "4h", 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:
|
||||
|
||||
conditions = list()
|
||||
|
||||
# TODO: Its not dry code!
|
||||
buy_indicator = self.buy_indicator0.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator0.value
|
||||
buy_operator = self.buy_operator0.value
|
||||
buy_real_num = self.buy_real_num0.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
# backup
|
||||
buy_indicator = self.buy_indicator1.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator1.value
|
||||
buy_operator = self.buy_operator1.value
|
||||
buy_real_num = self.buy_real_num1.value
|
||||
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
buy_indicator = self.buy_indicator2.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator2.value
|
||||
buy_operator = self.buy_operator2.value
|
||||
buy_real_num = self.buy_real_num2.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
(reduce(lambda x, y: x & y, conditions)
|
||||
# & (dataframe['percent_4h'] > 0)
|
||||
& (dataframe['percent3_4h'] <= 0)
|
||||
),
|
||||
'buy']=1
|
||||
# print(len(dataframe.keys()))
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
return dataframe
|
||||
|
||||
54
GodStraJD3_4_1.json
Normal file
54
GodStraJD3_4_1.json
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_4_1",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.145,
|
||||
"trailing_stop_positive_offset": 0.146,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_bbwidth_num0": 0.9,
|
||||
"buy_cond1_num0": 5.74,
|
||||
"buy_crossed_indicator0": "CDLIDENTICAL3CROWS-100",
|
||||
"buy_crossed_indicator1": "CDLMORNINGDOJISTAR-20",
|
||||
"buy_crossed_indicator2": "CDLEVENINGSTAR-10",
|
||||
"buy_indicator0": "HT_PHASOR-0-100",
|
||||
"buy_indicator1": "DEMA-10",
|
||||
"buy_indicator2": "CDLEVENINGSTAR-10",
|
||||
"buy_operator0": "/<R",
|
||||
"buy_operator1": "<R",
|
||||
"buy_operator2": "D",
|
||||
"buy_real_num0": 0.91,
|
||||
"buy_real_num1": 0.55,
|
||||
"buy_real_num2": 0.19,
|
||||
"buy_shift_bb_lowerband": 1,
|
||||
"profit_no_change": false,
|
||||
"profit_old_sma10": true,
|
||||
"profit_over_rsi": false,
|
||||
"profit_quick_gain": false,
|
||||
"profit_quick_gain_3": false,
|
||||
"profit_quick_lost": true,
|
||||
"profit_short_loss": true,
|
||||
"profit_sma10": true,
|
||||
"profit_sma20": true,
|
||||
"profit_very_old_sma10": false
|
||||
},
|
||||
"sell": {},
|
||||
"protection": {
|
||||
"lookback": 151,
|
||||
"protection_max_allowed_dd": 0.94,
|
||||
"protection_stop": 58,
|
||||
"protection_stoploss_stop": 10,
|
||||
"trade_limit": 1
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-02-07 17:23:41.297535+00:00"
|
||||
}
|
||||
1121
GodStraJD3_4_1.py
Normal file
1121
GodStraJD3_4_1.py
Normal file
File diff suppressed because it is too large
Load Diff
26
GodStraJD3_5.json
Normal file
26
GodStraJD3_5.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_5",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.15,
|
||||
"trailing_stop_positive_offset": 0.2,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_real_num0": 0.7,
|
||||
"buy_real_num1": 0.48,
|
||||
"buy_real_num2": 0.67
|
||||
},
|
||||
"sell": {},
|
||||
"protection": {}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-01-14 20:24:56.873912+00:00"
|
||||
}
|
||||
618
GodStraJD3_5.py
Normal file
618
GodStraJD3_5.py
Normal file
@@ -0,0 +1,618 @@
|
||||
# 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 freqtrade import data
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter
|
||||
|
||||
from numpy.lib import math
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
import pandas
|
||||
from pandas import DataFrame
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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'
|
||||
|
||||
# "buy_real_num0": 0.46,
|
||||
# "buy_real_num1": 0.48,
|
||||
# "buy_real_num2": 0.67
|
||||
|
||||
|
||||
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):
|
||||
|
||||
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] > dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "=":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "<":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "C":
|
||||
condition = (
|
||||
(qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) |
|
||||
(qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator]))
|
||||
)
|
||||
elif operator == "CA":
|
||||
condition = (
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "CB":
|
||||
condition = (
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == ">R":
|
||||
condition = (
|
||||
dataframe[indicator] > real_num
|
||||
)
|
||||
elif operator == "=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], real_num)
|
||||
)
|
||||
elif operator == "<R":
|
||||
condition = (
|
||||
dataframe[indicator] < real_num
|
||||
)
|
||||
elif operator == "/>R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) > real_num
|
||||
)
|
||||
elif operator == "/=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator].div(
|
||||
dataframe[crossed_indicator]), real_num)
|
||||
)
|
||||
elif operator == "/<R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) < real_num
|
||||
)
|
||||
elif operator == "UT":
|
||||
condition = (
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "DT":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "OT":
|
||||
condition = (
|
||||
|
||||
np.isclose(dataframe[indicator], dataframe[indicator_trend_sma])
|
||||
)
|
||||
elif operator == "CUT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "CDT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "COT":
|
||||
condition = (
|
||||
(
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) |
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
) &
|
||||
(
|
||||
np.isclose(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
)
|
||||
return condition, dataframe
|
||||
|
||||
|
||||
class GodStraJD3_5(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'},
|
||||
# 'min': {'color': 'white'},
|
||||
# 'max': {'color': 'white'},
|
||||
'sma20': {'color': 'cyan'}
|
||||
},
|
||||
'subplots': {
|
||||
# Subplots - each dict defines one additional plot
|
||||
"BB": {
|
||||
'bb_width': {'color': 'white'},
|
||||
'bb_min': {'color': 'red'},
|
||||
},
|
||||
"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'},
|
||||
},
|
||||
# "rolling": {
|
||||
# 'bb_rolling': {'color': '#87e470'},
|
||||
# "bb_rolling_min": {'color': '#ac3e2a'}
|
||||
# },
|
||||
# "percent": {
|
||||
# "percent": {'color': 'green'},
|
||||
# "percent3": {'color': 'blue'},
|
||||
# "percent5": {'color': 'red'}
|
||||
# }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# #################### END OF RESULT PLACE ####################
|
||||
|
||||
# TODO: Its not dry code!
|
||||
# Buy Hyperoptable Parameters/Spaces.
|
||||
# "buy_real_num0": 0.46,
|
||||
# "buy_real_num1": 0.48,
|
||||
# "buy_real_num2": 0.67
|
||||
#
|
||||
buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.46, space='buy')
|
||||
buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.48, space='buy')
|
||||
buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.67, space='buy')
|
||||
|
||||
# protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection')
|
||||
# protection_stop = IntParameter(0, 100, default=48, space='protection')
|
||||
# protection_stoploss_stop = IntParameter(0, 100, default=48, space='protection')
|
||||
# lookback = IntParameter(0, 200, default=48, space='protection')
|
||||
# trade_limit = IntParameter(0, 10, default=2, space='protection')
|
||||
#
|
||||
# @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 (current_profit >= 0) & (last_candle['percent3'] < -0.01):
|
||||
return "quick_lost"
|
||||
|
||||
if (current_profit > 0.005) & (last_candle['percent10'] < 0.001):
|
||||
return "no_change"
|
||||
|
||||
#if (current_profit > 0.01) & (last_candle['rsi'] < 30):
|
||||
# return "small_rsi"
|
||||
if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600):
|
||||
return "quick_gain_3"
|
||||
if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0): #& ((current_time - trade.open_date_utc).seconds <= 3600)
|
||||
return "quick_gain"
|
||||
if (current_profit > 0.01) \
|
||||
& ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \
|
||||
| (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 (current_profit > 0.005) & (last_candle['percent5'] < 0) \
|
||||
& ((current_time - trade.open_date_utc).seconds >= 3600) \
|
||||
& ((previous_last_candle['sma20'] > last_candle['sma20']) &
|
||||
((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 (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 (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 (current_profit > 0) \
|
||||
& (last_candle['rsi'] > 88): #| (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.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):
|
||||
return []
|
||||
|
||||
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['min'] = ta.MIN(dataframe['close'], timeperiod=200)
|
||||
dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20)
|
||||
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_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36)
|
||||
|
||||
# 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["q_0.1"] = dataframe.quantile(.1)
|
||||
dataframe["q_0.25"] = dataframe.quantile(.25)
|
||||
dataframe["q_0.33"] = dataframe.quantile(.33)
|
||||
|
||||
# # EMA - Exponential Moving Average
|
||||
# dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
|
||||
condition1, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator0,
|
||||
buy_indicator0,
|
||||
buy_crossed_indicator0,
|
||||
self.buy_real_num0.value
|
||||
)
|
||||
conditions.append(condition1)
|
||||
# # backup
|
||||
# condition2, dataframe = condition_generator(
|
||||
# dataframe,
|
||||
# buy_operator1,
|
||||
# buy_indicator1,
|
||||
# buy_crossed_indicator1,
|
||||
# self.buy_real_num1.value
|
||||
# )
|
||||
# conditions.append(condition2)
|
||||
#
|
||||
# condition3, dataframe = condition_generator(
|
||||
# dataframe,
|
||||
# buy_operator2,
|
||||
# buy_indicator2,
|
||||
# buy_crossed_indicator2,
|
||||
# self.buy_real_num2.value
|
||||
# )
|
||||
# conditions.append(condition3)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
(
|
||||
reduce(lambda x, y: x & y, conditions)
|
||||
& (dataframe['volume10'] * dataframe['close'] / 1000 >= 10)
|
||||
& (dataframe['close'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma10'])
|
||||
& (dataframe['low'] < dataframe['min20'])
|
||||
& (dataframe['bb_width'] > 0.035)
|
||||
# ) | (
|
||||
# (dataframe['volume10'] * dataframe['close'] / 1000 >= 10)
|
||||
# & (dataframe['percent20'] < -0.01)
|
||||
# & (dataframe['percent3'] > 0)
|
||||
# & (dataframe['close'] < dataframe['sma10'])
|
||||
# & (dataframe['sma100'].shift(1) < dataframe['sma100'])
|
||||
#
|
||||
# ) | (
|
||||
# (dataframe['volume10'].shift(1) * dataframe['close'].shift(1) / 1000 >= 10)
|
||||
# & (dataframe['percent20'].shift(1) < -0.01)
|
||||
# & (dataframe['percent3'].shift(1) > 0)
|
||||
# & (dataframe['close'].shift(1) < dataframe['sma10'].shift(1))
|
||||
# & (dataframe['sma100'].shift(1) < dataframe['sma100'])
|
||||
# # & (dataframe['pente5'].shift(1) > 0)
|
||||
), 'buy'] = 1
|
||||
|
||||
pandas.set_option('display.max_rows', dataframe.shape[0] + 1)
|
||||
pandas.set_option('display.max_columns', 30)
|
||||
|
||||
# print(reduce(lambda x, y: x & y, conditions))
|
||||
# print(reduce(lambda x, y: x & y, condition1), " ",
|
||||
# reduce(lambda x, y: x & y, condition2), " ",
|
||||
# reduce(lambda x, y: x & y, condition3), " ",
|
||||
# # (reduce(lambda x, y: x & y, conditions))
|
||||
# dataframe['buy'],
|
||||
#
|
||||
# )
|
||||
|
||||
# if conditions:
|
||||
# dataframe.loc[
|
||||
# (
|
||||
# reduce(lambda x, y: x & y, conditions)
|
||||
# # & (dataframe['volume10'] * dataframe['close'] / 1000 >= 100)
|
||||
# # & (dataframe['percent5'] < 0.025)
|
||||
# # (dataframe['percent10'] < 0.04)
|
||||
# # ) | (
|
||||
# # (dataframe['volume10'] * dataframe['close'] / 1000 >= 100)
|
||||
# # & (dataframe['percent50'] < -0.06)
|
||||
# # & (dataframe['percent3'] > 0)
|
||||
# # # & (dataframe['sma10'].shift(12) > dataframe['sma10'].shift(2))
|
||||
# # & (dataframe['sma10'].shift(2) > dataframe['sma10'].shift(1))
|
||||
# # & (dataframe['sma10'].shift(1) < dataframe['sma10'])
|
||||
# # # & (dataframe['sma100'].shift(1) < dataframe['sma100'])
|
||||
# )
|
||||
# #(dataframe['percent3'] > 0))
|
||||
# ,'buy']=1
|
||||
# print(len(dataframe.keys()))
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
return dataframe
|
||||
|
||||
41
GodStraJD3_5_1.json
Normal file
41
GodStraJD3_5_1.json
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_5_1",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1
|
||||
},
|
||||
"buy": {
|
||||
"buy_real_num0": 0.46,
|
||||
"buy_real_num1": 0.48,
|
||||
"buy_real_num2": 0.67,
|
||||
"profit_no_change": true,
|
||||
"profit_old_sma10": true,
|
||||
"profit_over_rsi": true,
|
||||
"profit_quick_gain": true,
|
||||
"profit_quick_gain_3": true,
|
||||
"profit_short_loss": true,
|
||||
"profit_sma10": true,
|
||||
"profit_sma20": true,
|
||||
"profit_very_old_sma10": true
|
||||
},
|
||||
"sell": {},
|
||||
"protection": {
|
||||
"lookback": 155,
|
||||
"protection_max_allowed_dd": 0.15,
|
||||
"protection_stop": 240,
|
||||
"protection_stoploss_stop": 73,
|
||||
"trade_limit": 3
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.243,
|
||||
"trailing_stop_positive_offset": 0.306,
|
||||
"trailing_only_offset_is_reached": true
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-01-29 13:25:27.974545+00:00"
|
||||
}
|
||||
32
GodStraJD3_5_1.jsonDECREASE
Normal file
32
GodStraJD3_5_1.jsonDECREASE
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_5_1",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.15,
|
||||
"trailing_stop_positive_offset": 0.2,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_real_num0": 1.0,
|
||||
"buy_real_num1": 0.11,
|
||||
"buy_real_num2": 0.47
|
||||
},
|
||||
"sell": {},
|
||||
"protection": {
|
||||
"lookback": 156,
|
||||
"protection_max_allowed_dd": 0.56,
|
||||
"protection_stop": 62,
|
||||
"protection_stoploss_stop": 46,
|
||||
"trade_limit": 6
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -0.288
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-01-27 20:28:08.774453+00:00"
|
||||
}
|
||||
577
GodStraJD3_5_1.py
Normal file
577
GodStraJD3_5_1.py
Normal file
@@ -0,0 +1,577 @@
|
||||
# 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 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
|
||||
from pandas import DataFrame
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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_crossed_indicator1 = 'DX-5'
|
||||
buy_crossed_indicator2 = 'LINEARREG-50'
|
||||
buy_indicator0 = 'MA-20'
|
||||
buy_indicator1 = 'STOCH-1-10'
|
||||
buy_indicator2 = 'CDLDRAGONFLYDOJI-5'
|
||||
buy_operator0 = "/<R"
|
||||
buy_operator1 = ">"
|
||||
buy_operator2 = "/<R"
|
||||
# buy_real_num0 = 0.1,
|
||||
# buy_real_num1 = 0.0,
|
||||
# buy_real_num2 = 0.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):
|
||||
|
||||
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] > dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "=":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "<":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "C":
|
||||
condition = (
|
||||
(qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) |
|
||||
(qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator]))
|
||||
)
|
||||
elif operator == "CA":
|
||||
condition = (
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "CB":
|
||||
condition = (
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == ">R":
|
||||
condition = (
|
||||
dataframe[indicator] > real_num
|
||||
)
|
||||
elif operator == "=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], real_num)
|
||||
)
|
||||
elif operator == "<R":
|
||||
condition = (
|
||||
dataframe[indicator] < real_num
|
||||
)
|
||||
elif operator == "/>R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) > real_num
|
||||
)
|
||||
elif operator == "/=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator].div(
|
||||
dataframe[crossed_indicator]), real_num)
|
||||
)
|
||||
elif operator == "/<R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) < real_num
|
||||
)
|
||||
elif operator == "UT":
|
||||
condition = (
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "DT":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "OT":
|
||||
condition = (
|
||||
|
||||
np.isclose(dataframe[indicator], dataframe[indicator_trend_sma])
|
||||
)
|
||||
elif operator == "CUT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "CDT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "COT":
|
||||
condition = (
|
||||
(
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) |
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
) &
|
||||
(
|
||||
np.isclose(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return condition, dataframe
|
||||
|
||||
|
||||
class GodStraJD3_5_1(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'},
|
||||
'min': {'color': 'white'},
|
||||
'max': {'color': 'white'},
|
||||
'sma20': {'color': 'cyan'}
|
||||
},
|
||||
'subplots': {
|
||||
# Subplots - each dict defines one additional plot
|
||||
"BB": {
|
||||
'bb_width': {'color': 'white'},
|
||||
'bb_min': {'color': 'red'},
|
||||
},
|
||||
"Ind0": {
|
||||
buy_crossed_indicator0: {'color': 'green'},
|
||||
buy_indicator0: {'color': 'red'}
|
||||
},
|
||||
"Ind1": {
|
||||
buy_indicator1: {'color': 'yellow'},
|
||||
buy_crossed_indicator1: {'color': 'pink'}
|
||||
},
|
||||
"Ind2": {
|
||||
buy_indicator2: {'color': 'cyan'},
|
||||
buy_crossed_indicator2: {'color': 'blue'},
|
||||
},
|
||||
"Rsi": {
|
||||
'rsi': {'color': 'pink'},
|
||||
},
|
||||
# "rolling": {
|
||||
# 'bb_rolling': {'color': '#87e470'},
|
||||
# "bb_rolling_min": {'color': '#ac3e2a'}
|
||||
# },
|
||||
"percent": {
|
||||
"percent": {'color': 'green'},
|
||||
"percent3": {'color': 'blue'},
|
||||
"percent5": {'color': 'red'}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# #################### END OF RESULT PLACE ####################
|
||||
|
||||
# TODO: Its not dry code!
|
||||
# Buy Hyperoptable Parameters/Spaces.
|
||||
buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.1, space='buy')
|
||||
buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.0, space='buy')
|
||||
buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.5, space='buy')
|
||||
|
||||
protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection')
|
||||
protection_stop = IntParameter(0, 100, default=48, space='protection')
|
||||
protection_stoploss_stop = IntParameter(0, 100, default=48, space='protection')
|
||||
lookback = IntParameter(0, 200, default=48, space='protection')
|
||||
trade_limit = IntParameter(0, 10, default=2, space='protection')
|
||||
|
||||
profit_no_change = 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")
|
||||
|
||||
@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 self.profit_no_change.value:
|
||||
if (current_profit > 0.005) & (last_candle['percent10'] < 0.001):
|
||||
return "no_change"
|
||||
|
||||
#if (current_profit > 0.01) & (last_candle['rsi'] < 30):
|
||||
# return "small_rsi"
|
||||
if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600):
|
||||
return "quick_gain_3"
|
||||
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.value:
|
||||
if (current_profit > 0.01) \
|
||||
& ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \
|
||||
| (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.value:
|
||||
if (current_profit > 0.005) & (last_candle['percent5'] < 0) \
|
||||
& ((current_time - trade.open_date_utc).seconds >= 3600) \
|
||||
& ((previous_last_candle['sma20'] > last_candle['sma20']) &
|
||||
((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.value:
|
||||
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.value:
|
||||
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.value:
|
||||
if (current_profit > 0) \
|
||||
& (last_candle['rsi'] > 88): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)):
|
||||
# print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
|
||||
return 'over_rsi'
|
||||
|
||||
if self.profit_short_loss.value:
|
||||
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):
|
||||
return []
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
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['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['min'] = ta.MIN(dataframe['close'], timeperiod=200)
|
||||
dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20)
|
||||
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_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36)
|
||||
|
||||
# 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"]
|
||||
)
|
||||
|
||||
# # EMA - Exponential Moving Average
|
||||
# dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator0,
|
||||
buy_indicator0,
|
||||
buy_crossed_indicator0,
|
||||
self.buy_real_num0.value
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
# backup
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator1,
|
||||
buy_indicator1,
|
||||
buy_crossed_indicator1,
|
||||
self.buy_real_num1.value
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator2,
|
||||
buy_indicator2,
|
||||
buy_crossed_indicator2,
|
||||
self.buy_real_num2.value
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
(
|
||||
# reduce(lambda x, y: x & y, conditions)
|
||||
# & (dataframe['volume10'] * dataframe['close'] / 1000 >= 100)
|
||||
# # & (dataframe['percent5'] < 0.025)
|
||||
# # (dataframe['percent10'] < 0.04)
|
||||
# ) | (
|
||||
(dataframe['volume10'] * dataframe['close'] / 1000 >= 100)
|
||||
& ((dataframe['percent20'].shift(5) < -0.025) | (dataframe['percent20'].shift(10) < -0.025))
|
||||
& ((dataframe['percent5'] > 0.001) | (dataframe['open'] < dataframe['bb_lowerband']))
|
||||
& (dataframe['sma10'].shift(1) < dataframe['sma10'])
|
||||
# & (dataframe['open'].shift(50) > dataframe['open'])
|
||||
)
|
||||
#(dataframe['percent3'] > 0))
|
||||
,'buy']=1
|
||||
# print(len(dataframe.keys()))
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
return dataframe
|
||||
|
||||
30
GodStraJD3_5_2.json
Normal file
30
GodStraJD3_5_2.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_5_2",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 1
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": true,
|
||||
"trailing_stop_positive": 0.344,
|
||||
"trailing_stop_positive_offset": 0.354,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_real_num0": 0.46,
|
||||
"buy_real_num1": 0.48,
|
||||
"buy_real_num2": 0.67
|
||||
},
|
||||
"sell": {
|
||||
"sell_real_num0": 0.11,
|
||||
"sell_real_num1": 0.78,
|
||||
"sell_real_num2": 0.36
|
||||
},
|
||||
"protection": {}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-01-20 02:01:29.086955+00:00"
|
||||
}
|
||||
30
GodStraJD3_5_2.jsonBest
Normal file
30
GodStraJD3_5_2.jsonBest
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_5_2",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 1
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": true,
|
||||
"trailing_stop_positive": 0.344,
|
||||
"trailing_stop_positive_offset": 0.354,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_real_num0": 0.46,
|
||||
"buy_real_num1": 0.48,
|
||||
"buy_real_num2": 0.67
|
||||
},
|
||||
"sell": {
|
||||
"sell_real_num0": 0.11,
|
||||
"sell_real_num1": 0.78,
|
||||
"sell_real_num2": 0.36
|
||||
},
|
||||
"protection": {},
|
||||
"stoploss": {
|
||||
"stoploss": -0.02
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-01-20 01:13:41.941514+00:00"
|
||||
}
|
||||
628
GodStraJD3_5_2.py
Normal file
628
GodStraJD3_5_2.py
Normal file
@@ -0,0 +1,628 @@
|
||||
# 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 freqtrade import data
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter
|
||||
|
||||
from numpy.lib import math
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
from pandas import DataFrame
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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_crossed_indicator1 = 'DX-5'
|
||||
buy_crossed_indicator2 = 'LINEARREG-50'
|
||||
buy_indicator0 = 'MA-20'
|
||||
buy_indicator1 = 'STOCH-1-10'
|
||||
buy_indicator2 = 'CDLDRAGONFLYDOJI-5'
|
||||
buy_operator0 = "/<R"
|
||||
buy_operator1 = ">"
|
||||
buy_operator2 = "/<R"
|
||||
|
||||
sell_crossed_indicator0 = 'MIDPOINT-10'
|
||||
sell_crossed_indicator1 = 'CDLTRISTAR-10"'
|
||||
sell_crossed_indicator2 = 'CDLBELTHOLD-50'
|
||||
sell_indicator0 = 'CDLLONGLINE-20'
|
||||
sell_indicator1 = 'STOCHF-1-50'
|
||||
sell_indicator2 = 'MACDEXT-0-5'
|
||||
sell_operator0 = "<"
|
||||
sell_operator1 = ">R"
|
||||
sell_operator2 = ">"
|
||||
|
||||
# buy_real_num0 = 0.1,
|
||||
# buy_real_num1 = 0.0,
|
||||
# buy_real_num2 = 0.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):
|
||||
|
||||
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] > dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "=":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "<":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "C":
|
||||
condition = (
|
||||
(qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) |
|
||||
(qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator]))
|
||||
)
|
||||
elif operator == "CA":
|
||||
condition = (
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "CB":
|
||||
condition = (
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == ">R":
|
||||
condition = (
|
||||
dataframe[indicator] > real_num
|
||||
)
|
||||
elif operator == "=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], real_num)
|
||||
)
|
||||
elif operator == "<R":
|
||||
condition = (
|
||||
dataframe[indicator] < real_num
|
||||
)
|
||||
elif operator == "/>R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) > real_num
|
||||
)
|
||||
elif operator == "/=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator].div(
|
||||
dataframe[crossed_indicator]), real_num)
|
||||
)
|
||||
elif operator == "/<R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) < real_num
|
||||
)
|
||||
elif operator == "UT":
|
||||
condition = (
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "DT":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "OT":
|
||||
condition = (
|
||||
|
||||
np.isclose(dataframe[indicator], dataframe[indicator_trend_sma])
|
||||
)
|
||||
elif operator == "CUT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "CDT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "COT":
|
||||
condition = (
|
||||
(
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) |
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
) &
|
||||
(
|
||||
np.isclose(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return condition, dataframe
|
||||
|
||||
|
||||
class GodStraJD3_5_2(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'},
|
||||
'min': {'color': 'white'},
|
||||
'max': {'color': 'white'},
|
||||
'sma20': {'color': 'cyan'}
|
||||
},
|
||||
'subplots': {
|
||||
# Subplots - each dict defines one additional plot
|
||||
"BB": {
|
||||
'bb_width': {'color': 'white'},
|
||||
'bb_min': {'color': 'red'},
|
||||
},
|
||||
"Ind0": {
|
||||
buy_crossed_indicator0: {'color': 'green'},
|
||||
buy_indicator0: {'color': 'red'}
|
||||
},
|
||||
"Ind1": {
|
||||
buy_indicator1: {'color': 'yellow'},
|
||||
buy_crossed_indicator1: {'color': 'pink'}
|
||||
},
|
||||
"Ind2": {
|
||||
buy_indicator2: {'color': 'cyan'},
|
||||
buy_crossed_indicator2: {'color': 'blue'},
|
||||
},
|
||||
"Sell0": {
|
||||
sell_crossed_indicator0: {'color': 'green'},
|
||||
sell_indicator0: {'color': 'red'}
|
||||
},
|
||||
"Sell1": {
|
||||
sell_indicator1: {'color': 'yellow'},
|
||||
sell_crossed_indicator1: {'color': 'pink'}
|
||||
},
|
||||
"Sell2": {
|
||||
sell_indicator2: {'color': 'cyan'},
|
||||
sell_crossed_indicator2: {'color': 'blue'},
|
||||
},
|
||||
"Rsi": {
|
||||
'rsi': {'color': 'pink'},
|
||||
},
|
||||
# "rolling": {
|
||||
# 'bb_rolling': {'color': '#87e470'},
|
||||
# "bb_rolling_min": {'color': '#ac3e2a'}
|
||||
# },
|
||||
"percent": {
|
||||
"percent": {'color': 'green'},
|
||||
"percent3": {'color': 'blue'},
|
||||
"percent5": {'color': 'red'}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# #################### END OF RESULT PLACE ####################
|
||||
|
||||
# TODO: Its not dry code!
|
||||
# Buy Hyperoptable Parameters/Spaces.
|
||||
buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.1, space='buy')
|
||||
buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.0, space='buy')
|
||||
buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.5, space='buy')
|
||||
|
||||
sell_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.09731, space='sell')
|
||||
sell_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.81657, space='sell')
|
||||
sell_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.87267, space='sell')
|
||||
|
||||
@property
|
||||
def protections(self):
|
||||
return [
|
||||
{
|
||||
"method": "CooldownPeriod",
|
||||
"stop_duration_candles": 12
|
||||
},
|
||||
{
|
||||
"method": "MaxDrawdown",
|
||||
"lookback_period_candles": 48,
|
||||
"trade_limit": 2,
|
||||
"stop_duration_candles": 48,
|
||||
"max_allowed_drawdown": 0.04,
|
||||
"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 (current_profit > 0.015) & (last_candle['percent'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600):
|
||||
return "quick_gain"
|
||||
if (current_profit > 0.01) & (last_candle['rsi'] < 20):
|
||||
return "small_rsi"
|
||||
if (current_profit > 0.005) & (last_candle['percent3'] < -0.01):
|
||||
# print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
|
||||
return 'quick_lost'
|
||||
if (current_profit < -0.02) & ((current_time - trade.open_date_utc).seconds >= 3600):
|
||||
return "stop_loss_1h"
|
||||
|
||||
if (current_profit > 0.005) & (last_candle['percent5'] < -0.015):
|
||||
# print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
|
||||
return 'very_quick_lost'
|
||||
|
||||
# if (current_profit > 0.01) \
|
||||
# & ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \
|
||||
# | (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 (current_profit > 0.005) & (last_candle['percent5'] < 0) \
|
||||
# & ((current_time - trade.open_date_utc).seconds >= 3600) \
|
||||
# & ((previous_last_candle['sma20'] > last_candle['sma20']) &
|
||||
# ((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 (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 (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 (current_profit > 0) \
|
||||
& (previous_last_candle['rsi'] > 88) \
|
||||
& ((last_candle['percent'] < - current_profit / 3) | (last_candle['percent3'] < - current_profit / 3)):
|
||||
# print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
|
||||
return 'over_rsi'
|
||||
|
||||
# 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):
|
||||
return []
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
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[sell_crossed_indicator0] = gene_calculator(dataframe, sell_crossed_indicator0)
|
||||
dataframe[sell_crossed_indicator1] = gene_calculator(dataframe, sell_crossed_indicator1)
|
||||
dataframe[sell_crossed_indicator2] = gene_calculator(dataframe, sell_crossed_indicator2)
|
||||
|
||||
dataframe[sell_indicator0] = gene_calculator(dataframe, sell_indicator0)
|
||||
dataframe[sell_indicator1] = gene_calculator(dataframe, sell_indicator1)
|
||||
dataframe[sell_indicator2] = gene_calculator(dataframe, sell_indicator2)
|
||||
|
||||
# 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['min'] = ta.MIN(dataframe['close'], timeperiod=200)
|
||||
dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20)
|
||||
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_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36)
|
||||
|
||||
# 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"]
|
||||
)
|
||||
|
||||
# # EMA - Exponential Moving Average
|
||||
# dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator0,
|
||||
buy_indicator0,
|
||||
buy_crossed_indicator0,
|
||||
self.buy_real_num0.value
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
# backup
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator1,
|
||||
buy_indicator1,
|
||||
buy_crossed_indicator1,
|
||||
self.buy_real_num1.value
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator2,
|
||||
buy_indicator2,
|
||||
buy_crossed_indicator2,
|
||||
self.buy_real_num2.value
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
# condition_1 = (
|
||||
# reduce(lambda x, y: x & y, conditions) &
|
||||
# (dataframe['volume10'] * dataframe['close'] / 1000 >= 100) &
|
||||
# (dataframe['open'] < dataframe['sma20'])
|
||||
# )
|
||||
# condition_2 = (
|
||||
# (dataframe['bb_width'] > 0.11) &
|
||||
# (dataframe['volume10'] * dataframe['close'] / 1000 >= 100) &
|
||||
# (dataframe['rsi'].shift(1) < 20) &
|
||||
# (dataframe['open'] < dataframe['sma20'])
|
||||
# )
|
||||
# if (condition_1):
|
||||
# dataframe.loc[condition_1, 'buy'] = 'buy_opt'
|
||||
# if (condition_2):
|
||||
# dataframe.loc[condition_2, 'buy'] = 'bb_width'
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
(
|
||||
reduce(lambda x, y: x & y, conditions) &
|
||||
(dataframe['volume10'] * dataframe['close'] / 1000 >= 100) &
|
||||
(dataframe['close'] < dataframe['sma20']) &
|
||||
(dataframe['close'] < dataframe['sma50']) &
|
||||
(dataframe['close'] * 0.99 < dataframe['bb_lowerband'])
|
||||
) | (
|
||||
(dataframe['close'] < dataframe['bb_lowerband']) &
|
||||
(dataframe['bb_width'] > 0.11) &
|
||||
(dataframe['volume10'] * dataframe['close'] / 1000 >= 100) &
|
||||
(dataframe['rsi'] < 30) &
|
||||
(dataframe['close'] < dataframe['sma20']) &
|
||||
(dataframe['sma100'].shift(30) < dataframe['sma100'])
|
||||
),'buy']=1
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
conditions = list()
|
||||
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator0,
|
||||
sell_indicator0,
|
||||
sell_crossed_indicator0,
|
||||
self.sell_real_num0.value
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
# backup
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator1,
|
||||
sell_indicator1,
|
||||
sell_crossed_indicator1,
|
||||
self.sell_real_num1.value
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator2,
|
||||
sell_indicator2,
|
||||
sell_crossed_indicator2,
|
||||
self.sell_real_num2.value
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
(
|
||||
reduce(lambda x, y: x & y, conditions)
|
||||
),
|
||||
'sell']=1
|
||||
return dataframe
|
||||
|
||||
29
GodStraJD3_5_3.json
Normal file
29
GodStraJD3_5_3.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_5_3",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 1
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -0.02
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": true,
|
||||
"trailing_stop_positive": 0.344,
|
||||
"trailing_stop_positive_offset": 0.354,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_sma_max": 0.98,
|
||||
"buy_sma_min": -1.52
|
||||
},
|
||||
"sell": {
|
||||
"sell_real_num0": 0.51,
|
||||
"sell_real_num1": 0.85,
|
||||
"sell_real_num2": 0.0
|
||||
},
|
||||
"protection": {}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-01-20 17:43:05.699962+00:00"
|
||||
}
|
||||
609
GodStraJD3_5_3.py
Normal file
609
GodStraJD3_5_3.py
Normal file
@@ -0,0 +1,609 @@
|
||||
# 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 freqtrade import data
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter
|
||||
|
||||
from numpy.lib import math
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
from pandas import DataFrame
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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_crossed_indicator1 = 'DX-5'
|
||||
buy_crossed_indicator2 = 'LINEARREG-50'
|
||||
buy_indicator0 = 'MA-20'
|
||||
buy_indicator1 = 'STOCH-1-10'
|
||||
buy_indicator2 = 'CDLDRAGONFLYDOJI-5'
|
||||
buy_operator0 = "/<R"
|
||||
buy_operator1 = ">"
|
||||
buy_operator2 = "/<R"
|
||||
|
||||
sell_crossed_indicator0 = 'MIDPOINT-10'
|
||||
sell_crossed_indicator1 = 'CDLTRISTAR-10"'
|
||||
sell_crossed_indicator2 = 'CDLBELTHOLD-50'
|
||||
sell_indicator0 = 'CDLLONGLINE-20'
|
||||
sell_indicator1 = 'STOCHF-1-50'
|
||||
sell_indicator2 = 'MACDEXT-0-5'
|
||||
sell_operator0 = "<"
|
||||
sell_operator1 = ">R"
|
||||
sell_operator2 = ">"
|
||||
|
||||
# buy_real_num0 = 0.1,
|
||||
# buy_real_num1 = 0.0,
|
||||
# buy_real_num2 = 0.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):
|
||||
|
||||
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] > dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "=":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "<":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "C":
|
||||
condition = (
|
||||
(qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) |
|
||||
(qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator]))
|
||||
)
|
||||
elif operator == "CA":
|
||||
condition = (
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "CB":
|
||||
condition = (
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == ">R":
|
||||
condition = (
|
||||
dataframe[indicator] > real_num
|
||||
)
|
||||
elif operator == "=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], real_num)
|
||||
)
|
||||
elif operator == "<R":
|
||||
condition = (
|
||||
dataframe[indicator] < real_num
|
||||
)
|
||||
elif operator == "/>R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) > real_num
|
||||
)
|
||||
elif operator == "/=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator].div(
|
||||
dataframe[crossed_indicator]), real_num)
|
||||
)
|
||||
elif operator == "/<R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) < real_num
|
||||
)
|
||||
elif operator == "UT":
|
||||
condition = (
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "DT":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "OT":
|
||||
condition = (
|
||||
|
||||
np.isclose(dataframe[indicator], dataframe[indicator_trend_sma])
|
||||
)
|
||||
elif operator == "CUT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "CDT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "COT":
|
||||
condition = (
|
||||
(
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) |
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
) &
|
||||
(
|
||||
np.isclose(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return condition, dataframe
|
||||
|
||||
|
||||
class GodStraJD3_5_3(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'},
|
||||
'min': {'color': 'white'},
|
||||
'max': {'color': 'white'},
|
||||
'sma20': {'color': 'cyan'}
|
||||
},
|
||||
'subplots': {
|
||||
# Subplots - each dict defines one additional plot
|
||||
"BB": {
|
||||
'bb_width': {'color': 'white'},
|
||||
'bb_min': {'color': 'red'},
|
||||
},
|
||||
"Ind0": {
|
||||
buy_crossed_indicator0: {'color': 'green'},
|
||||
buy_indicator0: {'color': 'red'}
|
||||
},
|
||||
"Ind1": {
|
||||
buy_indicator1: {'color': 'yellow'},
|
||||
buy_crossed_indicator1: {'color': 'pink'}
|
||||
},
|
||||
"Ind2": {
|
||||
buy_indicator2: {'color': 'cyan'},
|
||||
buy_crossed_indicator2: {'color': 'blue'},
|
||||
},
|
||||
"Sell0": {
|
||||
sell_crossed_indicator0: {'color': 'green'},
|
||||
sell_indicator0: {'color': 'red'}
|
||||
},
|
||||
"Sell1": {
|
||||
sell_indicator1: {'color': 'yellow'},
|
||||
sell_crossed_indicator1: {'color': 'pink'}
|
||||
},
|
||||
"Sell2": {
|
||||
sell_indicator2: {'color': 'cyan'},
|
||||
sell_crossed_indicator2: {'color': 'blue'},
|
||||
},
|
||||
"Rsi": {
|
||||
'rsi': {'color': 'pink'},
|
||||
},
|
||||
# "rolling": {
|
||||
# 'bb_rolling': {'color': '#87e470'},
|
||||
# "bb_rolling_min": {'color': '#ac3e2a'}
|
||||
# },
|
||||
"percent": {
|
||||
"percent": {'color': 'green'},
|
||||
"percent3": {'color': 'blue'},
|
||||
"percent5": {'color': 'red'}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# #################### END OF RESULT PLACE ####################
|
||||
|
||||
# TODO: Its not dry code!
|
||||
# Buy Hyperoptable Parameters/Spaces.
|
||||
|
||||
buy_real_num0 = 0.46
|
||||
buy_real_num1 = 0.48
|
||||
buy_real_num2 = 0.67
|
||||
#buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.1, space='buy')
|
||||
#buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.0, space='buy')
|
||||
#buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.5, space='buy')
|
||||
|
||||
sell_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.09731, space='sell')
|
||||
sell_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.81657, space='sell')
|
||||
sell_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.87267, space='sell')
|
||||
|
||||
# buy_bb_width = DecimalParameter(0, 0.2, decimals=3, default=0.12, space='buy')
|
||||
# buy_bb_min = IntParameter(-30, 50, default=50, space='buy')
|
||||
|
||||
buy_sma_min = DecimalParameter(-2, 2, decimals=2, default=0, space='buy')
|
||||
buy_sma_max = DecimalParameter(-2, 2, decimals=2, default=0.5, space='buy')
|
||||
|
||||
@property
|
||||
def protections(self):
|
||||
return [
|
||||
{
|
||||
"method": "CooldownPeriod",
|
||||
"stop_duration_candles": 10
|
||||
},
|
||||
{
|
||||
"method": "MaxDrawdown",
|
||||
"lookback_period_candles": 48,
|
||||
"trade_limit": 2,
|
||||
"stop_duration_candles": 72,
|
||||
"max_allowed_drawdown": 0.04,
|
||||
"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 (current_profit > 0.005) & (last_candle['percent10'] < 0.001):
|
||||
# return "no_change"
|
||||
if (current_profit > 0.01) & (last_candle['rsi'] < 20):
|
||||
return "small_rsi"
|
||||
# if (current_profit > 0.01) \
|
||||
# & ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \
|
||||
# | (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 (current_profit > 0.005) & (last_candle['percent5'] < 0) \
|
||||
# & ((current_time - trade.open_date_utc).seconds >= 3600) \
|
||||
# & ((previous_last_candle['sma20'] > last_candle['sma20']) &
|
||||
# ((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 (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 (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 (current_profit > 0) \
|
||||
& (last_candle['rsi'] > 88): #| (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.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):
|
||||
return []
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
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[sell_crossed_indicator0] = gene_calculator(dataframe, sell_crossed_indicator0)
|
||||
dataframe[sell_crossed_indicator1] = gene_calculator(dataframe, sell_crossed_indicator1)
|
||||
dataframe[sell_crossed_indicator2] = gene_calculator(dataframe, sell_crossed_indicator2)
|
||||
|
||||
dataframe[sell_indicator0] = gene_calculator(dataframe, sell_indicator0)
|
||||
dataframe[sell_indicator1] = gene_calculator(dataframe, sell_indicator1)
|
||||
dataframe[sell_indicator2] = gene_calculator(dataframe, sell_indicator2)
|
||||
|
||||
# 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['min'] = ta.MIN(dataframe['close'], timeperiod=200)
|
||||
dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20)
|
||||
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_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36)
|
||||
|
||||
# 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"]
|
||||
)
|
||||
|
||||
# # EMA - Exponential Moving Average
|
||||
# dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator0,
|
||||
buy_indicator0,
|
||||
buy_crossed_indicator0,
|
||||
#self.buy_real_num0.value
|
||||
self.buy_real_num0
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
# backup
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator1,
|
||||
buy_indicator1,
|
||||
buy_crossed_indicator1,
|
||||
#self.buy_real_num1.value
|
||||
self.buy_real_num1
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator2,
|
||||
buy_indicator2,
|
||||
buy_crossed_indicator2,
|
||||
#self.buy_real_num2.value
|
||||
self.buy_real_num2
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
(
|
||||
reduce(lambda x, y: x & y, conditions) &
|
||||
(dataframe['volume10'] * dataframe['close'] / 1000 >= 100) &
|
||||
# ((100 * ((dataframe['sma100'] - dataframe['sma100'].shift(10)) / dataframe['sma100'])) >= self.buy_sma_min.value) &
|
||||
# ((100 * ((dataframe['sma100'] - dataframe['sma100'].shift(10)) / dataframe['sma100'])) <= self.buy_sma_max.value) &
|
||||
(dataframe['close'] < dataframe['sma20'])
|
||||
),'buy']=1
|
||||
# print(len(dataframe.keys()))
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
conditions = list()
|
||||
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator0,
|
||||
sell_indicator0,
|
||||
sell_crossed_indicator0,
|
||||
self.sell_real_num0.value
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
# backup
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator1,
|
||||
sell_indicator1,
|
||||
sell_crossed_indicator1,
|
||||
self.sell_real_num1.value
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator2,
|
||||
sell_indicator2,
|
||||
sell_crossed_indicator2,
|
||||
self.sell_real_num2.value
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
(
|
||||
reduce(lambda x, y: x & y, conditions) # (dataframe['open'] < dataframe['sma10'])
|
||||
),
|
||||
'sell']=1
|
||||
return dataframe
|
||||
|
||||
48
GodStraJD3_6.json
Normal file
48
GodStraJD3_6.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_6",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 1
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.15,
|
||||
"trailing_stop_positive_offset": 0.2,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_crossed_indicator0": "CDLTHRUSTING-20",
|
||||
"buy_crossed_indicator1": "MACDEXT-0-20",
|
||||
"buy_crossed_indicator2": "CDLXSIDEGAP3METHODS-50",
|
||||
"buy_indicator0": "MIDPOINT-5",
|
||||
"buy_indicator1": "RSI-20",
|
||||
"buy_indicator2": "CDLSHORTLINE-5",
|
||||
"buy_operator0": "/>R",
|
||||
"buy_operator1": "<R",
|
||||
"buy_operator2": "<",
|
||||
"buy_real_num0": 0.45,
|
||||
"buy_real_num1": 0.42,
|
||||
"buy_real_num2": 0.06
|
||||
},
|
||||
"sell": {
|
||||
"sell_crossed_indicator0": "ROCR100-50",
|
||||
"sell_crossed_indicator1": "SAR-5",
|
||||
"sell_crossed_indicator2": "STOCH-1-10",
|
||||
"sell_indicator0": "CDLHAMMER-10",
|
||||
"sell_indicator1": "MACDFIX-0-10",
|
||||
"sell_indicator2": "CDLDARKCLOUDCOVER-100",
|
||||
"sell_operator0": "/<R",
|
||||
"sell_operator1": ">",
|
||||
"sell_operator2": "CB",
|
||||
"sell_real_num0": 0.4,
|
||||
"sell_real_num1": 0.7,
|
||||
"sell_real_num2": 0.8
|
||||
},
|
||||
"protection": {}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-01-15 13:33:08.407372+00:00"
|
||||
}
|
||||
956
GodStraJD3_6.py
Normal file
956
GodStraJD3_6.py
Normal file
@@ -0,0 +1,956 @@
|
||||
# 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 freqtrade import data
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter
|
||||
|
||||
from numpy.lib import math
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
from pandas import DataFrame
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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
|
||||
# TODO: this gene is removed 'MAVP' cuz or error on periods
|
||||
all_god_genes = {
|
||||
'Overlap Studies': {
|
||||
'BBANDS-0', # Bollinger Bands
|
||||
'BBANDS-1', # Bollinger Bands
|
||||
'BBANDS-2', # Bollinger Bands
|
||||
'DEMA', # Double Exponential Moving Average
|
||||
'EMA', # Exponential Moving Average
|
||||
'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline
|
||||
'KAMA', # Kaufman Adaptive Moving Average
|
||||
'MA', # Moving average
|
||||
'MAMA-0', # MESA Adaptive Moving Average
|
||||
'MAMA-1', # MESA Adaptive Moving Average
|
||||
# TODO: Fix this
|
||||
# 'MAVP', # Moving average with variable period
|
||||
'MIDPOINT', # MidPoint over period
|
||||
'MIDPRICE', # Midpoint Price over period
|
||||
'SAR', # Parabolic SAR
|
||||
'SAREXT', # Parabolic SAR - Extended
|
||||
'SMA', # Simple Moving Average
|
||||
'T3', # Triple Exponential Moving Average (T3)
|
||||
'TEMA', # Triple Exponential Moving Average
|
||||
'TRIMA', # Triangular Moving Average
|
||||
'WMA', # Weighted Moving Average
|
||||
},
|
||||
'Momentum Indicators': {
|
||||
'ADX', # Average Directional Movement Index
|
||||
'ADXR', # Average Directional Movement Index Rating
|
||||
'APO', # Absolute Price Oscillator
|
||||
'AROON-0', # Aroon
|
||||
'AROON-1', # Aroon
|
||||
'AROONOSC', # Aroon Oscillator
|
||||
'BOP', # Balance Of Power
|
||||
'CCI', # Commodity Channel Index
|
||||
'CMO', # Chande Momentum Oscillator
|
||||
'DX', # Directional Movement Index
|
||||
'MACD-0', # Moving Average Convergence/Divergence
|
||||
'MACD-1', # Moving Average Convergence/Divergence
|
||||
'MACD-2', # Moving Average Convergence/Divergence
|
||||
'MACDEXT-0', # MACD with controllable MA type
|
||||
'MACDEXT-1', # MACD with controllable MA type
|
||||
'MACDEXT-2', # MACD with controllable MA type
|
||||
'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MFI', # Money Flow Index
|
||||
'MINUS_DI', # Minus Directional Indicator
|
||||
'MINUS_DM', # Minus Directional Movement
|
||||
'MOM', # Momentum
|
||||
'PLUS_DI', # Plus Directional Indicator
|
||||
'PLUS_DM', # Plus Directional Movement
|
||||
'PPO', # Percentage Price Oscillator
|
||||
'ROC', # Rate of change : ((price/prevPrice)-1)*100
|
||||
# Rate of change Percentage: (price-prevPrice)/prevPrice
|
||||
'ROCP',
|
||||
'ROCR', # Rate of change ratio: (price/prevPrice)
|
||||
# Rate of change ratio 100 scale: (price/prevPrice)*100
|
||||
'ROCR100',
|
||||
'RSI', # Relative Strength Index
|
||||
'STOCH-0', # Stochastic
|
||||
'STOCH-1', # Stochastic
|
||||
'STOCHF-0', # Stochastic Fast
|
||||
'STOCHF-1', # Stochastic Fast
|
||||
'STOCHRSI-0', # Stochastic Relative Strength Index
|
||||
'STOCHRSI-1', # Stochastic Relative Strength Index
|
||||
# 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA
|
||||
'TRIX',
|
||||
'ULTOSC', # Ultimate Oscillator
|
||||
'WILLR', # Williams' %R
|
||||
},
|
||||
'Volume Indicators': {
|
||||
'AD', # Chaikin A/D Line
|
||||
'ADOSC', # Chaikin A/D Oscillator
|
||||
'OBV', # On Balance Volume
|
||||
},
|
||||
'Volatility Indicators': {
|
||||
'ATR', # Average True Range
|
||||
'NATR', # Normalized Average True Range
|
||||
'TRANGE', # True Range
|
||||
},
|
||||
'Price Transform': {
|
||||
'AVGPRICE', # Average Price
|
||||
'MEDPRICE', # Median Price
|
||||
'TYPPRICE', # Typical Price
|
||||
'WCLPRICE', # Weighted Close Price
|
||||
},
|
||||
'Cycle Indicators': {
|
||||
'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period
|
||||
'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase
|
||||
'HT_PHASOR-0', # Hilbert Transform - Phasor Components
|
||||
'HT_PHASOR-1', # Hilbert Transform - Phasor Components
|
||||
'HT_SINE-0', # Hilbert Transform - SineWave
|
||||
'HT_SINE-1', # Hilbert Transform - SineWave
|
||||
'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode
|
||||
},
|
||||
'Pattern Recognition': {
|
||||
'CDL2CROWS', # Two Crows
|
||||
'CDL3BLACKCROWS', # Three Black Crows
|
||||
'CDL3INSIDE', # Three Inside Up/Down
|
||||
'CDL3LINESTRIKE', # Three-Line Strike
|
||||
'CDL3OUTSIDE', # Three Outside Up/Down
|
||||
'CDL3STARSINSOUTH', # Three Stars In The South
|
||||
'CDL3WHITESOLDIERS', # Three Advancing White Soldiers
|
||||
'CDLABANDONEDBABY', # Abandoned Baby
|
||||
'CDLADVANCEBLOCK', # Advance Block
|
||||
'CDLBELTHOLD', # Belt-hold
|
||||
'CDLBREAKAWAY', # Breakaway
|
||||
'CDLCLOSINGMARUBOZU', # Closing Marubozu
|
||||
'CDLCONCEALBABYSWALL', # Concealing Baby Swallow
|
||||
'CDLCOUNTERATTACK', # Counterattack
|
||||
'CDLDARKCLOUDCOVER', # Dark Cloud Cover
|
||||
'CDLDOJI', # Doji
|
||||
'CDLDOJISTAR', # Doji Star
|
||||
'CDLDRAGONFLYDOJI', # Dragonfly Doji
|
||||
'CDLENGULFING', # Engulfing Pattern
|
||||
'CDLEVENINGDOJISTAR', # Evening Doji Star
|
||||
'CDLEVENINGSTAR', # Evening Star
|
||||
'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines
|
||||
'CDLGRAVESTONEDOJI', # Gravestone Doji
|
||||
'CDLHAMMER', # Hammer
|
||||
'CDLHANGINGMAN', # Hanging Man
|
||||
'CDLHARAMI', # Harami Pattern
|
||||
'CDLHARAMICROSS', # Harami Cross Pattern
|
||||
'CDLHIGHWAVE', # High-Wave Candle
|
||||
'CDLHIKKAKE', # Hikkake Pattern
|
||||
'CDLHIKKAKEMOD', # Modified Hikkake Pattern
|
||||
'CDLHOMINGPIGEON', # Homing Pigeon
|
||||
'CDLIDENTICAL3CROWS', # Identical Three Crows
|
||||
'CDLINNECK', # In-Neck Pattern
|
||||
'CDLINVERTEDHAMMER', # Inverted Hammer
|
||||
'CDLKICKING', # Kicking
|
||||
'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu
|
||||
'CDLLADDERBOTTOM', # Ladder Bottom
|
||||
'CDLLONGLEGGEDDOJI', # Long Legged Doji
|
||||
'CDLLONGLINE', # Long Line Candle
|
||||
'CDLMARUBOZU', # Marubozu
|
||||
'CDLMATCHINGLOW', # Matching Low
|
||||
'CDLMATHOLD', # Mat Hold
|
||||
'CDLMORNINGDOJISTAR', # Morning Doji Star
|
||||
'CDLMORNINGSTAR', # Morning Star
|
||||
'CDLONNECK', # On-Neck Pattern
|
||||
'CDLPIERCING', # Piercing Pattern
|
||||
'CDLRICKSHAWMAN', # Rickshaw Man
|
||||
'CDLRISEFALL3METHODS', # Rising/Falling Three Methods
|
||||
'CDLSEPARATINGLINES', # Separating Lines
|
||||
'CDLSHOOTINGSTAR', # Shooting Star
|
||||
'CDLSHORTLINE', # Short Line Candle
|
||||
'CDLSPINNINGTOP', # Spinning Top
|
||||
'CDLSTALLEDPATTERN', # Stalled Pattern
|
||||
'CDLSTICKSANDWICH', # Stick Sandwich
|
||||
# Takuri (Dragonfly Doji with very long lower shadow)
|
||||
'CDLTAKURI',
|
||||
'CDLTASUKIGAP', # Tasuki Gap
|
||||
'CDLTHRUSTING', # Thrusting Pattern
|
||||
'CDLTRISTAR', # Tristar Pattern
|
||||
'CDLUNIQUE3RIVER', # Unique 3 River
|
||||
'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows
|
||||
'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods
|
||||
|
||||
},
|
||||
'Statistic Functions': {
|
||||
'BETA', # Beta
|
||||
'CORREL', # Pearson's Correlation Coefficient (r)
|
||||
'LINEARREG', # Linear Regression
|
||||
'LINEARREG_ANGLE', # Linear Regression Angle
|
||||
'LINEARREG_INTERCEPT', # Linear Regression Intercept
|
||||
'LINEARREG_SLOPE', # Linear Regression Slope
|
||||
'STDDEV', # Standard Deviation
|
||||
'TSF', # Time Series Forecast
|
||||
'VAR', # Variance
|
||||
}
|
||||
|
||||
}
|
||||
god_genes = set()
|
||||
########################### SETTINGS ##############################
|
||||
|
||||
# god_genes = {'SMA'}
|
||||
god_genes |= all_god_genes['Overlap Studies']
|
||||
god_genes |= all_god_genes['Momentum Indicators']
|
||||
god_genes |= all_god_genes['Volume Indicators']
|
||||
god_genes |= all_god_genes['Volatility Indicators']
|
||||
god_genes |= all_god_genes['Price Transform']
|
||||
god_genes |= all_god_genes['Cycle Indicators']
|
||||
god_genes |= all_god_genes['Pattern Recognition']
|
||||
god_genes |= all_god_genes['Statistic Functions']
|
||||
|
||||
#timeperiods = [5, 6, 12, 15, 50, 55, 100, 110]
|
||||
timeperiods = [5, 10, 20, 50, 100]
|
||||
|
||||
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
|
||||
########################### END SETTINGS ##########################
|
||||
# DATAFRAME = DataFrame()
|
||||
|
||||
god_genes = list(god_genes)
|
||||
# print('selected indicators for optimzatin: \n', god_genes)
|
||||
|
||||
god_genes_with_timeperiod = list()
|
||||
for god_gene in god_genes:
|
||||
for timeperiod in timeperiods:
|
||||
# print(f'{god_gene}-{timeperiod}')
|
||||
god_genes_with_timeperiod.append(f'{god_gene}-{timeperiod}')
|
||||
|
||||
# Let give somethings to CatagoricalParam to Play with them
|
||||
# When just one thing is inside catagorical lists
|
||||
# TODO: its Not True Way :)
|
||||
if len(god_genes) == 1:
|
||||
god_genes = god_genes*2
|
||||
if len(timeperiods) == 1:
|
||||
timeperiods = timeperiods*2
|
||||
if len(operators) == 1:
|
||||
operators = operators*2
|
||||
|
||||
|
||||
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):
|
||||
|
||||
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] > dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "=":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "<":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "C":
|
||||
condition = (
|
||||
(qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) |
|
||||
(qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator]))
|
||||
)
|
||||
elif operator == "CA":
|
||||
condition = (
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "CB":
|
||||
condition = (
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == ">R":
|
||||
condition = (
|
||||
dataframe[indicator] > real_num
|
||||
)
|
||||
elif operator == "=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], real_num)
|
||||
)
|
||||
elif operator == "<R":
|
||||
condition = (
|
||||
dataframe[indicator] < real_num
|
||||
)
|
||||
elif operator == "/>R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) > real_num
|
||||
)
|
||||
elif operator == "/=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator].div(
|
||||
dataframe[crossed_indicator]), real_num)
|
||||
)
|
||||
elif operator == "/<R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) < real_num
|
||||
)
|
||||
elif operator == "UT":
|
||||
condition = (
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "DT":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "OT":
|
||||
condition = (
|
||||
|
||||
np.isclose(dataframe[indicator], dataframe[indicator_trend_sma])
|
||||
)
|
||||
elif operator == "CUT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "CDT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "COT":
|
||||
condition = (
|
||||
(
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) |
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
) &
|
||||
(
|
||||
np.isclose(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return condition, dataframe
|
||||
|
||||
|
||||
class GodStraJD3_6(IStrategy):
|
||||
# #################### RESULTS PASTE PLACE ####################
|
||||
# ROI table:
|
||||
minimal_roi = {
|
||||
"0": 1,
|
||||
# "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'},
|
||||
'min': {'color': 'white'},
|
||||
'max': {'color': 'white'},
|
||||
'sma20': {'color': 'cyan'}
|
||||
},
|
||||
'subplots': {
|
||||
# Subplots - each dict defines one additional plot
|
||||
"BB": {
|
||||
'bb_width': {'color': 'white'},
|
||||
'bb_min': {'color': 'red'},
|
||||
},
|
||||
"Ind": {
|
||||
'MA-20': {'color': 'green'},
|
||||
'STOCH-1-10': {'color': 'blue'},
|
||||
'CDLDRAGONFLYDOJI-5': {'color': 'red'}
|
||||
},
|
||||
"Ind2": {
|
||||
'MINUS_DM-5': {'color': 'green'},
|
||||
'DX-5': {'color': 'blue'},
|
||||
'LINEARREG-50': {'color': 'red'}
|
||||
},
|
||||
"Profit": {
|
||||
'profit': {'color': 'pink'},
|
||||
},
|
||||
"Rsi": {
|
||||
'rsi': {'color': 'pink'},
|
||||
},
|
||||
# "rolling": {
|
||||
# 'bb_rolling': {'color': '#87e470'},
|
||||
# "bb_rolling_min": {'color': '#ac3e2a'}
|
||||
# },
|
||||
"percent": {
|
||||
"percent": {'color': 'green'},
|
||||
"percent3": {'color': 'blue'},
|
||||
"percent5": {'color': 'red'}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# #################### END OF RESULT PLACE ####################
|
||||
|
||||
# TODO: Its not dry code!
|
||||
# Buy Hyperoptable Parameters/Spaces.
|
||||
buy_crossed_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="ADD-20", space='buy')
|
||||
buy_crossed_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="ASIN-6", space='buy')
|
||||
buy_crossed_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy')
|
||||
|
||||
buy_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="SMA-100", space='buy')
|
||||
buy_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="WILLR-50", space='buy')
|
||||
buy_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy')
|
||||
|
||||
buy_operator0 = CategoricalParameter(operators, default="/<R", space='buy')
|
||||
buy_operator1 = CategoricalParameter(operators, default="<R", space='buy')
|
||||
buy_operator2 = CategoricalParameter(operators, default="CB", space='buy')
|
||||
|
||||
buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.89009, space='buy')
|
||||
buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.56953, space='buy')
|
||||
buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.38365, space='buy')
|
||||
|
||||
# Sell Hyperoptable Parameters/Spaces.
|
||||
sell_crossed_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="CDLSHOOTINGSTAR-150", space='sell')
|
||||
sell_crossed_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="MAMA-1-100", space='sell')
|
||||
sell_crossed_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLMATHOLD-6", space='sell')
|
||||
|
||||
sell_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="CDLUPSIDEGAP2CROWS-5", space='sell')
|
||||
sell_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="CDLHARAMICROSS-150", space='sell')
|
||||
sell_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDL2CROWS-5", space='sell')
|
||||
|
||||
sell_operator0 = CategoricalParameter(operators, default="<R", space='sell')
|
||||
sell_operator1 = CategoricalParameter(operators, default="D", space='sell')
|
||||
sell_operator2 = CategoricalParameter(operators, default="/>R", space='sell')
|
||||
|
||||
sell_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.09731, space='sell')
|
||||
sell_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.81657, space='sell')
|
||||
sell_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.87267, space='sell')
|
||||
|
||||
@property
|
||||
def protections(self):
|
||||
return [
|
||||
{
|
||||
"method": "CooldownPeriod",
|
||||
"stop_duration_candles": 10
|
||||
},
|
||||
{
|
||||
"method": "MaxDrawdown",
|
||||
"lookback_period_candles": 48,
|
||||
"trade_limit": 2,
|
||||
"stop_duration_candles": 10,
|
||||
"max_allowed_drawdown": 0.04,
|
||||
"only_per_pair": False
|
||||
},
|
||||
# {
|
||||
# "method": "StoplossGuard",
|
||||
# "lookback_period_candles": 24,
|
||||
# "trade_limit": 4,
|
||||
# "stop_duration_candles": 2,
|
||||
# "only_per_pair": False
|
||||
# },
|
||||
# {
|
||||
# "method": "LowProfitPairs",
|
||||
# "lookback_period_candles": 6,
|
||||
# "trade_limit": 2,
|
||||
# "stop_duration_candles": 60,
|
||||
# "required_profit": 0.02
|
||||
# },
|
||||
# {
|
||||
# "method": "LowProfitPairs",
|
||||
# "lookback_period_candles": 24,
|
||||
# "trade_limit": 4,
|
||||
# "stop_duration_candles": 2,
|
||||
# "required_profit": 0.01
|
||||
# }
|
||||
]
|
||||
|
||||
# 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()
|
||||
#
|
||||
# # print("proposed_stake=", proposed_stake, " max_stake=", max_stake)
|
||||
# if current_candle['bb_width'] > 0.065:
|
||||
# # print("use more stake", pair, " ", proposed_stake * 2)
|
||||
# return min(max_stake, proposed_stake * 2)
|
||||
#
|
||||
# if current_candle['bb_width'] > 0.045:
|
||||
# # 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 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()
|
||||
# #print("last_candle", last_candle)
|
||||
# #print("previous_last_candle", previous_last_candle)
|
||||
#
|
||||
# #dataframe.iloc[-1]['profit'] = current_profit
|
||||
# count = 0
|
||||
# for coin, balance in self.wallets.get_all_balances().items():
|
||||
# count = count + 1
|
||||
# # print(coin, " ", balance)
|
||||
# # print("count=", count)
|
||||
#
|
||||
# # (last_candle['percent5'] < -0.005) \
|
||||
# # if (0 < current_profit < 0.005) \
|
||||
# # & ((current_time - trade.open_date_utc).seconds >= 3600 * 2):
|
||||
# # # & (previous_last_candle['sma10'] > last_candle['sma10']):
|
||||
# # print("too_small_gain", pair, trade, " profit=", current_profit, " rate=", current_rate, " percent5=",
|
||||
# # last_candle['percent5'])
|
||||
# # return 'too_small_gain'
|
||||
#
|
||||
# # if (current_profit < -0.05) \
|
||||
# # & ((current_time - trade.open_date_utc).days >= 3):
|
||||
# # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate)
|
||||
# # return 'stop_loss_profit'
|
||||
#
|
||||
# # if (current_profit > 0.02) \
|
||||
# # & (last_candle['percent'] < 0.01) \
|
||||
# # & ((current_time - trade.open_date_utc).seconds >= 3600):
|
||||
# # print("lost_half_profit", pair, trade, " profit=", current_profit, " rate=", current_rate)
|
||||
# # return 'lost_half_profit'
|
||||
#
|
||||
# # ((current_time - trade.open_date_utc).seconds >= 3600 * 2) \
|
||||
# if (current_profit > 0) \
|
||||
# & ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) | (last_candle['percent3'] < -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 'over_bb_band_sma10_desc'
|
||||
#
|
||||
# # if (current_profit > 0) \
|
||||
# # & (last_candle['percent'] < -0.02):
|
||||
# # # print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
|
||||
# # return 'stop_percent_loss'
|
||||
#
|
||||
# #if (current_profit > 0) \
|
||||
# # & ((current_time - trade.open_date_utc).seconds >= 3600 * 2) \
|
||||
# # & (previous_last_candle['sma20'] > last_candle['sma20']) \
|
||||
# # & (last_candle['percent'] < 0):
|
||||
# # print("over_bb_band_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
|
||||
# # return 'over_bb_band_sma20_desc'
|
||||
#
|
||||
# if (current_profit > 0) \
|
||||
# & (last_candle['rsi'] > 88): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)):
|
||||
# # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
|
||||
# return 'over_rsi'
|
||||
#
|
||||
# # description trade
|
||||
# # Trade(id=0, pair=CAKE/USDT, amount=4.19815281, open_rate=11.91000000, open_since=2021-12-22 17:55:00)
|
||||
# # print(last_candle)
|
||||
# #if 0.015 < current_profit < 0.03:
|
||||
# # if (last_candle['percent3'] < -0.005 ):
|
||||
# # # self.lock_pair(pair, until=current_time + timedelta(hours=3))
|
||||
# # print("profit_3h_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
|
||||
# # return 'profit_percent3'
|
||||
#
|
||||
# #
|
||||
# # if (0 < current_profit < 0.1) \
|
||||
# # & (previous_last_candle['sma20'] > last_candle['sma20']) \
|
||||
# # & ((current_time - trade.open_date_utc).seconds >= 3600 * 5):
|
||||
# # print("profit_5h_sma20_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
|
||||
# # return 'profit_5h_sma20_desc'
|
||||
#
|
||||
# # if (count == self.config['max_open_trades']) & (current_profit < -0.04) \
|
||||
# # & ((current_time - trade.open_date_utc).seconds >= 3600 * 6):
|
||||
# # self.lock_pair(pair, until=current_time + timedelta(hours=10))
|
||||
# # print("stop_short_loss", pair, trade, " profit=", current_profit, " rate=", current_rate,
|
||||
# # "count=", count, "max=", self.config['max_open_trades'])
|
||||
# # return 'stop_short_loss'
|
||||
|
||||
def informative_pairs(self):
|
||||
return []
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
# MACD
|
||||
# macd = ta.MACD(dataframe)
|
||||
# dataframe['macd'] = macd['macd']
|
||||
# dataframe['macdsignal'] = macd['macdsignal']
|
||||
# dataframe['macdhist'] = macd['macdhist']
|
||||
|
||||
# # # Plus Directional Indicator / Movement
|
||||
# dataframe['plus_dm'] = ta.PLUS_DM(dataframe)
|
||||
# dataframe['plus_di'] = ta.PLUS_DI(dataframe)
|
||||
#
|
||||
# # Minus Directional Indicator / Movement
|
||||
# dataframe['adx'] = ta.ADX(dataframe)
|
||||
dataframe['MINUS_DM-5'] = gene_calculator(dataframe, 'MINUS_DM-5')
|
||||
dataframe['LINEARREG-50'] = gene_calculator(dataframe, 'LINEARREG-50')
|
||||
dataframe['MA-20'] = gene_calculator(dataframe, 'MA-20')
|
||||
|
||||
dataframe['STOCH-1-10'] = gene_calculator(dataframe, 'STOCH-1-10')
|
||||
dataframe['CDLDRAGONFLYDOJI-5'] = gene_calculator(dataframe, 'CDLDRAGONFLYDOJI-5')
|
||||
dataframe['DX-5'] = gene_calculator(dataframe, 'DX-5')
|
||||
|
||||
# dataframe['MINUS_DM-5'] = ta.MINUS_DM(dataframe, timeperiod=5)
|
||||
# dataframe['LINEARREG-50'] = ta.LINEARREG(dataframe, timeperiod=50)
|
||||
# dataframe['MA-20'] = ta.MA(dataframe, timeperiod=20)
|
||||
# stoch = ta.STOCH(dataframe, timeperiod=10)
|
||||
# # print(stoch)
|
||||
# dataframe['STOCH-1-10'] = stoch['slowd']
|
||||
# dataframe['CDLDRAGONFLYDOJI-5'] = ta.CDLDRAGONFLYDOJI(dataframe, timeperiod=5)
|
||||
|
||||
# dataframe['minus_di'] = ta.MINUS_DI(dataframe)
|
||||
|
||||
# dataframe['min'] = ta.MIN(dataframe)
|
||||
# dataframe['max'] = ta.MAX(dataframe)
|
||||
|
||||
# # Aroon, Aroon Oscillator
|
||||
# aroon = ta.AROON(dataframe)
|
||||
# dataframe['aroonup'] = aroon['aroonup']
|
||||
# dataframe['aroondown'] = aroon['aroondown']
|
||||
# dataframe['aroonosc'] = ta.AROONOSC(dataframe)
|
||||
|
||||
dataframe['profit'] = 0
|
||||
# RSI
|
||||
dataframe['rsi'] = ta.RSI(dataframe)
|
||||
|
||||
# # EMA - Exponential Moving Average
|
||||
# dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
|
||||
# dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5)
|
||||
# dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10)
|
||||
# dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21)
|
||||
# dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)
|
||||
# dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100)
|
||||
|
||||
# # SMA - Simple Moving Average
|
||||
# dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3)
|
||||
# dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5)
|
||||
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['sma200'] = ta.SMA(dataframe, timeperiod=200)
|
||||
# dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95
|
||||
# dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98
|
||||
# dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500)
|
||||
# dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9
|
||||
# dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95
|
||||
# dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2
|
||||
dataframe["percent"] = (dataframe["close"] - dataframe["open"]) / dataframe["open"]
|
||||
dataframe["percent5"] = dataframe["percent"].rolling(5).sum()
|
||||
dataframe["percent3"] = dataframe["percent"].rolling(3).sum()
|
||||
dataframe["percent20"] = dataframe["percent"].rolling(20).sum()
|
||||
dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200)
|
||||
dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20)
|
||||
|
||||
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_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36)
|
||||
|
||||
# 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"]
|
||||
# )
|
||||
|
||||
# # EMA - Exponential Moving Average
|
||||
# dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
|
||||
# TODO: Its not dry code!
|
||||
buy_indicator = self.buy_indicator0.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator0.value
|
||||
buy_operator = self.buy_operator0.value
|
||||
buy_real_num = self.buy_real_num0.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
# backup
|
||||
buy_indicator = self.buy_indicator1.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator1.value
|
||||
buy_operator = self.buy_operator1.value
|
||||
buy_real_num = self.buy_real_num1.value
|
||||
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
buy_indicator = self.buy_indicator2.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator2.value
|
||||
buy_operator = self.buy_operator2.value
|
||||
buy_real_num = self.buy_real_num2.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
# (
|
||||
# (dataframe['close'] < dataframe['bb_lowerband'])
|
||||
# & (dataframe['bb_width'] >= 0.045)
|
||||
# & (dataframe['volume'] * dataframe['close'] / 1000 > 100)
|
||||
# ) |
|
||||
(reduce(lambda x, y: x & y, conditions)),
|
||||
'buy']=1
|
||||
# print(len(dataframe.keys()))
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
# TODO: Its not dry code!
|
||||
sell_indicator = self.sell_indicator0.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator0.value
|
||||
sell_operator = self.sell_operator0.value
|
||||
sell_real_num = self.sell_real_num0.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
sell_indicator = self.sell_indicator1.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator1.value
|
||||
sell_operator = self.sell_operator1.value
|
||||
sell_real_num = self.sell_real_num1.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
sell_indicator = self.sell_indicator2.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator2.value
|
||||
sell_operator = self.sell_operator2.value
|
||||
sell_real_num = self.sell_real_num2.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
#dataframe.loc[(dataframe['close'] < dataframe['bb_lowerband']),'sell']=1
|
||||
|
||||
# count = 0
|
||||
# for coin, balance in self.wallets.get_all_balances().items():
|
||||
# count = count + 1
|
||||
# # print(coin, " ", balance)
|
||||
# if (count == self.config['max_open_trades']) & (current_profit < -0.04) \
|
||||
# & ((current_time - trade.open_date_utc).seconds >= 3600 * 6):
|
||||
# self.lock_pair(pair, until=current_time + timedelta(hours=10))
|
||||
# print("stop_short_loss", pair, trade, " profit=", current_profit, " rate=", current_rate,
|
||||
# "count=", count, "max=", self.config['max_open_trades'])
|
||||
# return 'stop_short_loss'
|
||||
|
||||
# print("sell pair=", self.wallets.get_all_balances()[metadata['pair']])
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
(
|
||||
reduce(lambda x, y: x & y, conditions) &
|
||||
(dataframe['volume'] * dataframe['close'] / 1000 >= 100)
|
||||
# (dataframe['open'] < dataframe['sma10'])
|
||||
),
|
||||
'sell']=1
|
||||
return dataframe
|
||||
48
GodStraJD3_6_53.json
Normal file
48
GodStraJD3_6_53.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_6_53",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 1
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.15,
|
||||
"trailing_stop_positive_offset": 0.2,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_crossed_indicator0": "HT_TRENDLINE-100",
|
||||
"buy_crossed_indicator1": "MACD-1-100",
|
||||
"buy_crossed_indicator2": "CCI-20",
|
||||
"buy_indicator0": "CDLDOJISTAR-10",
|
||||
"buy_indicator1": "WCLPRICE-10",
|
||||
"buy_indicator2": "DEMA-50",
|
||||
"buy_operator0": "/>R",
|
||||
"buy_operator1": "<R",
|
||||
"buy_operator2": "<",
|
||||
"buy_real_num0": 0.92,
|
||||
"buy_real_num1": 0.4,
|
||||
"buy_real_num2": 0.04
|
||||
},
|
||||
"sell": {
|
||||
"sell_crossed_indicator0": "MIDPOINT-10",
|
||||
"sell_crossed_indicator1": "CDLTRISTAR-10",
|
||||
"sell_crossed_indicator2": "CDLBELTHOLD-50",
|
||||
"sell_indicator0": "CDLLONGLINE-20",
|
||||
"sell_indicator1": "STOCHF-1-50",
|
||||
"sell_indicator2": "MACDEXT-0-5",
|
||||
"sell_operator0": "<",
|
||||
"sell_operator1": ">R",
|
||||
"sell_operator2": ">",
|
||||
"sell_real_num0": 0.1,
|
||||
"sell_real_num1": 0.8,
|
||||
"sell_real_num2": 1.0
|
||||
},
|
||||
"protection": {}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-02-01 22:59:30.762086+00:00"
|
||||
}
|
||||
48
GodStraJD3_6_53.jsonOLD
Normal file
48
GodStraJD3_6_53.jsonOLD
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_6_53",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 1
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -2.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.15,
|
||||
"trailing_stop_positive_offset": 0.2,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_crossed_indicator0": "HT_TRENDLINE-100",
|
||||
"buy_crossed_indicator1": "MACD-1-100",
|
||||
"buy_crossed_indicator2": "CCI-20",
|
||||
"buy_indicator0": "CDLDOJISTAR-10",
|
||||
"buy_indicator1": "WCLPRICE-10",
|
||||
"buy_indicator2": "DEMA-50",
|
||||
"buy_operator0": "/>R",
|
||||
"buy_operator1": "<R",
|
||||
"buy_operator2": "<",
|
||||
"buy_real_num0": 0.92,
|
||||
"buy_real_num1": 0.4,
|
||||
"buy_real_num2": 0.04
|
||||
},
|
||||
"sell": {
|
||||
"sell_crossed_indicator0": "CDLSHOOTINGSTAR-150",
|
||||
"sell_crossed_indicator1": "MAMA-1-100",
|
||||
"sell_crossed_indicator2": "CDLMATHOLD-6",
|
||||
"sell_indicator0": "CDLUPSIDEGAP2CROWS-5",
|
||||
"sell_indicator1": "CDLHARAMICROSS-150",
|
||||
"sell_indicator2": "CDL2CROWS-5",
|
||||
"sell_operator0": "<R",
|
||||
"sell_operator1": "D",
|
||||
"sell_operator2": "/>R",
|
||||
"sell_real_num0": 0.1,
|
||||
"sell_real_num1": 0.8,
|
||||
"sell_real_num2": 0.9
|
||||
},
|
||||
"protection": {}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-01-15 13:26:31.727849+00:00"
|
||||
}
|
||||
973
GodStraJD3_6_53.py
Normal file
973
GodStraJD3_6_53.py
Normal file
@@ -0,0 +1,973 @@
|
||||
# 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 freqtrade import data
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter
|
||||
|
||||
from numpy.lib import math
|
||||
from freqtrade.strategy.interface import IStrategy, SellCheckTuple
|
||||
from pandas import DataFrame
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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
|
||||
# TODO: this gene is removed 'MAVP' cuz or error on periods
|
||||
all_god_genes = {
|
||||
'Overlap Studies': {
|
||||
'BBANDS-0', # Bollinger Bands
|
||||
'BBANDS-1', # Bollinger Bands
|
||||
'BBANDS-2', # Bollinger Bands
|
||||
'DEMA', # Double Exponential Moving Average
|
||||
'EMA', # Exponential Moving Average
|
||||
'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline
|
||||
'KAMA', # Kaufman Adaptive Moving Average
|
||||
'MA', # Moving average
|
||||
'MAMA-0', # MESA Adaptive Moving Average
|
||||
'MAMA-1', # MESA Adaptive Moving Average
|
||||
# TODO: Fix this
|
||||
# 'MAVP', # Moving average with variable period
|
||||
'MIDPOINT', # MidPoint over period
|
||||
'MIDPRICE', # Midpoint Price over period
|
||||
'SAR', # Parabolic SAR
|
||||
'SAREXT', # Parabolic SAR - Extended
|
||||
'SMA', # Simple Moving Average
|
||||
'T3', # Triple Exponential Moving Average (T3)
|
||||
'TEMA', # Triple Exponential Moving Average
|
||||
'TRIMA', # Triangular Moving Average
|
||||
'WMA', # Weighted Moving Average
|
||||
},
|
||||
'Momentum Indicators': {
|
||||
'ADX', # Average Directional Movement Index
|
||||
'ADXR', # Average Directional Movement Index Rating
|
||||
'APO', # Absolute Price Oscillator
|
||||
'AROON-0', # Aroon
|
||||
'AROON-1', # Aroon
|
||||
'AROONOSC', # Aroon Oscillator
|
||||
'BOP', # Balance Of Power
|
||||
'CCI', # Commodity Channel Index
|
||||
'CMO', # Chande Momentum Oscillator
|
||||
'DX', # Directional Movement Index
|
||||
'MACD-0', # Moving Average Convergence/Divergence
|
||||
'MACD-1', # Moving Average Convergence/Divergence
|
||||
'MACD-2', # Moving Average Convergence/Divergence
|
||||
'MACDEXT-0', # MACD with controllable MA type
|
||||
'MACDEXT-1', # MACD with controllable MA type
|
||||
'MACDEXT-2', # MACD with controllable MA type
|
||||
'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MFI', # Money Flow Index
|
||||
'MINUS_DI', # Minus Directional Indicator
|
||||
'MINUS_DM', # Minus Directional Movement
|
||||
'MOM', # Momentum
|
||||
'PLUS_DI', # Plus Directional Indicator
|
||||
'PLUS_DM', # Plus Directional Movement
|
||||
'PPO', # Percentage Price Oscillator
|
||||
'ROC', # Rate of change : ((price/prevPrice)-1)*100
|
||||
# Rate of change Percentage: (price-prevPrice)/prevPrice
|
||||
'ROCP',
|
||||
'ROCR', # Rate of change ratio: (price/prevPrice)
|
||||
# Rate of change ratio 100 scale: (price/prevPrice)*100
|
||||
'ROCR100',
|
||||
'RSI', # Relative Strength Index
|
||||
'STOCH-0', # Stochastic
|
||||
'STOCH-1', # Stochastic
|
||||
'STOCHF-0', # Stochastic Fast
|
||||
'STOCHF-1', # Stochastic Fast
|
||||
'STOCHRSI-0', # Stochastic Relative Strength Index
|
||||
'STOCHRSI-1', # Stochastic Relative Strength Index
|
||||
# 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA
|
||||
'TRIX',
|
||||
'ULTOSC', # Ultimate Oscillator
|
||||
'WILLR', # Williams' %R
|
||||
},
|
||||
'Volume Indicators': {
|
||||
'AD', # Chaikin A/D Line
|
||||
'ADOSC', # Chaikin A/D Oscillator
|
||||
'OBV', # On Balance Volume
|
||||
},
|
||||
'Volatility Indicators': {
|
||||
'ATR', # Average True Range
|
||||
'NATR', # Normalized Average True Range
|
||||
'TRANGE', # True Range
|
||||
},
|
||||
'Price Transform': {
|
||||
'AVGPRICE', # Average Price
|
||||
'MEDPRICE', # Median Price
|
||||
'TYPPRICE', # Typical Price
|
||||
'WCLPRICE', # Weighted Close Price
|
||||
},
|
||||
'Cycle Indicators': {
|
||||
'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period
|
||||
'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase
|
||||
'HT_PHASOR-0', # Hilbert Transform - Phasor Components
|
||||
'HT_PHASOR-1', # Hilbert Transform - Phasor Components
|
||||
'HT_SINE-0', # Hilbert Transform - SineWave
|
||||
'HT_SINE-1', # Hilbert Transform - SineWave
|
||||
'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode
|
||||
},
|
||||
'Pattern Recognition': {
|
||||
'CDL2CROWS', # Two Crows
|
||||
'CDL3BLACKCROWS', # Three Black Crows
|
||||
'CDL3INSIDE', # Three Inside Up/Down
|
||||
'CDL3LINESTRIKE', # Three-Line Strike
|
||||
'CDL3OUTSIDE', # Three Outside Up/Down
|
||||
'CDL3STARSINSOUTH', # Three Stars In The South
|
||||
'CDL3WHITESOLDIERS', # Three Advancing White Soldiers
|
||||
'CDLABANDONEDBABY', # Abandoned Baby
|
||||
'CDLADVANCEBLOCK', # Advance Block
|
||||
'CDLBELTHOLD', # Belt-hold
|
||||
'CDLBREAKAWAY', # Breakaway
|
||||
'CDLCLOSINGMARUBOZU', # Closing Marubozu
|
||||
'CDLCONCEALBABYSWALL', # Concealing Baby Swallow
|
||||
'CDLCOUNTERATTACK', # Counterattack
|
||||
'CDLDARKCLOUDCOVER', # Dark Cloud Cover
|
||||
'CDLDOJI', # Doji
|
||||
'CDLDOJISTAR', # Doji Star
|
||||
'CDLDRAGONFLYDOJI', # Dragonfly Doji
|
||||
'CDLENGULFING', # Engulfing Pattern
|
||||
'CDLEVENINGDOJISTAR', # Evening Doji Star
|
||||
'CDLEVENINGSTAR', # Evening Star
|
||||
'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines
|
||||
'CDLGRAVESTONEDOJI', # Gravestone Doji
|
||||
'CDLHAMMER', # Hammer
|
||||
'CDLHANGINGMAN', # Hanging Man
|
||||
'CDLHARAMI', # Harami Pattern
|
||||
'CDLHARAMICROSS', # Harami Cross Pattern
|
||||
'CDLHIGHWAVE', # High-Wave Candle
|
||||
'CDLHIKKAKE', # Hikkake Pattern
|
||||
'CDLHIKKAKEMOD', # Modified Hikkake Pattern
|
||||
'CDLHOMINGPIGEON', # Homing Pigeon
|
||||
'CDLIDENTICAL3CROWS', # Identical Three Crows
|
||||
'CDLINNECK', # In-Neck Pattern
|
||||
'CDLINVERTEDHAMMER', # Inverted Hammer
|
||||
'CDLKICKING', # Kicking
|
||||
'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu
|
||||
'CDLLADDERBOTTOM', # Ladder Bottom
|
||||
'CDLLONGLEGGEDDOJI', # Long Legged Doji
|
||||
'CDLLONGLINE', # Long Line Candle
|
||||
'CDLMARUBOZU', # Marubozu
|
||||
'CDLMATCHINGLOW', # Matching Low
|
||||
'CDLMATHOLD', # Mat Hold
|
||||
'CDLMORNINGDOJISTAR', # Morning Doji Star
|
||||
'CDLMORNINGSTAR', # Morning Star
|
||||
'CDLONNECK', # On-Neck Pattern
|
||||
'CDLPIERCING', # Piercing Pattern
|
||||
'CDLRICKSHAWMAN', # Rickshaw Man
|
||||
'CDLRISEFALL3METHODS', # Rising/Falling Three Methods
|
||||
'CDLSEPARATINGLINES', # Separating Lines
|
||||
'CDLSHOOTINGSTAR', # Shooting Star
|
||||
'CDLSHORTLINE', # Short Line Candle
|
||||
'CDLSPINNINGTOP', # Spinning Top
|
||||
'CDLSTALLEDPATTERN', # Stalled Pattern
|
||||
'CDLSTICKSANDWICH', # Stick Sandwich
|
||||
# Takuri (Dragonfly Doji with very long lower shadow)
|
||||
'CDLTAKURI',
|
||||
'CDLTASUKIGAP', # Tasuki Gap
|
||||
'CDLTHRUSTING', # Thrusting Pattern
|
||||
'CDLTRISTAR', # Tristar Pattern
|
||||
'CDLUNIQUE3RIVER', # Unique 3 River
|
||||
'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows
|
||||
'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods
|
||||
|
||||
},
|
||||
'Statistic Functions': {
|
||||
'BETA', # Beta
|
||||
'CORREL', # Pearson's Correlation Coefficient (r)
|
||||
'LINEARREG', # Linear Regression
|
||||
'LINEARREG_ANGLE', # Linear Regression Angle
|
||||
'LINEARREG_INTERCEPT', # Linear Regression Intercept
|
||||
'LINEARREG_SLOPE', # Linear Regression Slope
|
||||
'STDDEV', # Standard Deviation
|
||||
'TSF', # Time Series Forecast
|
||||
'VAR', # Variance
|
||||
}
|
||||
|
||||
}
|
||||
god_genes = set()
|
||||
########################### SETTINGS ##############################
|
||||
|
||||
# god_genes = {'SMA'}
|
||||
god_genes |= all_god_genes['Overlap Studies']
|
||||
god_genes |= all_god_genes['Momentum Indicators']
|
||||
god_genes |= all_god_genes['Volume Indicators']
|
||||
god_genes |= all_god_genes['Volatility Indicators']
|
||||
god_genes |= all_god_genes['Price Transform']
|
||||
god_genes |= all_god_genes['Cycle Indicators']
|
||||
god_genes |= all_god_genes['Pattern Recognition']
|
||||
god_genes |= all_god_genes['Statistic Functions']
|
||||
|
||||
#timeperiods = [5, 6, 12, 15, 50, 55, 100, 110]
|
||||
timeperiods = [5, 10, 20, 50, 100]
|
||||
|
||||
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
|
||||
|
||||
ind_1 = 'HT_TRENDLINE-100'
|
||||
ind_2 = 'MACD-1-100'
|
||||
ind_3 = 'CCI-20'
|
||||
ind_4 = 'CDLDOJISTAR-10'
|
||||
ind_5 = 'WCLPRICE-10'
|
||||
ind_6 = 'DEMA-50'
|
||||
|
||||
sell_1 = "CDLLONGLINE-20"
|
||||
sell_2 = "STOCHF-1-50"
|
||||
sell_3 = "MACDEXT-0-5"
|
||||
sell_4 = "MIDPOINT-10"
|
||||
sell_5 = "CDLTRISTAR-10"
|
||||
sell_6 = "CDLBELTHOLD-50"
|
||||
|
||||
########################### END SETTINGS ##########################
|
||||
# DATAFRAME = DataFrame()
|
||||
|
||||
god_genes = list(god_genes)
|
||||
# print('selected indicators for optimzatin: \n', god_genes)
|
||||
|
||||
god_genes_with_timeperiod = list()
|
||||
for god_gene in god_genes:
|
||||
for timeperiod in timeperiods:
|
||||
# print(f'{god_gene}-{timeperiod}')
|
||||
god_genes_with_timeperiod.append(f'{god_gene}-{timeperiod}')
|
||||
|
||||
# Let give somethings to CatagoricalParam to Play with them
|
||||
# When just one thing is inside catagorical lists
|
||||
# TODO: its Not True Way :)
|
||||
if len(god_genes) == 1:
|
||||
god_genes = god_genes*2
|
||||
if len(timeperiods) == 1:
|
||||
timeperiods = timeperiods*2
|
||||
if len(operators) == 1:
|
||||
operators = operators*2
|
||||
|
||||
|
||||
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):
|
||||
|
||||
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] > dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "=":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "<":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "C":
|
||||
condition = (
|
||||
(qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) |
|
||||
(qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator]))
|
||||
)
|
||||
elif operator == "CA":
|
||||
condition = (
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "CB":
|
||||
condition = (
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == ">R":
|
||||
condition = (
|
||||
dataframe[indicator] > real_num
|
||||
)
|
||||
elif operator == "=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], real_num)
|
||||
)
|
||||
elif operator == "<R":
|
||||
condition = (
|
||||
dataframe[indicator] < real_num
|
||||
)
|
||||
elif operator == "/>R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) > real_num
|
||||
)
|
||||
elif operator == "/=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator].div(
|
||||
dataframe[crossed_indicator]), real_num)
|
||||
)
|
||||
elif operator == "/<R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) < real_num
|
||||
)
|
||||
elif operator == "UT":
|
||||
condition = (
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "DT":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "OT":
|
||||
condition = (
|
||||
|
||||
np.isclose(dataframe[indicator], dataframe[indicator_trend_sma])
|
||||
)
|
||||
elif operator == "CUT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "CDT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "COT":
|
||||
condition = (
|
||||
(
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) |
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
) &
|
||||
(
|
||||
np.isclose(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return condition, dataframe
|
||||
|
||||
|
||||
class GodStraJD3_6_53(IStrategy):
|
||||
# #################### RESULTS PASTE PLACE ####################
|
||||
# ROI table:
|
||||
minimal_roi = {
|
||||
"0": 1,
|
||||
# "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'},
|
||||
# 'min': {'color': 'white'},
|
||||
# 'max': {'color': 'white'},
|
||||
'sma20': {'color': 'cyan'}
|
||||
},
|
||||
'subplots': {
|
||||
# Subplots - each dict defines one additional plot
|
||||
# "BB": {
|
||||
# 'bb_width': {'color': 'white'},
|
||||
# 'bb_min': {'color': 'red'},
|
||||
# },
|
||||
# "Ind": {
|
||||
# ind_1: {'color': 'green'},
|
||||
# ind_2: {'color': 'blue'},
|
||||
# ind_3: {'color': 'red'}
|
||||
# },
|
||||
# "Ind2": {
|
||||
# ind_4: {'color': 'green'},
|
||||
# ind_5: {'color': 'blue'},
|
||||
# ind_6: {'color': 'red'}
|
||||
# },
|
||||
"Pentes": {
|
||||
'pente5': {'color': 'green'},
|
||||
'pente10': {'color': 'pink'},
|
||||
'pente20': {'color': 'green'},
|
||||
'pente50': {'color': 'yellow'}
|
||||
},
|
||||
# "Rsi": {
|
||||
# 'rsi': {'color': 'pink'},
|
||||
# },
|
||||
# "rolling": {
|
||||
# 'bb_rolling': {'color': '#87e470'},
|
||||
# "bb_rolling_min": {'color': '#ac3e2a'}
|
||||
# },
|
||||
"percent": {
|
||||
"percent3": {'color': 'blue'},
|
||||
"percent5": {'color': 'red'},
|
||||
"percent10": {'color': 'green'},
|
||||
"percent20": {'color': 'red'},
|
||||
"percent50": {'color': 'pink'}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# #################### END OF RESULT PLACE ####################
|
||||
|
||||
# TODO: Its not dry code!
|
||||
# Buy Hyperoptable Parameters/Spaces.
|
||||
buy_crossed_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="ADD-20", space='buy')
|
||||
buy_crossed_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="ASIN-6", space='buy')
|
||||
buy_crossed_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy')
|
||||
|
||||
buy_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="SMA-100", space='buy')
|
||||
buy_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="WILLR-50", space='buy')
|
||||
buy_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy')
|
||||
|
||||
buy_operator0 = CategoricalParameter(operators, default="/<R", space='buy')
|
||||
buy_operator1 = CategoricalParameter(operators, default="<R", space='buy')
|
||||
buy_operator2 = CategoricalParameter(operators, default="CB", space='buy')
|
||||
|
||||
buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.89009, space='buy')
|
||||
buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.56953, space='buy')
|
||||
buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.38365, space='buy')
|
||||
|
||||
# Sell Hyperoptable Parameters/Spaces.
|
||||
sell_crossed_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="CDLSHOOTINGSTAR-150", space='sell')
|
||||
sell_crossed_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="MAMA-1-100", space='sell')
|
||||
sell_crossed_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLMATHOLD-6", space='sell')
|
||||
|
||||
sell_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="CDLUPSIDEGAP2CROWS-5", space='sell')
|
||||
sell_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="CDLHARAMICROSS-150", space='sell')
|
||||
sell_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDL2CROWS-5", space='sell')
|
||||
|
||||
sell_operator0 = CategoricalParameter(operators, default="<R", space='sell')
|
||||
sell_operator1 = CategoricalParameter(operators, default="D", space='sell')
|
||||
sell_operator2 = CategoricalParameter(operators, default="/>R", space='sell')
|
||||
|
||||
sell_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.09731, space='sell')
|
||||
sell_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.81657, space='sell')
|
||||
sell_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.87267, space='sell')
|
||||
|
||||
protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection')
|
||||
protection_stop = IntParameter(0, 100, default=48, space='protection')
|
||||
protection_stoploss_stop = IntParameter(0, 100, default=48, space='protection')
|
||||
lookback = IntParameter(0, 200, default=48, space='protection')
|
||||
trade_limit = IntParameter(0, 10, default=2, space='protection')
|
||||
|
||||
|
||||
@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 (current_profit >= 0) & \
|
||||
(
|
||||
(last_candle['percent3'] < -0.01) |
|
||||
((last_candle['percent'] < -0.01) & (previous_last_candle['rsi'] > 72))
|
||||
):
|
||||
return "quick_lost"
|
||||
|
||||
if (current_profit > 0.005) & (last_candle['percent10'] < 0.001):
|
||||
return "no_change"
|
||||
#if (current_profit > 0.01) & (last_candle['rsi'] < 30):
|
||||
# return "small_rsi"
|
||||
if (current_profit >= 0.03) & (last_candle['percent3'] < 0) & ((current_time - trade.open_date_utc).seconds <= 3600):
|
||||
return "quick_gain_3"
|
||||
if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0): #& ((current_time - trade.open_date_utc).seconds <= 3600)
|
||||
return "quick_gain"
|
||||
if (current_profit > 0.01) \
|
||||
& ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \
|
||||
| (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 (current_profit > 0.005) & (last_candle['percent5'] < 0) \
|
||||
& ((current_time - trade.open_date_utc).seconds >= 3600) \
|
||||
& ((previous_last_candle['sma20'] > last_candle['sma20']) &
|
||||
((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 (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 (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 (current_profit > 0) \
|
||||
& (last_candle['rsi'] > 88): #| (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.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):
|
||||
return []
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
# MACD
|
||||
# macd = ta.MACD(dataframe)
|
||||
# dataframe['macd'] = macd['macd']
|
||||
# dataframe['macdsignal'] = macd['macdsignal']
|
||||
# dataframe['macdhist'] = macd['macdhist']
|
||||
|
||||
# # # Plus Directional Indicator / Movement
|
||||
# dataframe['plus_dm'] = ta.PLUS_DM(dataframe)
|
||||
# dataframe['plus_di'] = ta.PLUS_DI(dataframe)
|
||||
#
|
||||
# # Minus Directional Indicator / Movement
|
||||
# dataframe['adx'] = ta.ADX(dataframe)
|
||||
|
||||
dataframe[ind_1] = gene_calculator(dataframe, ind_1)
|
||||
dataframe[ind_2] = gene_calculator(dataframe, ind_2)
|
||||
dataframe[ind_3] = gene_calculator(dataframe, ind_3)
|
||||
|
||||
dataframe[ind_4] = gene_calculator(dataframe, ind_4)
|
||||
dataframe[ind_5] = gene_calculator(dataframe, ind_5)
|
||||
dataframe[ind_6] = gene_calculator(dataframe, ind_6)
|
||||
|
||||
dataframe[sell_1] = gene_calculator(dataframe, sell_1)
|
||||
dataframe[sell_2] = gene_calculator(dataframe, sell_2)
|
||||
dataframe[sell_3] = gene_calculator(dataframe, sell_3)
|
||||
|
||||
dataframe[sell_4] = gene_calculator(dataframe, sell_4)
|
||||
dataframe[sell_5] = gene_calculator(dataframe, sell_5)
|
||||
dataframe[sell_6] = gene_calculator(dataframe, sell_6)
|
||||
|
||||
# dataframe['MINUS_DM-5'] = ta.MINUS_DM(dataframe, timeperiod=5)
|
||||
# dataframe['LINEARREG-50'] = ta.LINEARREG(dataframe, timeperiod=50)
|
||||
# dataframe['MA-20'] = ta.MA(dataframe, timeperiod=20)
|
||||
# stoch = ta.STOCH(dataframe, timeperiod=10)
|
||||
# # print(stoch)
|
||||
# dataframe['STOCH-1-10'] = stoch['slowd']
|
||||
# dataframe['CDLDRAGONFLYDOJI-5'] = ta.CDLDRAGONFLYDOJI(dataframe, timeperiod=5)
|
||||
|
||||
# dataframe['minus_di'] = ta.MINUS_DI(dataframe)
|
||||
|
||||
# dataframe['min'] = ta.MIN(dataframe)
|
||||
# dataframe['max'] = ta.MAX(dataframe)
|
||||
|
||||
# # Aroon, Aroon Oscillator
|
||||
# aroon = ta.AROON(dataframe)
|
||||
# dataframe['aroonup'] = aroon['aroonup']
|
||||
# dataframe['aroondown'] = aroon['aroondown']
|
||||
# dataframe['aroonosc'] = ta.AROONOSC(dataframe)
|
||||
|
||||
dataframe['profit'] = 0
|
||||
# RSI
|
||||
dataframe['rsi'] = ta.RSI(dataframe)
|
||||
|
||||
# # EMA - Exponential Moving Average
|
||||
# dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
|
||||
# dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5)
|
||||
# dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10)
|
||||
# dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21)
|
||||
# dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)
|
||||
# dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100)
|
||||
|
||||
# # SMA - Simple Moving Average
|
||||
# dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3)
|
||||
dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5)
|
||||
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['sma200'] = ta.SMA(dataframe, timeperiod=200)
|
||||
# dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95
|
||||
# dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98
|
||||
# dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500)
|
||||
# dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9
|
||||
# dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95
|
||||
# dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2
|
||||
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()
|
||||
|
||||
dataframe['min'] = ta.MIN(dataframe['close'], timeperiod=200)
|
||||
dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20)
|
||||
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_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36)
|
||||
dataframe['pente5'] = (100 * (dataframe["sma5"] - dataframe["sma5"].shift(1)) / dataframe["sma5"])
|
||||
dataframe['pente10'] = (100 * (dataframe["sma10"] - dataframe["sma10"].shift(1)) / dataframe["sma10"])
|
||||
dataframe['pente20'] = (100 * (dataframe["sma20"] - dataframe["sma20"].shift(1)) / dataframe["sma20"])
|
||||
dataframe['pente50'] = (100 * (dataframe["sma50"] - dataframe["sma50"].shift(1)) / dataframe["sma50"])
|
||||
|
||||
# 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"]
|
||||
# )
|
||||
|
||||
# # EMA - Exponential Moving Average
|
||||
# dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
|
||||
# TODO: Its not dry code!
|
||||
buy_indicator = self.buy_indicator0.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator0.value
|
||||
buy_operator = self.buy_operator0.value
|
||||
buy_real_num = self.buy_real_num0.value
|
||||
condition1, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition1)
|
||||
# backup
|
||||
buy_indicator = self.buy_indicator1.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator1.value
|
||||
buy_operator = self.buy_operator1.value
|
||||
buy_real_num = self.buy_real_num1.value
|
||||
|
||||
condition2, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition2)
|
||||
|
||||
buy_indicator = self.buy_indicator2.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator2.value
|
||||
buy_operator = self.buy_operator2.value
|
||||
buy_real_num = self.buy_real_num2.value
|
||||
condition3, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition3)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
(
|
||||
(reduce(lambda x, y: x & y, conditions))
|
||||
& (dataframe['volume10'] * dataframe['close'] / 1000 >= 10)
|
||||
& (dataframe['close'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma10'])
|
||||
& (dataframe['low'] < dataframe['min20'])
|
||||
) | (
|
||||
(dataframe['volume10'] * dataframe['close'] / 1000 >= 10)
|
||||
& (dataframe['percent20'].shift(10) < -0.03)
|
||||
& (dataframe['pente10'].shift(5) < 0)
|
||||
& (dataframe['pente10'] > 0)
|
||||
& (dataframe['open'] < dataframe['sma10'])
|
||||
& (dataframe['close'] < dataframe['sma10'])
|
||||
& (dataframe['low'] < dataframe['min20'])
|
||||
# ) | (
|
||||
# (dataframe['volume10'] * dataframe['close'] / 1000 >= 10)
|
||||
# & (dataframe['percent20'].shift(5) < -0.01)
|
||||
# & (dataframe['percent3'] > 0)
|
||||
# & (dataframe['open'] < dataframe['sma10'])
|
||||
# & (dataframe['close'] < dataframe['sma10'])
|
||||
# & (dataframe['sma100'].shift(1) < dataframe['sma100'])
|
||||
# # & (dataframe['pente5'] > 0)
|
||||
#
|
||||
# ) | (
|
||||
# (dataframe['volume10'].shift(1) * dataframe['close'].shift(1) / 1000 >= 10)
|
||||
# & (dataframe['percent20'].shift(6) < -0.01)
|
||||
# & (dataframe['percent3'].shift(1) > 0)
|
||||
# & (dataframe['open'].shift(1) < dataframe['sma10'].shift(1))
|
||||
# & (dataframe['close'].shift(1) < dataframe['sma10'].shift(1))
|
||||
# & (dataframe['sma100'].shift(1) < dataframe['sma100'])
|
||||
# # & (dataframe['pente5'].shift(1) > 0)
|
||||
),
|
||||
'buy']=1
|
||||
# print(len(dataframe.keys()))
|
||||
|
||||
# print(
|
||||
# reduce(lambda x, y: x & y, condition1), " ",
|
||||
# reduce(lambda x, y: x & y, condition2), " ",
|
||||
# reduce(lambda x, y: x & y, condition3), " ",
|
||||
# # (reduce(lambda x, y: x & y, conditions))
|
||||
# dataframe['buy'],
|
||||
# )
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
# TODO: Its not dry code!
|
||||
sell_indicator = self.sell_indicator0.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator0.value
|
||||
sell_operator = self.sell_operator0.value
|
||||
sell_real_num = self.sell_real_num0.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
sell_indicator = self.sell_indicator1.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator1.value
|
||||
sell_operator = self.sell_operator1.value
|
||||
sell_real_num = self.sell_real_num1.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
sell_indicator = self.sell_indicator2.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator2.value
|
||||
sell_operator = self.sell_operator2.value
|
||||
sell_real_num = self.sell_real_num2.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
#dataframe.loc[(dataframe['close'] < dataframe['bb_lowerband']),'sell']=1
|
||||
|
||||
# count = 0
|
||||
# for coin, balance in self.wallets.get_all_balances().items():
|
||||
# count = count + 1
|
||||
# # print(coin, " ", balance)
|
||||
# if (count == self.config['max_open_trades']) & (current_profit < -0.04) \
|
||||
# & ((current_time - trade.open_date_utc).seconds >= 3600 * 6):
|
||||
# self.lock_pair(pair, until=current_time + timedelta(hours=10))
|
||||
# print("stop_short_loss", pair, trade, " profit=", current_profit, " rate=", current_rate,
|
||||
# "count=", count, "max=", self.config['max_open_trades'])
|
||||
# return 'stop_short_loss'
|
||||
|
||||
# print("sell pair=", self.wallets.get_all_balances()[metadata['pair']])
|
||||
|
||||
# if conditions:
|
||||
# dataframe.loc[
|
||||
# (
|
||||
# reduce(lambda x, y: x & y, conditions) #(dataframe['percent3'] > 0)
|
||||
# ),
|
||||
# 'sell']=1
|
||||
return dataframe
|
||||
|
||||
51
GodStraJD3_6_53_1.json
Normal file
51
GodStraJD3_6_53_1.json
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_6_53_1",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.15,
|
||||
"trailing_stop_positive_offset": 0.2,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_crossed_indicator0": "HT_TRENDLINE-100",
|
||||
"buy_crossed_indicator1": "MACD-1-100",
|
||||
"buy_crossed_indicator2": "CCI-20",
|
||||
"buy_indicator0": "CDLDOJISTAR-10",
|
||||
"buy_indicator1": "WCLPRICE-10",
|
||||
"buy_indicator2": "DEMA-50",
|
||||
"buy_operator0": "/>R",
|
||||
"buy_operator1": "<R",
|
||||
"buy_operator2": "<",
|
||||
"buy_real_num0": 0.92,
|
||||
"buy_real_num1": 0.4,
|
||||
"buy_real_num2": 0.04
|
||||
},
|
||||
"sell": {
|
||||
"sell_crossed_indicator0": "MIDPOINT-10",
|
||||
"sell_crossed_indicator1": "CDLTRISTAR-10",
|
||||
"sell_crossed_indicator2": "CDLBELTHOLD-50",
|
||||
"sell_indicator0": "CDLLONGLINE-20",
|
||||
"sell_indicator1": "STOCHF-1-50",
|
||||
"sell_indicator2": "MACDEXT-0-5",
|
||||
"sell_operator0": "<",
|
||||
"sell_operator1": ">R",
|
||||
"sell_operator2": ">",
|
||||
"sell_real_num0": 0.1,
|
||||
"sell_real_num1": 0.8,
|
||||
"sell_real_num2": 1.0
|
||||
},
|
||||
"protection": {
|
||||
"protection_max_allowed_dd": 0.36,
|
||||
"protection_stop": 25
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -0.189
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-01-23 14:20:28.600763+00:00"
|
||||
}
|
||||
920
GodStraJD3_6_53_1.py
Normal file
920
GodStraJD3_6_53_1.py
Normal file
@@ -0,0 +1,920 @@
|
||||
# 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 freqtrade import data
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter
|
||||
|
||||
from numpy.lib import math
|
||||
from freqtrade.strategy.interface import IStrategy, SellCheckTuple
|
||||
from pandas import DataFrame
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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
|
||||
# TODO: this gene is removed 'MAVP' cuz or error on periods
|
||||
all_god_genes = {
|
||||
'Overlap Studies': {
|
||||
'BBANDS-0', # Bollinger Bands
|
||||
'BBANDS-1', # Bollinger Bands
|
||||
'BBANDS-2', # Bollinger Bands
|
||||
'DEMA', # Double Exponential Moving Average
|
||||
'EMA', # Exponential Moving Average
|
||||
'HT_TRENDLINE', # Hilbert Transform - Instantaneous Trendline
|
||||
'KAMA', # Kaufman Adaptive Moving Average
|
||||
'MA', # Moving average
|
||||
'MAMA-0', # MESA Adaptive Moving Average
|
||||
'MAMA-1', # MESA Adaptive Moving Average
|
||||
# TODO: Fix this
|
||||
# 'MAVP', # Moving average with variable period
|
||||
'MIDPOINT', # MidPoint over period
|
||||
'MIDPRICE', # Midpoint Price over period
|
||||
'SAR', # Parabolic SAR
|
||||
'SAREXT', # Parabolic SAR - Extended
|
||||
'SMA', # Simple Moving Average
|
||||
'T3', # Triple Exponential Moving Average (T3)
|
||||
'TEMA', # Triple Exponential Moving Average
|
||||
'TRIMA', # Triangular Moving Average
|
||||
'WMA', # Weighted Moving Average
|
||||
},
|
||||
'Momentum Indicators': {
|
||||
'ADX', # Average Directional Movement Index
|
||||
'ADXR', # Average Directional Movement Index Rating
|
||||
'APO', # Absolute Price Oscillator
|
||||
'AROON-0', # Aroon
|
||||
'AROON-1', # Aroon
|
||||
'AROONOSC', # Aroon Oscillator
|
||||
'BOP', # Balance Of Power
|
||||
'CCI', # Commodity Channel Index
|
||||
'CMO', # Chande Momentum Oscillator
|
||||
'DX', # Directional Movement Index
|
||||
'MACD-0', # Moving Average Convergence/Divergence
|
||||
'MACD-1', # Moving Average Convergence/Divergence
|
||||
'MACD-2', # Moving Average Convergence/Divergence
|
||||
'MACDEXT-0', # MACD with controllable MA type
|
||||
'MACDEXT-1', # MACD with controllable MA type
|
||||
'MACDEXT-2', # MACD with controllable MA type
|
||||
'MACDFIX-0', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MACDFIX-1', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MACDFIX-2', # Moving Average Convergence/Divergence Fix 12/26
|
||||
'MFI', # Money Flow Index
|
||||
'MINUS_DI', # Minus Directional Indicator
|
||||
'MINUS_DM', # Minus Directional Movement
|
||||
'MOM', # Momentum
|
||||
'PLUS_DI', # Plus Directional Indicator
|
||||
'PLUS_DM', # Plus Directional Movement
|
||||
'PPO', # Percentage Price Oscillator
|
||||
'ROC', # Rate of change : ((price/prevPrice)-1)*100
|
||||
# Rate of change Percentage: (price-prevPrice)/prevPrice
|
||||
'ROCP',
|
||||
'ROCR', # Rate of change ratio: (price/prevPrice)
|
||||
# Rate of change ratio 100 scale: (price/prevPrice)*100
|
||||
'ROCR100',
|
||||
'RSI', # Relative Strength Index
|
||||
'STOCH-0', # Stochastic
|
||||
'STOCH-1', # Stochastic
|
||||
'STOCHF-0', # Stochastic Fast
|
||||
'STOCHF-1', # Stochastic Fast
|
||||
'STOCHRSI-0', # Stochastic Relative Strength Index
|
||||
'STOCHRSI-1', # Stochastic Relative Strength Index
|
||||
# 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA
|
||||
'TRIX',
|
||||
'ULTOSC', # Ultimate Oscillator
|
||||
'WILLR', # Williams' %R
|
||||
},
|
||||
'Volume Indicators': {
|
||||
'AD', # Chaikin A/D Line
|
||||
'ADOSC', # Chaikin A/D Oscillator
|
||||
'OBV', # On Balance Volume
|
||||
},
|
||||
'Volatility Indicators': {
|
||||
'ATR', # Average True Range
|
||||
'NATR', # Normalized Average True Range
|
||||
'TRANGE', # True Range
|
||||
},
|
||||
'Price Transform': {
|
||||
'AVGPRICE', # Average Price
|
||||
'MEDPRICE', # Median Price
|
||||
'TYPPRICE', # Typical Price
|
||||
'WCLPRICE', # Weighted Close Price
|
||||
},
|
||||
'Cycle Indicators': {
|
||||
'HT_DCPERIOD', # Hilbert Transform - Dominant Cycle Period
|
||||
'HT_DCPHASE', # Hilbert Transform - Dominant Cycle Phase
|
||||
'HT_PHASOR-0', # Hilbert Transform - Phasor Components
|
||||
'HT_PHASOR-1', # Hilbert Transform - Phasor Components
|
||||
'HT_SINE-0', # Hilbert Transform - SineWave
|
||||
'HT_SINE-1', # Hilbert Transform - SineWave
|
||||
'HT_TRENDMODE', # Hilbert Transform - Trend vs Cycle Mode
|
||||
},
|
||||
'Pattern Recognition': {
|
||||
'CDL2CROWS', # Two Crows
|
||||
'CDL3BLACKCROWS', # Three Black Crows
|
||||
'CDL3INSIDE', # Three Inside Up/Down
|
||||
'CDL3LINESTRIKE', # Three-Line Strike
|
||||
'CDL3OUTSIDE', # Three Outside Up/Down
|
||||
'CDL3STARSINSOUTH', # Three Stars In The South
|
||||
'CDL3WHITESOLDIERS', # Three Advancing White Soldiers
|
||||
'CDLABANDONEDBABY', # Abandoned Baby
|
||||
'CDLADVANCEBLOCK', # Advance Block
|
||||
'CDLBELTHOLD', # Belt-hold
|
||||
'CDLBREAKAWAY', # Breakaway
|
||||
'CDLCLOSINGMARUBOZU', # Closing Marubozu
|
||||
'CDLCONCEALBABYSWALL', # Concealing Baby Swallow
|
||||
'CDLCOUNTERATTACK', # Counterattack
|
||||
'CDLDARKCLOUDCOVER', # Dark Cloud Cover
|
||||
'CDLDOJI', # Doji
|
||||
'CDLDOJISTAR', # Doji Star
|
||||
'CDLDRAGONFLYDOJI', # Dragonfly Doji
|
||||
'CDLENGULFING', # Engulfing Pattern
|
||||
'CDLEVENINGDOJISTAR', # Evening Doji Star
|
||||
'CDLEVENINGSTAR', # Evening Star
|
||||
'CDLGAPSIDESIDEWHITE', # Up/Down-gap side-by-side white lines
|
||||
'CDLGRAVESTONEDOJI', # Gravestone Doji
|
||||
'CDLHAMMER', # Hammer
|
||||
'CDLHANGINGMAN', # Hanging Man
|
||||
'CDLHARAMI', # Harami Pattern
|
||||
'CDLHARAMICROSS', # Harami Cross Pattern
|
||||
'CDLHIGHWAVE', # High-Wave Candle
|
||||
'CDLHIKKAKE', # Hikkake Pattern
|
||||
'CDLHIKKAKEMOD', # Modified Hikkake Pattern
|
||||
'CDLHOMINGPIGEON', # Homing Pigeon
|
||||
'CDLIDENTICAL3CROWS', # Identical Three Crows
|
||||
'CDLINNECK', # In-Neck Pattern
|
||||
'CDLINVERTEDHAMMER', # Inverted Hammer
|
||||
'CDLKICKING', # Kicking
|
||||
'CDLKICKINGBYLENGTH', # Kicking - bull/bear determined by the longer marubozu
|
||||
'CDLLADDERBOTTOM', # Ladder Bottom
|
||||
'CDLLONGLEGGEDDOJI', # Long Legged Doji
|
||||
'CDLLONGLINE', # Long Line Candle
|
||||
'CDLMARUBOZU', # Marubozu
|
||||
'CDLMATCHINGLOW', # Matching Low
|
||||
'CDLMATHOLD', # Mat Hold
|
||||
'CDLMORNINGDOJISTAR', # Morning Doji Star
|
||||
'CDLMORNINGSTAR', # Morning Star
|
||||
'CDLONNECK', # On-Neck Pattern
|
||||
'CDLPIERCING', # Piercing Pattern
|
||||
'CDLRICKSHAWMAN', # Rickshaw Man
|
||||
'CDLRISEFALL3METHODS', # Rising/Falling Three Methods
|
||||
'CDLSEPARATINGLINES', # Separating Lines
|
||||
'CDLSHOOTINGSTAR', # Shooting Star
|
||||
'CDLSHORTLINE', # Short Line Candle
|
||||
'CDLSPINNINGTOP', # Spinning Top
|
||||
'CDLSTALLEDPATTERN', # Stalled Pattern
|
||||
'CDLSTICKSANDWICH', # Stick Sandwich
|
||||
# Takuri (Dragonfly Doji with very long lower shadow)
|
||||
'CDLTAKURI',
|
||||
'CDLTASUKIGAP', # Tasuki Gap
|
||||
'CDLTHRUSTING', # Thrusting Pattern
|
||||
'CDLTRISTAR', # Tristar Pattern
|
||||
'CDLUNIQUE3RIVER', # Unique 3 River
|
||||
'CDLUPSIDEGAP2CROWS', # Upside Gap Two Crows
|
||||
'CDLXSIDEGAP3METHODS', # Upside/Downside Gap Three Methods
|
||||
|
||||
},
|
||||
'Statistic Functions': {
|
||||
'BETA', # Beta
|
||||
'CORREL', # Pearson's Correlation Coefficient (r)
|
||||
'LINEARREG', # Linear Regression
|
||||
'LINEARREG_ANGLE', # Linear Regression Angle
|
||||
'LINEARREG_INTERCEPT', # Linear Regression Intercept
|
||||
'LINEARREG_SLOPE', # Linear Regression Slope
|
||||
'STDDEV', # Standard Deviation
|
||||
'TSF', # Time Series Forecast
|
||||
'VAR', # Variance
|
||||
}
|
||||
|
||||
}
|
||||
god_genes = set()
|
||||
########################### SETTINGS ##############################
|
||||
|
||||
# god_genes = {'SMA'}
|
||||
god_genes |= all_god_genes['Overlap Studies']
|
||||
god_genes |= all_god_genes['Momentum Indicators']
|
||||
god_genes |= all_god_genes['Volume Indicators']
|
||||
god_genes |= all_god_genes['Volatility Indicators']
|
||||
god_genes |= all_god_genes['Price Transform']
|
||||
god_genes |= all_god_genes['Cycle Indicators']
|
||||
god_genes |= all_god_genes['Pattern Recognition']
|
||||
god_genes |= all_god_genes['Statistic Functions']
|
||||
|
||||
#timeperiods = [5, 6, 12, 15, 50, 55, 100, 110]
|
||||
timeperiods = [5, 10, 20, 50, 100]
|
||||
|
||||
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
|
||||
|
||||
ind_1 = 'HT_TRENDLINE-100'
|
||||
ind_2 = 'MACD-1-100'
|
||||
ind_3 = 'CCI-20'
|
||||
ind_4 = 'CDLDOJISTAR-10'
|
||||
ind_5 = 'WCLPRICE-10'
|
||||
ind_6 = 'DEMA-50'
|
||||
|
||||
sell_1 = "CDLLONGLINE-20"
|
||||
sell_2 = "STOCHF-1-50"
|
||||
sell_3 = "MACDEXT-0-5"
|
||||
sell_4 = "MIDPOINT-10"
|
||||
sell_5 = "CDLTRISTAR-10"
|
||||
sell_6 = "CDLBELTHOLD-50"
|
||||
|
||||
########################### END SETTINGS ##########################
|
||||
# DATAFRAME = DataFrame()
|
||||
|
||||
god_genes = list(god_genes)
|
||||
# print('selected indicators for optimzatin: \n', god_genes)
|
||||
|
||||
god_genes_with_timeperiod = list()
|
||||
for god_gene in god_genes:
|
||||
for timeperiod in timeperiods:
|
||||
# print(f'{god_gene}-{timeperiod}')
|
||||
god_genes_with_timeperiod.append(f'{god_gene}-{timeperiod}')
|
||||
|
||||
# Let give somethings to CatagoricalParam to Play with them
|
||||
# When just one thing is inside catagorical lists
|
||||
# TODO: its Not True Way :)
|
||||
if len(god_genes) == 1:
|
||||
god_genes = god_genes*2
|
||||
if len(timeperiods) == 1:
|
||||
timeperiods = timeperiods*2
|
||||
if len(operators) == 1:
|
||||
operators = operators*2
|
||||
|
||||
|
||||
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):
|
||||
|
||||
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] > dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "=":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "<":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "C":
|
||||
condition = (
|
||||
(qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) |
|
||||
(qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator]))
|
||||
)
|
||||
elif operator == "CA":
|
||||
condition = (
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "CB":
|
||||
condition = (
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == ">R":
|
||||
condition = (
|
||||
dataframe[indicator] > real_num
|
||||
)
|
||||
elif operator == "=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], real_num)
|
||||
)
|
||||
elif operator == "<R":
|
||||
condition = (
|
||||
dataframe[indicator] < real_num
|
||||
)
|
||||
elif operator == "/>R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) > real_num
|
||||
)
|
||||
elif operator == "/=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator].div(
|
||||
dataframe[crossed_indicator]), real_num)
|
||||
)
|
||||
elif operator == "/<R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) < real_num
|
||||
)
|
||||
elif operator == "UT":
|
||||
condition = (
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "DT":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "OT":
|
||||
condition = (
|
||||
|
||||
np.isclose(dataframe[indicator], dataframe[indicator_trend_sma])
|
||||
)
|
||||
elif operator == "CUT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "CDT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "COT":
|
||||
condition = (
|
||||
(
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) |
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
) &
|
||||
(
|
||||
np.isclose(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return condition, dataframe
|
||||
|
||||
|
||||
class GodStraJD3_6_53_1(IStrategy):
|
||||
# #################### RESULTS PASTE PLACE ####################
|
||||
# ROI table:
|
||||
minimal_roi = {
|
||||
"0": 1,
|
||||
# "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'},
|
||||
'min': {'color': 'white'},
|
||||
'max': {'color': 'white'},
|
||||
'sma20': {'color': 'cyan'}
|
||||
},
|
||||
'subplots': {
|
||||
# Subplots - each dict defines one additional plot
|
||||
"BB": {
|
||||
'bb_width': {'color': 'white'},
|
||||
'bb_min': {'color': 'red'},
|
||||
},
|
||||
"Ind": {
|
||||
ind_1: {'color': 'green'},
|
||||
ind_2: {'color': 'blue'},
|
||||
ind_3: {'color': 'red'}
|
||||
},
|
||||
"Ind2": {
|
||||
ind_4: {'color': 'green'},
|
||||
ind_5: {'color': 'blue'},
|
||||
ind_6: {'color': 'red'}
|
||||
},
|
||||
"Profit": {
|
||||
'profit': {'color': 'pink'},
|
||||
},
|
||||
"Rsi": {
|
||||
'rsi': {'color': 'pink'},
|
||||
},
|
||||
# "rolling": {
|
||||
# 'bb_rolling': {'color': '#87e470'},
|
||||
# "bb_rolling_min": {'color': '#ac3e2a'}
|
||||
# },
|
||||
"percent": {
|
||||
"percent": {'color': 'green'},
|
||||
"percent3": {'color': 'blue'},
|
||||
"percent5": {'color': 'red'}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# #################### END OF RESULT PLACE ####################
|
||||
|
||||
# TODO: Its not dry code!
|
||||
# Buy Hyperoptable Parameters/Spaces.
|
||||
buy_crossed_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="ADD-20", space='buy')
|
||||
buy_crossed_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="ASIN-6", space='buy')
|
||||
buy_crossed_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLEVENINGSTAR-50", space='buy')
|
||||
|
||||
buy_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="SMA-100", space='buy')
|
||||
buy_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="WILLR-50", space='buy')
|
||||
buy_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLHANGINGMAN-20", space='buy')
|
||||
|
||||
buy_operator0 = CategoricalParameter(operators, default="/<R", space='buy')
|
||||
buy_operator1 = CategoricalParameter(operators, default="<R", space='buy')
|
||||
buy_operator2 = CategoricalParameter(operators, default="CB", space='buy')
|
||||
|
||||
protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection')
|
||||
protection_stop = IntParameter(0, 100, default=48, space='protection')
|
||||
|
||||
buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.89009, space='buy')
|
||||
buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.56953, space='buy')
|
||||
buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.38365, space='buy')
|
||||
|
||||
# Sell Hyperoptable Parameters/Spaces.
|
||||
sell_crossed_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="CDLSHOOTINGSTAR-150", space='sell')
|
||||
sell_crossed_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="MAMA-1-100", space='sell')
|
||||
sell_crossed_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDLMATHOLD-6", space='sell')
|
||||
|
||||
sell_indicator0 = CategoricalParameter(god_genes_with_timeperiod, default="CDLUPSIDEGAP2CROWS-5", space='sell')
|
||||
sell_indicator1 = CategoricalParameter(god_genes_with_timeperiod, default="CDLHARAMICROSS-150", space='sell')
|
||||
sell_indicator2 = CategoricalParameter(god_genes_with_timeperiod, default="CDL2CROWS-5", space='sell')
|
||||
|
||||
sell_operator0 = CategoricalParameter(operators, default="<R", space='sell')
|
||||
sell_operator1 = CategoricalParameter(operators, default="D", space='sell')
|
||||
sell_operator2 = CategoricalParameter(operators, default="/>R", space='sell')
|
||||
|
||||
sell_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.09731, space='sell')
|
||||
sell_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.81657, space='sell')
|
||||
sell_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.87267, space='sell')
|
||||
|
||||
@property
|
||||
def protections(self):
|
||||
return [
|
||||
{
|
||||
"method": "CooldownPeriod",
|
||||
"stop_duration_candles": 10
|
||||
},
|
||||
{
|
||||
"method": "MaxDrawdown",
|
||||
"lookback_period_candles": 48,
|
||||
"trade_limit": 2,
|
||||
"stop_duration_candles": self.protection_stop.value,
|
||||
"max_allowed_drawdown": self.protection_max_allowed_dd.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()
|
||||
#print("last_candle", last_candle)
|
||||
#print("previous_last_candle", previous_last_candle)
|
||||
|
||||
#dataframe.iloc[-1]['profit'] = current_profit
|
||||
count = 0
|
||||
for coin, balance in self.wallets.get_all_balances().items():
|
||||
count = count + 1
|
||||
# print(coin, " ", balance)
|
||||
# print("count=", count)
|
||||
|
||||
if (current_profit > 0) \
|
||||
& ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.002) \
|
||||
| (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 (current_profit > 0) \
|
||||
& ((current_time - trade.open_date_utc).seconds >= 3600) \
|
||||
& ((previous_last_candle['sma20'] > last_candle['sma20']) &
|
||||
((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 (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['percent'] < 0) & (last_candle['percent3'] < 0)):
|
||||
# print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
|
||||
return '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['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 (current_profit > 0) \
|
||||
& (last_candle['rsi'] > 88): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)):
|
||||
# print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
|
||||
return 'over_rsi'
|
||||
|
||||
def informative_pairs(self):
|
||||
return []
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
# MACD
|
||||
# macd = ta.MACD(dataframe)
|
||||
# dataframe['macd'] = macd['macd']
|
||||
# dataframe['macdsignal'] = macd['macdsignal']
|
||||
# dataframe['macdhist'] = macd['macdhist']
|
||||
|
||||
# # # Plus Directional Indicator / Movement
|
||||
# dataframe['plus_dm'] = ta.PLUS_DM(dataframe)
|
||||
# dataframe['plus_di'] = ta.PLUS_DI(dataframe)
|
||||
#
|
||||
# # Minus Directional Indicator / Movement
|
||||
# dataframe['adx'] = ta.ADX(dataframe)
|
||||
|
||||
dataframe[ind_1] = gene_calculator(dataframe, ind_1)
|
||||
dataframe[ind_2] = gene_calculator(dataframe, ind_2)
|
||||
dataframe[ind_3] = gene_calculator(dataframe, ind_3)
|
||||
|
||||
dataframe[ind_4] = gene_calculator(dataframe, ind_4)
|
||||
dataframe[ind_5] = gene_calculator(dataframe, ind_5)
|
||||
dataframe[ind_6] = gene_calculator(dataframe, ind_6)
|
||||
|
||||
dataframe[sell_1] = gene_calculator(dataframe, sell_1)
|
||||
dataframe[sell_2] = gene_calculator(dataframe, sell_2)
|
||||
dataframe[sell_3] = gene_calculator(dataframe, sell_3)
|
||||
|
||||
dataframe[sell_4] = gene_calculator(dataframe, sell_4)
|
||||
dataframe[sell_5] = gene_calculator(dataframe, sell_5)
|
||||
dataframe[sell_6] = gene_calculator(dataframe, sell_6)
|
||||
|
||||
# dataframe['MINUS_DM-5'] = ta.MINUS_DM(dataframe, timeperiod=5)
|
||||
# dataframe['LINEARREG-50'] = ta.LINEARREG(dataframe, timeperiod=50)
|
||||
# dataframe['MA-20'] = ta.MA(dataframe, timeperiod=20)
|
||||
# stoch = ta.STOCH(dataframe, timeperiod=10)
|
||||
# # print(stoch)
|
||||
# dataframe['STOCH-1-10'] = stoch['slowd']
|
||||
# dataframe['CDLDRAGONFLYDOJI-5'] = ta.CDLDRAGONFLYDOJI(dataframe, timeperiod=5)
|
||||
|
||||
# dataframe['minus_di'] = ta.MINUS_DI(dataframe)
|
||||
|
||||
# dataframe['min'] = ta.MIN(dataframe)
|
||||
# dataframe['max'] = ta.MAX(dataframe)
|
||||
|
||||
# # Aroon, Aroon Oscillator
|
||||
# aroon = ta.AROON(dataframe)
|
||||
# dataframe['aroonup'] = aroon['aroonup']
|
||||
# dataframe['aroondown'] = aroon['aroondown']
|
||||
# dataframe['aroonosc'] = ta.AROONOSC(dataframe)
|
||||
|
||||
dataframe['profit'] = 0
|
||||
# RSI
|
||||
dataframe['rsi'] = ta.RSI(dataframe)
|
||||
|
||||
# # EMA - Exponential Moving Average
|
||||
# dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
|
||||
# dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5)
|
||||
# dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10)
|
||||
# dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21)
|
||||
# dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)
|
||||
# dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100)
|
||||
|
||||
# # SMA - Simple Moving Average
|
||||
# dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3)
|
||||
# dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5)
|
||||
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['sma200'] = ta.SMA(dataframe, timeperiod=200)
|
||||
# dataframe['sma200_95'] = ta.SMA(dataframe, timeperiod=200) * 0.95
|
||||
# dataframe['sma200_98'] = ta.SMA(dataframe, timeperiod=200) * 0.98
|
||||
# dataframe['sma500'] = ta.SMA(dataframe, timeperiod=500)
|
||||
# dataframe['sma500_90'] = ta.SMA(dataframe, timeperiod=500) * 0.9
|
||||
# dataframe['sma500_95'] = ta.SMA(dataframe, timeperiod=500) * 0.95
|
||||
# dataframe['sma500_20'] = ta.SMA(dataframe, timeperiod=500) * 0.2
|
||||
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['min'] = ta.MIN(dataframe['close'], timeperiod=200)
|
||||
dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20)
|
||||
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_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36)
|
||||
|
||||
# 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"]
|
||||
# )
|
||||
|
||||
# # EMA - Exponential Moving Average
|
||||
# dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
|
||||
# TODO: Its not dry code!
|
||||
buy_indicator = self.buy_indicator0.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator0.value
|
||||
buy_operator = self.buy_operator0.value
|
||||
buy_real_num = self.buy_real_num0.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
# backup
|
||||
buy_indicator = self.buy_indicator1.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator1.value
|
||||
buy_operator = self.buy_operator1.value
|
||||
buy_real_num = self.buy_real_num1.value
|
||||
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
buy_indicator = self.buy_indicator2.value
|
||||
buy_crossed_indicator = self.buy_crossed_indicator2.value
|
||||
buy_operator = self.buy_operator2.value
|
||||
buy_real_num = self.buy_real_num2.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator,
|
||||
buy_indicator,
|
||||
buy_crossed_indicator,
|
||||
buy_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['close'].shift(2) < dataframe['bb_lowerband'].shift(2))
|
||||
& (dataframe['bb_width'].shift(2) >= 0.12)
|
||||
& (dataframe['volume'].shift(2) * dataframe['close'].shift(2) / 1000 > 100)
|
||||
) | (
|
||||
(reduce(lambda x, y: x & y, conditions))
|
||||
& (dataframe['volume10'] * dataframe['close'] / 1000 >= 100)
|
||||
& (dataframe['close'] < dataframe['sma20'])
|
||||
& (dataframe['close'] < dataframe['sma50'])
|
||||
# & (dataframe['sma10'].shift(1) <= dataframe['sma10'])
|
||||
# (dataframe['close'] * 0.99 < dataframe['bb_lowerband'])
|
||||
# (dataframe['rsi'] < 45)
|
||||
),
|
||||
'buy']=1
|
||||
# print(len(dataframe.keys()))
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
# TODO: Its not dry code!
|
||||
sell_indicator = self.sell_indicator0.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator0.value
|
||||
sell_operator = self.sell_operator0.value
|
||||
sell_real_num = self.sell_real_num0.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
sell_indicator = self.sell_indicator1.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator1.value
|
||||
sell_operator = self.sell_operator1.value
|
||||
sell_real_num = self.sell_real_num1.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
sell_indicator = self.sell_indicator2.value
|
||||
sell_crossed_indicator = self.sell_crossed_indicator2.value
|
||||
sell_operator = self.sell_operator2.value
|
||||
sell_real_num = self.sell_real_num2.value
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
sell_operator,
|
||||
sell_indicator,
|
||||
sell_crossed_indicator,
|
||||
sell_real_num
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
#dataframe.loc[(dataframe['close'] < dataframe['bb_lowerband']),'sell']=1
|
||||
|
||||
# count = 0
|
||||
# for coin, balance in self.wallets.get_all_balances().items():
|
||||
# count = count + 1
|
||||
# # print(coin, " ", balance)
|
||||
# if (count == self.config['max_open_trades']) & (current_profit < -0.04) \
|
||||
# & ((current_time - trade.open_date_utc).seconds >= 3600 * 6):
|
||||
# self.lock_pair(pair, until=current_time + timedelta(hours=10))
|
||||
# print("stop_short_loss", pair, trade, " profit=", current_profit, " rate=", current_rate,
|
||||
# "count=", count, "max=", self.config['max_open_trades'])
|
||||
# return 'stop_short_loss'
|
||||
|
||||
# print("sell pair=", self.wallets.get_all_balances()[metadata['pair']])
|
||||
|
||||
# if conditions:
|
||||
# dataframe.loc[
|
||||
# (
|
||||
# reduce(lambda x, y: x & y, conditions) #(dataframe['percent3'] > 0)
|
||||
# # | (dataframe['percent3'] < -0.03)
|
||||
# ),
|
||||
# 'sell']=1
|
||||
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['close'] < dataframe['open']) &
|
||||
(dataframe['close'].shift(1) < dataframe['open'].shift(1)) &
|
||||
(dataframe['close'].shift(2) < dataframe['open'].shift(2)) &
|
||||
(dataframe['close'] < dataframe['bb_lowerband']) &
|
||||
(((dataframe['bb_lowerband'].shift(2) - dataframe['bb_lowerband']) / dataframe['bb_lowerband']) >= 0.02)
|
||||
# (((dataframe['close'].shift(1) - dataframe['close']) / dataframe['close']) >= 0.025)
|
||||
), 'sell'] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
29
GodStraJD3_6_53_2.json
Normal file
29
GodStraJD3_6_53_2.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_6_53_2",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 2
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -0.02
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.15,
|
||||
"trailing_stop_positive_offset": 0.2,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_real_num0": 0.87,
|
||||
"buy_real_num1": 0.33,
|
||||
"buy_real_num2": 0.89
|
||||
},
|
||||
"sell": {},
|
||||
"protection": {
|
||||
"protection_max_allowed_dd": 0.04,
|
||||
"protection_stop": 288
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-01-23 13:16:55.016896+00:00"
|
||||
}
|
||||
520
GodStraJD3_6_53_2.py
Normal file
520
GodStraJD3_6_53_2.py
Normal file
@@ -0,0 +1,520 @@
|
||||
# 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 freqtrade import data
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.strategy.parameters import CategoricalParameter, DecimalParameter, IntParameter
|
||||
|
||||
from numpy.lib import math
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
from pandas import DataFrame
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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_crossed_indicator1 = 'DX-5'
|
||||
buy_crossed_indicator2 = 'LINEARREG-50'
|
||||
buy_indicator0 = 'MA-20'
|
||||
buy_indicator1 = 'STOCH-1-10'
|
||||
buy_indicator2 = 'CDLDRAGONFLYDOJI-5'
|
||||
buy_operator0 = "/<R"
|
||||
buy_operator1 = ">"
|
||||
buy_operator2 = "/<R"
|
||||
|
||||
|
||||
# buy_real_num0 = 0.1,
|
||||
# buy_real_num1 = 0.0,
|
||||
# buy_real_num2 = 0.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):
|
||||
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] > dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "=":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "<":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "C":
|
||||
condition = (
|
||||
(qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) |
|
||||
(qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator]))
|
||||
)
|
||||
elif operator == "CA":
|
||||
condition = (
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "CB":
|
||||
condition = (
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == ">R":
|
||||
condition = (
|
||||
dataframe[indicator] > real_num
|
||||
)
|
||||
elif operator == "=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], real_num)
|
||||
)
|
||||
elif operator == "<R":
|
||||
condition = (
|
||||
dataframe[indicator] < real_num
|
||||
)
|
||||
elif operator == "/>R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) > real_num
|
||||
)
|
||||
elif operator == "/=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator].div(
|
||||
dataframe[crossed_indicator]), real_num)
|
||||
)
|
||||
elif operator == "/<R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) < real_num
|
||||
)
|
||||
elif operator == "UT":
|
||||
condition = (
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "DT":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "OT":
|
||||
condition = (
|
||||
|
||||
np.isclose(dataframe[indicator], dataframe[indicator_trend_sma])
|
||||
)
|
||||
elif operator == "CUT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "CDT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "COT":
|
||||
condition = (
|
||||
(
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) |
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
) &
|
||||
(
|
||||
np.isclose(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return condition, dataframe
|
||||
|
||||
|
||||
class GodStraJD3_6_53_2(IStrategy):
|
||||
# #################### RESULTS PASTE PLACE ####################
|
||||
# ROI table:
|
||||
minimal_roi = {
|
||||
"0": 2,
|
||||
# "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'},
|
||||
'min': {'color': 'white'},
|
||||
'max': {'color': 'white'},
|
||||
'sma20': {'color': 'cyan'}
|
||||
},
|
||||
'subplots': {
|
||||
# Subplots - each dict defines one additional plot
|
||||
"BB": {
|
||||
'bb_width': {'color': 'white'},
|
||||
'bb_min': {'color': 'red'},
|
||||
},
|
||||
"Ind0": {
|
||||
buy_crossed_indicator0: {'color': 'green'},
|
||||
buy_indicator0: {'color': 'red'}
|
||||
},
|
||||
"Ind1": {
|
||||
buy_indicator1: {'color': 'yellow'},
|
||||
buy_crossed_indicator1: {'color': 'pink'}
|
||||
},
|
||||
"Ind2": {
|
||||
buy_indicator2: {'color': 'cyan'},
|
||||
buy_crossed_indicator2: {'color': 'blue'},
|
||||
},
|
||||
"Rsi": {
|
||||
'rsi': {'color': 'pink'},
|
||||
},
|
||||
# "rolling": {
|
||||
# 'bb_rolling': {'color': '#87e470'},
|
||||
# "bb_rolling_min": {'color': '#ac3e2a'}
|
||||
# },
|
||||
"percent": {
|
||||
"percent": {'color': 'green'},
|
||||
"percent3": {'color': 'blue'},
|
||||
"percent5": {'color': 'red'}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# #################### END OF RESULT PLACE ####################
|
||||
|
||||
# TODO: Its not dry code!
|
||||
# Buy Hyperoptable Parameters/Spaces.
|
||||
buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.1, space='buy')
|
||||
buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.0, space='buy')
|
||||
buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.5, space='buy')
|
||||
|
||||
protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection')
|
||||
protection_stop = IntParameter(0, 100, default=48, space='protection')
|
||||
|
||||
|
||||
@property
|
||||
def protections(self):
|
||||
return [
|
||||
{
|
||||
"method": "CooldownPeriod",
|
||||
"stop_duration_candles": 10
|
||||
},
|
||||
{
|
||||
"method": "MaxDrawdown",
|
||||
"lookback_period_candles": 48,
|
||||
"trade_limit": 2,
|
||||
"stop_duration_candles": self.protection_stop.value,
|
||||
"max_allowed_drawdown": self.protection_max_allowed_dd.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 (current_profit > 0) \
|
||||
& ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \
|
||||
| (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 (current_profit > 0.01) \
|
||||
& ((previous_5_candle['sma20'] > last_candle['sma20']) &
|
||||
((last_candle['percent10'] < -0.01) | (last_candle['percent20'] < -0.01))):
|
||||
# print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
|
||||
return 'sma20'
|
||||
|
||||
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.0105)) \
|
||||
& ((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 (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 (current_profit > 0) \
|
||||
& (last_candle['rsi'] > 88): #| (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) \
|
||||
# & (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):
|
||||
return []
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
dataframe[buy_crossed_indicator0] = gene_calculator(dataframe, buy_crossed_indicator0)
|
||||
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[buy_crossed_indicator1] = gene_calculator(dataframe, buy_crossed_indicator1)
|
||||
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['min'] = ta.MIN(dataframe['close'], timeperiod=200)
|
||||
dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20)
|
||||
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_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36)
|
||||
|
||||
# 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"]
|
||||
)
|
||||
|
||||
# # EMA - Exponential Moving Average
|
||||
# dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator0,
|
||||
buy_indicator0,
|
||||
buy_crossed_indicator0,
|
||||
self.buy_real_num0.value
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
# backup
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator1,
|
||||
buy_indicator1,
|
||||
buy_crossed_indicator1,
|
||||
self.buy_real_num1.value
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
condition, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator2,
|
||||
buy_indicator2,
|
||||
buy_crossed_indicator2,
|
||||
self.buy_real_num2.value
|
||||
)
|
||||
conditions.append(condition)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
(
|
||||
(reduce(lambda x, y: x & y, conditions)) &
|
||||
(dataframe['volume10'] * dataframe['close'] / 1000 >= 10)
|
||||
# (dataframe['rsi'] < 45)
|
||||
),
|
||||
'buy'] = 1
|
||||
# print(len(dataframe.keys()))
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
return dataframe
|
||||
33
GodStraJD3_7.json
Normal file
33
GodStraJD3_7.json
Normal file
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_7",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.15,
|
||||
"trailing_stop_positive_offset": 0.2,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"profit_no_change": false,
|
||||
"profit_old_sma10": false,
|
||||
"profit_over_rsi": true,
|
||||
"profit_quick_gain": false,
|
||||
"profit_quick_gain_3": false,
|
||||
"profit_quick_lost": true,
|
||||
"profit_short_loss": true,
|
||||
"profit_sma10": false,
|
||||
"profit_sma20": true,
|
||||
"profit_very_old_sma10": true
|
||||
},
|
||||
"sell": {},
|
||||
"protection": {}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-02-04 20:21:28.189888+00:00"
|
||||
}
|
||||
636
GodStraJD3_7.py
Normal file
636
GodStraJD3_7.py
Normal file
@@ -0,0 +1,636 @@
|
||||
# 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 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
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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'
|
||||
|
||||
# "buy_real_num0": 0.46,
|
||||
# "buy_real_num1": 0.48,
|
||||
# "buy_real_num2": 0.67
|
||||
|
||||
|
||||
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):
|
||||
|
||||
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] > dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "=":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "<":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[crossed_indicator]
|
||||
)
|
||||
elif operator == "C":
|
||||
condition = (
|
||||
(qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) |
|
||||
(qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator]))
|
||||
)
|
||||
elif operator == "CA":
|
||||
condition = (
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == "CB":
|
||||
condition = (
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator], dataframe[crossed_indicator])
|
||||
)
|
||||
elif operator == ">R":
|
||||
condition = (
|
||||
dataframe[indicator] > real_num
|
||||
)
|
||||
elif operator == "=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator], real_num)
|
||||
)
|
||||
elif operator == "<R":
|
||||
condition = (
|
||||
dataframe[indicator] < real_num
|
||||
)
|
||||
elif operator == "/>R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) > real_num
|
||||
)
|
||||
elif operator == "/=R":
|
||||
condition = (
|
||||
np.isclose(dataframe[indicator].div(
|
||||
dataframe[crossed_indicator]), real_num)
|
||||
)
|
||||
elif operator == "/<R":
|
||||
condition = (
|
||||
dataframe[indicator].div(dataframe[crossed_indicator]) < real_num
|
||||
)
|
||||
elif operator == "UT":
|
||||
condition = (
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "DT":
|
||||
condition = (
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
elif operator == "OT":
|
||||
condition = (
|
||||
|
||||
np.isclose(dataframe[indicator], dataframe[indicator_trend_sma])
|
||||
)
|
||||
elif operator == "CUT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "CDT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "COT":
|
||||
condition = (
|
||||
(
|
||||
(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
) |
|
||||
(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
) &
|
||||
(
|
||||
np.isclose(
|
||||
dataframe[indicator],
|
||||
dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
)
|
||||
return condition, dataframe
|
||||
|
||||
|
||||
class GodStraJD3_7(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'},
|
||||
# 'min': {'color': 'white'},
|
||||
# 'max': {'color': 'white'},
|
||||
'sma20': {'color': 'cyan'}
|
||||
},
|
||||
'subplots': {
|
||||
# Subplots - each dict defines one additional plot
|
||||
"BB": {
|
||||
'bb_width': {'color': 'white'},
|
||||
'bb_min': {'color': 'red'},
|
||||
},
|
||||
"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'},
|
||||
},
|
||||
# "rolling": {
|
||||
# 'bb_rolling': {'color': '#87e470'},
|
||||
# "bb_rolling_min": {'color': '#ac3e2a'}
|
||||
# },
|
||||
# "percent": {
|
||||
# "percent": {'color': 'green'},
|
||||
# "percent3": {'color': 'blue'},
|
||||
# "percent5": {'color': 'red'}
|
||||
# }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# #################### END OF RESULT PLACE ####################
|
||||
|
||||
# TODO: Its not dry code!
|
||||
# Buy Hyperoptable Parameters/Spaces.
|
||||
# "buy_real_num0": 0.46,
|
||||
# "buy_real_num1": 0.48,
|
||||
# "buy_real_num2": 0.67
|
||||
#
|
||||
# buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.46, space='buy')
|
||||
# buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.48, space='buy')
|
||||
# buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.67, space='buy')
|
||||
|
||||
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")
|
||||
|
||||
# protection_max_allowed_dd = DecimalParameter(0, 1, decimals=DECIMALS, default=0.04, space='protection')
|
||||
# protection_stop = IntParameter(0, 100, default=48, space='protection')
|
||||
# protection_stoploss_stop = IntParameter(0, 100, default=48, space='protection')
|
||||
# lookback = IntParameter(0, 200, default=48, space='protection')
|
||||
# trade_limit = IntParameter(0, 10, default=2, space='protection')
|
||||
#
|
||||
# @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 self.profit_quick_lost.value:
|
||||
if (current_profit >= 0) & (last_candle['percent3'] < -0.01):
|
||||
return "quick_lost"
|
||||
|
||||
if self.profit_no_change.value:
|
||||
if (current_profit > 0.005) & (last_candle['percent10'] < 0.001):
|
||||
return "no_change"
|
||||
|
||||
#if (current_profit > 0.01) & (last_candle['rsi'] < 30):
|
||||
# return "small_rsi"
|
||||
if self.profit_quick_gain_3.value:
|
||||
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.value:
|
||||
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.value:
|
||||
if (current_profit > 0.01) \
|
||||
& ((previous_5_candle['sma10'] > last_candle['sma10'] * 1.005) \
|
||||
| (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.value:
|
||||
if (current_profit > 0.005) & (last_candle['percent5'] < 0) \
|
||||
& ((current_time - trade.open_date_utc).seconds >= 3600) \
|
||||
& ((previous_last_candle['sma20'] > last_candle['sma20']) &
|
||||
((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.value:
|
||||
# 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.value:
|
||||
# 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.value:
|
||||
if (current_profit > 0) \
|
||||
& (last_candle['rsi'] > 88): #| (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)):
|
||||
# print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
|
||||
return 'over_rsi'
|
||||
|
||||
if self.profit_short_loss.value:
|
||||
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):
|
||||
return []
|
||||
|
||||
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['min'] = ta.MIN(dataframe['close'], timeperiod=200)
|
||||
dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20)
|
||||
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_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36)
|
||||
|
||||
# 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])
|
||||
|
||||
# # EMA - Exponential Moving Average
|
||||
# dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
|
||||
condition1, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator0,
|
||||
buy_indicator0,
|
||||
buy_crossed_indicator0,
|
||||
0.7 #self.buy_real_num0.value
|
||||
)
|
||||
conditions.append(condition1)
|
||||
|
||||
# # backup
|
||||
# condition2, dataframe = condition_generator(
|
||||
# dataframe,
|
||||
# buy_operator1,
|
||||
# buy_indicator1,
|
||||
# buy_crossed_indicator1,
|
||||
# self.buy_real_num1.value
|
||||
# )
|
||||
# conditions.append(condition2)
|
||||
#
|
||||
# condition3, dataframe = condition_generator(
|
||||
# dataframe,
|
||||
# buy_operator2,
|
||||
# buy_indicator2,
|
||||
# buy_crossed_indicator2,
|
||||
# self.buy_real_num2.value
|
||||
# )
|
||||
# conditions.append(condition3)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
(
|
||||
reduce(lambda x, y: x & y, conditions)
|
||||
& (dataframe['volume10'] * dataframe['close'] / 1000 >= 10)
|
||||
& (dataframe['close'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma10'])
|
||||
& (dataframe['low'] < dataframe['min20'])
|
||||
# ) | (
|
||||
# (dataframe['volume10'] * dataframe['close'] / 1000 >= 10)
|
||||
# & (dataframe['percent20'] < -0.01)
|
||||
# & (dataframe['percent3'] > 0)
|
||||
# & (dataframe['close'] < dataframe['sma10'])
|
||||
# & (dataframe['sma100'].shift(1) < dataframe['sma100'])
|
||||
#
|
||||
# ) | (
|
||||
# (dataframe['volume10'].shift(1) * dataframe['close'].shift(1) / 1000 >= 10)
|
||||
# & (dataframe['percent20'].shift(1) < -0.01)
|
||||
# & (dataframe['percent3'].shift(1) > 0)
|
||||
# & (dataframe['close'].shift(1) < dataframe['sma10'].shift(1))
|
||||
# & (dataframe['sma100'].shift(1) < dataframe['sma100'])
|
||||
# # & (dataframe['pente5'].shift(1) > 0)
|
||||
), 'buy'] = 1
|
||||
|
||||
pandas.set_option('display.max_rows', dataframe.shape[0] + 1)
|
||||
pandas.set_option('display.max_columns', 30)
|
||||
# print(condition1)
|
||||
|
||||
# print(reduce(lambda x, y: x & y, conditions))
|
||||
# print(reduce(lambda x, y: x & y, condition1), " ",
|
||||
# reduce(lambda x, y: x & y, condition2), " ",
|
||||
# reduce(lambda x, y: x & y, condition3), " ",
|
||||
# # (reduce(lambda x, y: x & y, conditions))
|
||||
# dataframe['buy'],
|
||||
#
|
||||
# )
|
||||
|
||||
# if conditions:
|
||||
# dataframe.loc[
|
||||
# (
|
||||
# reduce(lambda x, y: x & y, conditions)
|
||||
# # & (dataframe['volume10'] * dataframe['close'] / 1000 >= 100)
|
||||
# # & (dataframe['percent5'] < 0.025)
|
||||
# # (dataframe['percent10'] < 0.04)
|
||||
# # ) | (
|
||||
# # (dataframe['volume10'] * dataframe['close'] / 1000 >= 100)
|
||||
# # & (dataframe['percent50'] < -0.06)
|
||||
# # & (dataframe['percent3'] > 0)
|
||||
# # # & (dataframe['sma10'].shift(12) > dataframe['sma10'].shift(2))
|
||||
# # & (dataframe['sma10'].shift(2) > dataframe['sma10'].shift(1))
|
||||
# # & (dataframe['sma10'].shift(1) < dataframe['sma10'])
|
||||
# # # & (dataframe['sma100'].shift(1) < dataframe['sma100'])
|
||||
# )
|
||||
# #(dataframe['percent3'] > 0))
|
||||
# ,'buy']=1
|
||||
# print(len(dataframe.keys()))
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
return dataframe
|
||||
|
||||
31
GodStraJD3_7_1.json
Normal file
31
GodStraJD3_7_1.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_7_1",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.15,
|
||||
"trailing_stop_positive_offset": 0.2,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_real_num0": 0.5,
|
||||
"buy_signal_bb_width": 0.029
|
||||
},
|
||||
"sell": {},
|
||||
"protection": {
|
||||
"lookback": 124,
|
||||
"protection_max_allowed_dd": 0.85,
|
||||
"protection_stop": 26,
|
||||
"protection_stoploss_stop": 91,
|
||||
"trade_limit": 3
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-02-18 23:22:31.726399+00:00"
|
||||
}
|
||||
540
GodStraJD3_7_1.py
Normal file
540
GodStraJD3_7_1.py
Normal file
@@ -0,0 +1,540 @@
|
||||
# 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 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
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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'
|
||||
|
||||
# "buy_real_num0": 0.46,
|
||||
# "buy_real_num1": 0.48,
|
||||
# "buy_real_num2": 0.67
|
||||
|
||||
|
||||
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):
|
||||
|
||||
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] > dataframe[crossed_indicator])
|
||||
elif operator == "=":
|
||||
condition = (np.isclose(dataframe[indicator], dataframe[crossed_indicator]))
|
||||
elif operator == "<":
|
||||
condition = (dataframe[indicator] < dataframe[crossed_indicator])
|
||||
elif operator == "C":
|
||||
condition = (
|
||||
(qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator])) |
|
||||
(qtpylib.crossed_above(dataframe[indicator], dataframe[crossed_indicator]))
|
||||
)
|
||||
elif operator == "CA":
|
||||
condition = (qtpylib.crossed_above(dataframe[indicator], dataframe[crossed_indicator]))
|
||||
elif operator == "CB":
|
||||
condition = (qtpylib.crossed_below(dataframe[indicator], dataframe[crossed_indicator]))
|
||||
elif operator == ">R":
|
||||
condition = (dataframe[indicator] > real_num)
|
||||
elif operator == "=R":
|
||||
condition = (np.isclose(dataframe[indicator], real_num))
|
||||
elif operator == "<R":
|
||||
condition = (dataframe[indicator] < real_num)
|
||||
elif operator == "/>R":
|
||||
condition = (dataframe[indicator].div(dataframe[crossed_indicator]) > real_num)
|
||||
elif operator == "/=R":
|
||||
condition = (np.isclose(dataframe[indicator].div(dataframe[crossed_indicator]), real_num))
|
||||
elif operator == "/<R":
|
||||
condition = (dataframe[indicator].div(dataframe[crossed_indicator]) < real_num)
|
||||
elif operator == "UT":
|
||||
condition = (dataframe[indicator] > dataframe[indicator_trend_sma])
|
||||
elif operator == "DT":
|
||||
condition = (dataframe[indicator] < dataframe[indicator_trend_sma])
|
||||
elif operator == "OT":
|
||||
condition = (np.isclose(dataframe[indicator], dataframe[indicator_trend_sma]))
|
||||
elif operator == "CUT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_above(dataframe[indicator], dataframe[indicator_trend_sma])
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] > dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "CDT":
|
||||
condition = (
|
||||
(
|
||||
qtpylib.crossed_below(dataframe[indicator], dataframe[indicator_trend_sma])
|
||||
) &
|
||||
(
|
||||
dataframe[indicator] < dataframe[indicator_trend_sma]
|
||||
)
|
||||
)
|
||||
elif operator == "COT":
|
||||
condition = (
|
||||
(
|
||||
(
|
||||
qtpylib.crossed_below(dataframe[indicator], dataframe[indicator_trend_sma])
|
||||
) |
|
||||
(
|
||||
qtpylib.crossed_above(dataframe[indicator], dataframe[indicator_trend_sma])
|
||||
)
|
||||
) &
|
||||
(
|
||||
np.isclose(dataframe[indicator], dataframe[indicator_trend_sma])
|
||||
)
|
||||
)
|
||||
return condition, dataframe
|
||||
|
||||
|
||||
class GodStraJD3_7_1(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'},
|
||||
# 'min': {'color': 'white'},
|
||||
# 'max': {'color': 'white'},
|
||||
'sma20': {'color': 'cyan'}
|
||||
},
|
||||
'subplots': {
|
||||
# Subplots - each dict defines one additional plot
|
||||
"BB": {
|
||||
'bb_width': {'color': 'white'},
|
||||
'bb_min': {'color': 'red'},
|
||||
},
|
||||
"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'},
|
||||
},
|
||||
# "rolling": {
|
||||
# 'bb_rolling': {'color': '#87e470'},
|
||||
# "bb_rolling_min": {'color': '#ac3e2a'}
|
||||
# },
|
||||
# "percent": {
|
||||
# "percent": {'color': 'green'},
|
||||
# "percent3": {'color': 'blue'},
|
||||
# "percent5": {'color': 'red'}
|
||||
# }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# #################### END OF RESULT PLACE ####################
|
||||
|
||||
# TODO: Its not dry code!
|
||||
# Buy Hyperoptable Parameters/Spaces.
|
||||
# "buy_real_num0": 0.46,
|
||||
# "buy_real_num1": 0.48,
|
||||
# "buy_real_num2": 0.67
|
||||
#
|
||||
# buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.46, space='buy')
|
||||
# buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.48, space='buy')
|
||||
# buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.67, space='buy')
|
||||
|
||||
profit_no_change = False
|
||||
profit_old_sma10 = False
|
||||
profit_over_rsi = True
|
||||
profit_quick_gain = True
|
||||
profit_quick_gain_3 = True
|
||||
profit_quick_lost = True
|
||||
profit_short_loss = True
|
||||
profit_sma10 = False
|
||||
profit_sma20 = True
|
||||
profit_very_old_sma10 = False
|
||||
|
||||
# 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, 0.15, decimals=3, default=0.05, space='buy')
|
||||
buy_real_num0 = DecimalParameter(0, 1, decimals=2, default=0.67, 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')
|
||||
|
||||
@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 self.profit_quick_lost:
|
||||
if (current_profit >= 0) & (last_candle['percent3'] < -0.01):
|
||||
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.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'] * 1.005) \
|
||||
| (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) & (last_candle['percent5'] < 0) \
|
||||
& ((current_time - trade.open_date_utc).seconds >= 3600) \
|
||||
& ((previous_last_candle['sma20'] > last_candle['sma20']) &
|
||||
((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 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):
|
||||
return []
|
||||
|
||||
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['min'] = ta.MIN(dataframe['close'], timeperiod=200)
|
||||
dataframe['min20'] = ta.MIN(dataframe['close'], timeperiod=20)
|
||||
dataframe['min50'] = ta.MIN(dataframe['close'], timeperiod=50)
|
||||
|
||||
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_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36)
|
||||
|
||||
# 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])
|
||||
|
||||
# # EMA - Exponential Moving Average
|
||||
# dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
|
||||
condition1, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator0,
|
||||
buy_indicator0,
|
||||
buy_crossed_indicator0,
|
||||
self.buy_real_num0.value
|
||||
)
|
||||
conditions.append(condition1)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
(
|
||||
reduce(lambda x, y: x & y, conditions)
|
||||
& (dataframe['volume10'] * dataframe['close'] / 1000 >= 10)
|
||||
& (dataframe['close'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma10'])
|
||||
& (dataframe['low'] < dataframe['min50'])
|
||||
& (dataframe['bb_width'] > self.buy_signal_bb_width.value)
|
||||
), 'buy'] = 1
|
||||
|
||||
pandas.set_option('display.max_rows', dataframe.shape[0] + 1)
|
||||
pandas.set_option('display.max_columns', 30)
|
||||
# print(condition1)
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
return dataframe
|
||||
|
||||
32
GodStraJD3_7_2.json
Normal file
32
GodStraJD3_7_2.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_7_2",
|
||||
"params": {
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": true,
|
||||
"trailing_stop_positive": 0.042,
|
||||
"trailing_stop_positive_offset": 0.119,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_decalage0": 6,
|
||||
"buy_real_num0": 0.9,
|
||||
"buy_signal_bb_width": 0.0
|
||||
},
|
||||
"sell": {},
|
||||
"protection": {
|
||||
"lookback": 133,
|
||||
"protection_max_allowed_dd": 0.71,
|
||||
"protection_stop": 61,
|
||||
"protection_stoploss_stop": 50,
|
||||
"trade_limit": 9
|
||||
},
|
||||
"roi": {
|
||||
"0": 2
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-03-07 17:59:59.847942+00:00"
|
||||
}
|
||||
606
GodStraJD3_7_2.py
Normal file
606
GodStraJD3_7_2.py
Normal file
@@ -0,0 +1,606 @@
|
||||
# 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 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
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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'
|
||||
|
||||
|
||||
# "buy_real_num0": 0.46,
|
||||
# "buy_real_num1": 0.48,
|
||||
# "buy_real_num2": 0.67
|
||||
|
||||
|
||||
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_2(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": {
|
||||
'ecart_20': {'color': 'red'},
|
||||
'ecart_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 ####################
|
||||
|
||||
# TODO: Its not dry code!
|
||||
# Buy Hyperoptable Parameters/Spaces.
|
||||
# "buy_real_num0": 0.46,
|
||||
# "buy_real_num1": 0.48,
|
||||
# "buy_real_num2": 0.67
|
||||
#
|
||||
# buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.46, space='buy')
|
||||
# buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.48, space='buy')
|
||||
# buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.67, space='buy')
|
||||
|
||||
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 = False
|
||||
profit_sma20 = True
|
||||
profit_very_old_sma10 = False
|
||||
|
||||
# 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, 0.15, decimals=2, default=0.05, space='buy')
|
||||
buy_real_num0 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy')
|
||||
buy_decalage0 = IntParameter(1, 10, default=5, 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')
|
||||
|
||||
@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 (current_profit >= -0.01) & ((current_time - trade.open_date_utc).days >= 5) \
|
||||
& ((current_time - trade.open_date_utc).days < 10) \
|
||||
& (previous_last_candle['sma20'] > last_candle['sma20']):
|
||||
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['sma20'] > last_candle['sma20']):
|
||||
return "too_old_0.02"
|
||||
if (current_profit >= -0.03) & ((current_time - trade.open_date_utc).days >= 15) \
|
||||
& (previous_last_candle['sma20'] > last_candle['sma20']):
|
||||
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.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'] * 1.005) \
|
||||
| (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) & (last_candle['percent5'] < 0) \
|
||||
& ((current_time - trade.open_date_utc).seconds >= 3600) \
|
||||
& ((previous_last_candle['sma20'] > last_candle['sma20']) &
|
||||
((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'] < - current_profit / 3) |
|
||||
(last_candle['percent3'] < - current_profit / 3)):
|
||||
# print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
|
||||
return 'over_rsi'
|
||||
if False & (current_profit > 0) & (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 False & (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):
|
||||
return []
|
||||
|
||||
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=72)
|
||||
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["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_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36)
|
||||
|
||||
dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close']
|
||||
dataframe['min1.1'] = 1.01 * dataframe['min']
|
||||
|
||||
# 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["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)
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
condition1, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator0,
|
||||
buy_indicator0,
|
||||
buy_crossed_indicator0,
|
||||
self.buy_real_num0.value,
|
||||
self.buy_decalage0.value
|
||||
)
|
||||
conditions.append(condition1)
|
||||
|
||||
if conditions:
|
||||
for decalage in range(3, self.buy_decalage0.value):
|
||||
dataframe.loc[
|
||||
(
|
||||
reduce(lambda x, y: x & y, conditions)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
& (dataframe['sma10'].shift(1) <= dataframe['sma10'])
|
||||
& (dataframe['close'] < dataframe['bb_middleband'])
|
||||
& (dataframe['open'] < dataframe['sma10'])
|
||||
& (dataframe['min50'].shift(decalage) == dataframe['min50'])
|
||||
& (dataframe['min10'] <= dataframe['min50'] * 1.02)
|
||||
& (dataframe['percent20'].shift(decalage) <= -0.01)
|
||||
# & (dataframe['min20'] == dataframe['min50'])
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage))
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['cond1'].shift(decalage) <= self.buy_real_num0.value / 2)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (dataframe['sma10'].shift(1) <= dataframe['sma10'])
|
||||
& (dataframe['close'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma10'])
|
||||
& (dataframe['min50'].shift(decalage) == dataframe['min50'])
|
||||
# & (dataframe['min10'] <= dataframe['min50'] * 1.02)
|
||||
& (dataframe['percent20'].shift(decalage) <= -0.02)
|
||||
# & (dataframe['min20'] == dataframe['min50'])
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage))
|
||||
|
||||
# pandas.set_option('display.max_rows', dataframe.shape[0] + 1)
|
||||
# pandas.set_option('display.max_columns', 30)
|
||||
# print(condition1)
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
return dataframe
|
||||
34
GodStraJD3_7_3.json
Normal file
34
GodStraJD3_7_3.json
Normal file
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_7_3",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.15,
|
||||
"trailing_stop_positive_offset": 0.2,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_decalage0": 6,
|
||||
"buy_real_num0": 0.9,
|
||||
"buy_decalage2": 5,
|
||||
"buy_real_num2": 1.5,
|
||||
"buy_signal_bb_width": 0.06
|
||||
},
|
||||
"sell": {},
|
||||
"protection": {
|
||||
"lookback": 133,
|
||||
"protection_max_allowed_dd": 0.71,
|
||||
"protection_stop": 61,
|
||||
"protection_stoploss_stop": 50,
|
||||
"trade_limit": 9
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-02-25 21:24:08.672826+00:00"
|
||||
}
|
||||
641
GodStraJD3_7_3.py
Normal file
641
GodStraJD3_7_3.py
Normal file
@@ -0,0 +1,641 @@
|
||||
# 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 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
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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'
|
||||
|
||||
# "buy_real_num0": 0.46,
|
||||
# "buy_real_num1": 0.48,
|
||||
# "buy_real_num2": 0.67
|
||||
|
||||
|
||||
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_3(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": {
|
||||
'ecart_20': {'color': 'red'},
|
||||
'ecart_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 ####################
|
||||
|
||||
# TODO: Its not dry code!
|
||||
# Buy Hyperoptable Parameters/Spaces.
|
||||
# "buy_real_num0": 0.46,
|
||||
# "buy_real_num1": 0.48,
|
||||
# "buy_real_num2": 0.67
|
||||
#
|
||||
# buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.46, space='buy')
|
||||
# buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.48, space='buy')
|
||||
# buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.67, space='buy')
|
||||
|
||||
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 = False
|
||||
profit_sma20 = True
|
||||
profit_very_old_sma10 = False
|
||||
|
||||
# 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_real_num0 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy')
|
||||
buy_decalage0 = IntParameter(1, 10, default=5, space='buy')
|
||||
|
||||
buy_real_num2 = DecimalParameter(1, 3, decimals=2, default=0.67, space='buy')
|
||||
buy_decalage2 = IntParameter(1, 10, default=5, 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')
|
||||
|
||||
@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['sma20'] > last_candle['sma20']):
|
||||
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['sma20'] > last_candle['sma20']):
|
||||
return "too_old_0.02"
|
||||
if (current_profit >= -0.03) & ((current_time - trade.open_date_utc).days >= 15) \
|
||||
& (previous_last_candle['sma20'] > last_candle['sma20']):
|
||||
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.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'] * 1.005) \
|
||||
| (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) & (last_candle['percent5'] < 0) \
|
||||
& ((current_time - trade.open_date_utc).seconds >= 3600) \
|
||||
& ((previous_last_candle['sma20'] > last_candle['sma20']) &
|
||||
((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) & (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):
|
||||
return []
|
||||
|
||||
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=72)
|
||||
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["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_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36)
|
||||
|
||||
dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close']
|
||||
dataframe['min1.1'] = 1.01 * dataframe['min']
|
||||
|
||||
# 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["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)
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions = list()
|
||||
condition1, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator0,
|
||||
buy_indicator0,
|
||||
buy_crossed_indicator0,
|
||||
self.buy_real_num0.value,
|
||||
self.buy_decalage0.value
|
||||
)
|
||||
conditions.append(condition1)
|
||||
|
||||
conditions2 = list()
|
||||
|
||||
condition2, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator0,
|
||||
buy_indicator0,
|
||||
buy_crossed_indicator0,
|
||||
self.buy_real_num2.value,
|
||||
self.buy_decalage2.value
|
||||
)
|
||||
conditions2.append(condition2)
|
||||
|
||||
if conditions:
|
||||
for decalage in range(3, self.buy_decalage0.value):
|
||||
dataframe.loc[
|
||||
(
|
||||
reduce(lambda x, y: x & y, conditions)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
& (dataframe['sma10'].shift(1) <= dataframe['sma10'])
|
||||
& (dataframe['close'] < dataframe['bb_middleband'])
|
||||
& (dataframe['open'] < dataframe['sma10'])
|
||||
& (dataframe['min50'].shift(decalage) == dataframe['min50'])
|
||||
& (dataframe['min10'] <= dataframe['min50'] * 1.02)
|
||||
& (dataframe['percent20'].shift(decalage) <= -0.01)
|
||||
# & (dataframe['min20'] == dataframe['min50'])
|
||||
& (dataframe['distance_min'] <= 0.02)
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage))
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['cond1'].shift(decalage) <= self.buy_real_num0.value / 2)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (dataframe['sma10'].shift(1) <= dataframe['sma10'])
|
||||
& (dataframe['close'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma10'])
|
||||
& (dataframe['min50'].shift(decalage) == dataframe['min50'])
|
||||
#& (dataframe['min10'] <= dataframe['min50'] * 1.02)
|
||||
& (dataframe['percent20'].shift(decalage) <= -0.02)
|
||||
# & (dataframe['min20'] == dataframe['min50'])
|
||||
& (dataframe['distance_min'] <= 0.02)
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage))
|
||||
# dataframe.loc[
|
||||
# (
|
||||
# (dataframe['cond1'].shift(decalage) <= 1.2)
|
||||
# & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# # & (dataframe['sma10'].shift(1) <= dataframe['sma10'])
|
||||
# & (dataframe['close'] < dataframe['sma10'])
|
||||
# & (dataframe['open'] < dataframe['sma10'])
|
||||
# & (dataframe['min50'].shift(decalage) == dataframe['min50'])
|
||||
# #& (dataframe['min10'] <= dataframe['min50'] * 1.02)
|
||||
# & (dataframe['percent20'].shift(decalage) <= -0.065)
|
||||
# & (dataframe['distance_min'] <= 0.01)
|
||||
# ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage))
|
||||
# if conditions2:
|
||||
# for decalage in range(1, self.buy_decalage2.value): #self.buy_decalage.value):
|
||||
# dataframe.loc[
|
||||
# (
|
||||
# reduce(lambda x, y: x & y, conditions2)
|
||||
# & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (dataframe['sma10'].shift(1) < dataframe['sma10'])
|
||||
# & (dataframe['close'] < dataframe['bb_middleband'])
|
||||
# # & (dataframe['open'] < dataframe['sma10'])
|
||||
# & (dataframe['min50'].shift(decalage) == dataframe['min50'])
|
||||
# & (dataframe['bb_width'].shift(decalage) > self.buy_signal_bb_width.value)
|
||||
# & (dataframe['percent20'].shift(decalage) <= -0.01)
|
||||
# # & (dataframe['min20'] == dataframe['min50'])
|
||||
# ), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage))
|
||||
|
||||
|
||||
pandas.set_option('display.max_rows', dataframe.shape[0] + 1)
|
||||
pandas.set_option('display.max_columns', 30)
|
||||
# print(condition1)
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
return dataframe
|
||||
|
||||
45
GodStraJD3_7_4.json
Normal file
45
GodStraJD3_7_4.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_7_4",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.026,
|
||||
"trailing_stop_positive_offset": 0.077,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_0": true,
|
||||
"buy_0_distance": 0.04,
|
||||
"buy_0_percent20": 0.02,
|
||||
"buy_2": true,
|
||||
"buy_2_distance": 0.02,
|
||||
"buy_2_percent20": 0.08,
|
||||
"buy_3": true,
|
||||
"buy_3_distance": -0.06,
|
||||
"buy_3_percent20": 0.1,
|
||||
"buy_decalage0": 8,
|
||||
"buy_decalage2": 8,
|
||||
"buy_decalage3": 6,
|
||||
"buy_decalage_deb_0": 3,
|
||||
"buy_decalage_deb_2": 1,
|
||||
"buy_decalage_deb_3": 3,
|
||||
"buy_min_horizon": 83
|
||||
},
|
||||
"sell": {},
|
||||
"protection": {
|
||||
"lookback": 133,
|
||||
"protection_max_allowed_dd": 0.71,
|
||||
"protection_stop": 61,
|
||||
"protection_stoploss_stop": 50,
|
||||
"trade_limit": 9
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-03-08 17:38:42.327292+00:00"
|
||||
}
|
||||
804
GodStraJD3_7_4.py
Normal file
804
GodStraJD3_7_4.py
Normal file
@@ -0,0 +1,804 @@
|
||||
# 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
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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'
|
||||
|
||||
# "buy_real_num0": 0.46,
|
||||
# "buy_real_num1": 0.48,
|
||||
# "buy_real_num2": 0.67
|
||||
|
||||
|
||||
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_4(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": {
|
||||
'ecart_20': {'color': 'red'},
|
||||
'ecart_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 ####################
|
||||
|
||||
# TODO: Its not dry code!
|
||||
# Buy Hyperoptable Parameters/Spaces.
|
||||
# "buy_real_num0": 0.46,
|
||||
# "buy_real_num1": 0.48,
|
||||
# "buy_real_num2": 0.67
|
||||
#
|
||||
# buy_real_num0 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.46, space='buy')
|
||||
# buy_real_num1 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.48, space='buy')
|
||||
# buy_real_num2 = DecimalParameter(0, 1, decimals=DECIMALS, default=0.67, space='buy')
|
||||
|
||||
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 = False
|
||||
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_real_num0 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy')
|
||||
# buy_decalage0 = IntParameter(1, 10, default=5, space='buy')
|
||||
# #
|
||||
# buy_real_num1 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy')
|
||||
# buy_decalage1 = IntParameter(1, 10, default=5, space='buy')
|
||||
#
|
||||
# buy_real_num2 = DecimalParameter(1, 3, decimals=2, default=0.67, space='buy')
|
||||
# buy_decalage2 = IntParameter(1, 10, default=5, 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_0_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_decalage_deb_0 = IntParameter(1, 3, default=5, space='buy')
|
||||
buy_decalage_deb_2 = IntParameter(1, 3, default=5, space='buy')
|
||||
buy_decalage_deb_3 = IntParameter(1, 3, default=5, space='buy')
|
||||
|
||||
buy_decalage0 = IntParameter(buy_decalage_deb_0.value + 1, 8, default=5, space='buy')
|
||||
buy_decalage2 = IntParameter(buy_decalage_deb_2.value + 1, 8, default=5, space='buy')
|
||||
buy_decalage3 = IntParameter(buy_decalage_deb_3.value + 1, 8, default=5, 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')
|
||||
|
||||
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['sma20'] > last_candle['sma20']):
|
||||
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['sma20'] > last_candle['sma20']):
|
||||
return "too_old_0.02"
|
||||
if (current_profit >= -0.03) & ((current_time - trade.open_date_utc).days >= 15) \
|
||||
& (previous_last_candle['sma20'] > last_candle['sma20']):
|
||||
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.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'] * 1.005) \
|
||||
| (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) & (last_candle['percent5'] < 0) \
|
||||
& ((current_time - trade.open_date_utc).seconds >= 3600) \
|
||||
& ((previous_last_candle['sma20'] > last_candle['sma20']) &
|
||||
((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) & (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):
|
||||
return []
|
||||
|
||||
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["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_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36)
|
||||
|
||||
dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close']
|
||||
dataframe['min1.1'] = 1.01 * dataframe['min']
|
||||
|
||||
# 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["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)
|
||||
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))
|
||||
|
||||
conditions = list()
|
||||
condition1, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator0,
|
||||
buy_indicator0,
|
||||
buy_crossed_indicator0,
|
||||
0.9, #self.buy_real_num0.value,
|
||||
6 #self.buy_decalage0.value
|
||||
)
|
||||
conditions.append(condition1)
|
||||
|
||||
conditions2 = list()
|
||||
|
||||
condition2, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator0,
|
||||
buy_indicator0,
|
||||
buy_crossed_indicator0,
|
||||
1.5, #self.buy_real_num2.value,
|
||||
5 #self.buy_decalage2.value
|
||||
)
|
||||
conditions2.append(condition2)
|
||||
|
||||
if conditions:
|
||||
for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value):
|
||||
if self.buy_0.value:
|
||||
dataframe.loc[
|
||||
(
|
||||
reduce(lambda x, y: x & y, conditions)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
& (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['min10'] <= dataframe['min50'] * 1.02)
|
||||
& (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value)
|
||||
# & (dataframe['min20'] == dataframe['min50'])
|
||||
& (dataframe['distance_min'] <= self.buy_0_distance.value)
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage))
|
||||
for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value):
|
||||
if self.buy_2.value:
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_real_num0.value / 2)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (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)
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage))
|
||||
for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value):
|
||||
if self.buy_3.value:
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['cond1'].shift(decalage) <= 0.2)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (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_3_percent20.value)
|
||||
& (dataframe['distance_min'] <= self.buy_3_distance.value)
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage))
|
||||
# if conditions2:
|
||||
# for decalage in range(1, self.buy_decalage2.value): #self.buy_decalage.value):
|
||||
# dataframe.loc[
|
||||
# (
|
||||
# reduce(lambda x, y: x & y, conditions2)
|
||||
# & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (dataframe['sma10'].shift(1) < dataframe['sma10'])
|
||||
# & (dataframe['close'] < dataframe['bb_middleband'])
|
||||
# # & (dataframe['open'] < dataframe['sma10'])
|
||||
# & (dataframe['min50'].shift(decalage) == dataframe['min50'])
|
||||
# & (dataframe['bb_width'].shift(decalage) > self.buy_signal_bb_width.value)
|
||||
# & (dataframe['percent20'].shift(decalage) <= -0.01)
|
||||
# # & (dataframe['min20'] == dataframe['min50'])
|
||||
# ), ['buy', 'buy_tag']] = (1, 'buy_4_' + 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
|
||||
|
||||
48
GodStraJD3_7_5.json
Normal file
48
GodStraJD3_7_5.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_7_5",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.026,
|
||||
"trailing_stop_positive_offset": 0.077,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_0": true,
|
||||
"buy_0_distance": 0.06,
|
||||
"buy_0_percent20": 0.02,
|
||||
"buy_2": true,
|
||||
"buy_2_distance": 0.09,
|
||||
"buy_2_percent20": 0.05,
|
||||
"buy_3": true,
|
||||
"buy_3_distance": 0.03,
|
||||
"buy_3_percent20": 0.06,
|
||||
"buy_decalage0": 7,
|
||||
"buy_decalage2": 8,
|
||||
"buy_decalage3": 6,
|
||||
"buy_decalage_deb_0": 2,
|
||||
"buy_decalage_deb_2": 1,
|
||||
"buy_decalage_deb_3": 3,
|
||||
"buy_min_horizon": 179,
|
||||
"buy_real_num0": 0.82,
|
||||
"buy_real_num1": 0.42,
|
||||
"buy_real_num2": 0.21
|
||||
},
|
||||
"sell": {},
|
||||
"protection": {
|
||||
"lookback": 133,
|
||||
"protection_max_allowed_dd": 0.71,
|
||||
"protection_stop": 61,
|
||||
"protection_stoploss_stop": 50,
|
||||
"trade_limit": 9
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-03-09 00:06:48.822740+00:00"
|
||||
}
|
||||
764
GodStraJD3_7_5.py
Normal file
764
GodStraJD3_7_5.py
Normal file
@@ -0,0 +1,764 @@
|
||||
# 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
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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(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_real_num0 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy')
|
||||
buy_real_num1 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy')
|
||||
buy_real_num2 = 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_0_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_decalage_deb_0 = IntParameter(1, 3, default=5, space='buy')
|
||||
buy_decalage_deb_2 = IntParameter(1, 3, default=5, space='buy')
|
||||
buy_decalage_deb_3 = IntParameter(1, 3, default=5, space='buy')
|
||||
|
||||
buy_decalage0 = IntParameter(buy_decalage_deb_0.value + 1, 8, default=5, space='buy')
|
||||
buy_decalage2 = IntParameter(buy_decalage_deb_2.value + 1, 8, default=5, space='buy')
|
||||
buy_decalage3 = IntParameter(buy_decalage_deb_3.value + 1, 8, default=5, 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')
|
||||
|
||||
sell_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell')
|
||||
|
||||
|
||||
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.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):
|
||||
return []
|
||||
|
||||
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_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_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["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)
|
||||
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_decalage_deb_0.value, self.buy_decalage0.value):
|
||||
if self.buy_0.value:
|
||||
conditions = list()
|
||||
condition1, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator0,
|
||||
buy_indicator0,
|
||||
buy_crossed_indicator0,
|
||||
self.buy_real_num0.value,
|
||||
self.buy_decalage0.value
|
||||
)
|
||||
conditions.append(condition1)
|
||||
dataframe.loc[
|
||||
(
|
||||
reduce(lambda x, y: x & y, conditions)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
& (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['min10'] <= dataframe['min50'] * 1.02)
|
||||
& (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value)
|
||||
# & (dataframe['min20'] == dataframe['min50'])
|
||||
& (dataframe['distance_min'] <= self.buy_0_distance.value)
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage))
|
||||
for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value):
|
||||
if self.buy_2.value:
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_real_num0.value / 2)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (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)
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage))
|
||||
for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value):
|
||||
if self.buy_3.value:
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['cond1'].shift(decalage) <= 0.2)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (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_3_percent20.value)
|
||||
& (dataframe['distance_min'] <= self.buy_3_distance.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
|
||||
|
||||
57
GodStraJD3_7_5_1.json
Normal file
57
GodStraJD3_7_5_1.json
Normal file
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_7_5_1",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.026,
|
||||
"trailing_stop_positive_offset": 0.077,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_0": false,
|
||||
"buy_0_percent20": 0.07,
|
||||
"buy_1_decalage": 8,
|
||||
"buy_1_decalage_deb": 2,
|
||||
"buy_1_distance": 0.03,
|
||||
"buy_1_min": 1.09,
|
||||
"buy_1_normal_var": 4.1,
|
||||
"buy_1_real_num": 0.13,
|
||||
"buy_1_volume": 94,
|
||||
"buy_2": false,
|
||||
"buy_2_decalage": 8,
|
||||
"buy_2_decalage_deb": 1,
|
||||
"buy_2_distance": 0.06,
|
||||
"buy_2_min": 1.07,
|
||||
"buy_2_normal_var": 2.1,
|
||||
"buy_2_percent20": -0.08,
|
||||
"buy_2_real_num": 0.96,
|
||||
"buy_2_volume": 19,
|
||||
"buy_3": true,
|
||||
"buy_3_decalage": 8,
|
||||
"buy_3_decalage_deb": 2,
|
||||
"buy_3_distance": 0.06,
|
||||
"buy_3_min": 1.01,
|
||||
"buy_3_normal_var": 0.8,
|
||||
"buy_3_percent20": 0.01,
|
||||
"buy_3_real_num": 0.19,
|
||||
"buy_3_volume": 32,
|
||||
"buy_min_horizon": 139
|
||||
},
|
||||
"sell": {},
|
||||
"protection": {
|
||||
"lookback": 133,
|
||||
"protection_max_allowed_dd": 0.71,
|
||||
"protection_stop": 61,
|
||||
"protection_stoploss_stop": 50,
|
||||
"trade_limit": 9
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-03-17 11:40:13.234887+00:00"
|
||||
}
|
||||
823
GodStraJD3_7_5_1.py
Normal file
823
GodStraJD3_7_5_1.py
Normal file
@@ -0,0 +1,823 @@
|
||||
# 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
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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_1(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_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_min = DecimalParameter(1, 1.1, decimals=2, default=1.02, space='buy')
|
||||
buy_2_min = DecimalParameter(1, 1.1, decimals=2, default=1.02, space='buy')
|
||||
buy_3_min = DecimalParameter(1, 1.1, decimals=2, 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')
|
||||
|
||||
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['sma20'] > last_candle['sma20']):
|
||||
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['sma20'] > last_candle['sma20']):
|
||||
return "too_old_0.02"
|
||||
if (current_profit >= -0.03) & ((current_time - trade.open_date_utc).days >= 15) \
|
||||
& (previous_last_candle['sma20'] > last_candle['sma20']):
|
||||
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'] * 1.005) \
|
||||
| (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) & (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):
|
||||
return []
|
||||
|
||||
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_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["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)
|
||||
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['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['min10'] <= dataframe['min50'] * 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) <= 0.45) #self.buy_1_real_num.value / 2)
|
||||
& (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'] * self.buy_2_min.value)
|
||||
& (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) <= 0.2)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_3_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'] * 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
|
||||
|
||||
72
GodStraJD3_7_5_10.json
Normal file
72
GodStraJD3_7_5_10.json
Normal file
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_7_5_10",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.026,
|
||||
"trailing_stop_positive_offset": 0.077,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_0_distance": 0.01,
|
||||
"buy_0_percent20": 0.1,
|
||||
"buy_1_bb_lower_5": 0.52,
|
||||
"buy_1_pente_sma10": 0.25,
|
||||
"buy_1_pente_sma20": 0.38,
|
||||
"buy_1_percent_5m_num": -0.04,
|
||||
"buy_2_bb_lower_5": 0.56,
|
||||
"buy_2_distance": 0.1,
|
||||
"buy_2_pente_sma10": 0.55,
|
||||
"buy_2_pente_sma20": 0.25,
|
||||
"buy_2_percent20": 0.04,
|
||||
"buy_2_percent_5m_num": -0.07,
|
||||
"buy_3_bb_lower_5": 0.6,
|
||||
"buy_3_distance": -0.01,
|
||||
"buy_3_pente_sma10": 0.32,
|
||||
"buy_3_pente_sma20": 0.5,
|
||||
"buy_3_percent20": 0.09,
|
||||
"buy_3_percent_5m_num": -0.04,
|
||||
"buy_4_day_week_percent": 0.0,
|
||||
"buy_4_pente_sma10": 0.56,
|
||||
"buy_4_pente_sma20": 0.13,
|
||||
"buy_day_week": "percent3_1d",
|
||||
"buy_decalage0": 7,
|
||||
"buy_decalage2": 8,
|
||||
"buy_decalage3": 8,
|
||||
"buy_decalage_deb_0": 3,
|
||||
"buy_decalage_deb_2": 0,
|
||||
"buy_decalage_deb_3": 0,
|
||||
"buy_min_horizon": 83,
|
||||
"buy_real_num0": 1.63,
|
||||
"buy_real_num1": 0.42,
|
||||
"buy_real_num2": 0.38
|
||||
},
|
||||
"sell": {
|
||||
"sell_RSI": 89,
|
||||
"sell_RSI2": 78,
|
||||
"sell_RSI2_percent": 0.001,
|
||||
"sell_candels": 4,
|
||||
"sell_percent": 0.02,
|
||||
"sell_percent3": 0.014,
|
||||
"sell_profit_no_change": 0.02,
|
||||
"sell_profit_percent10": 0.0013,
|
||||
"sell_too_old_day": 7,
|
||||
"sell_too_old_percent": 0.019
|
||||
},
|
||||
"protection": {
|
||||
"lookback": 133,
|
||||
"protection_max_allowed_dd": 0.71,
|
||||
"protection_stop": 61,
|
||||
"protection_stoploss_stop": 50,
|
||||
"trade_limit": 9
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-03-29 07:11:59.278799+00:00"
|
||||
}
|
||||
962
GodStraJD3_7_5_10.py
Normal file
962
GodStraJD3_7_5_10.py
Normal file
@@ -0,0 +1,962 @@
|
||||
# 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 logging
|
||||
import calendar
|
||||
from freqtrade.loggers import setup_logging
|
||||
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
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
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_10(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'},
|
||||
'sma5': {'color': 'pink'},
|
||||
'sma10': {'color': 'yellow'},
|
||||
'min20': {'color': '#87e470'},
|
||||
'min50': {'color': '#ac3e2a'},
|
||||
"min1.1": {'color': 'yellow'},
|
||||
'sma20': {'color': 'cyan'},
|
||||
'open_1d': {'color': 'white'},
|
||||
'close_1d': {'color': 'white'}
|
||||
},
|
||||
'subplots': {
|
||||
# Subplots - each dict defines one additional plot
|
||||
"BB": {
|
||||
'bb_width': {'color': 'white'},
|
||||
'bb_lower_5': {'color': 'yellow'}
|
||||
},
|
||||
# "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 = True
|
||||
profit_old_sma10 = False
|
||||
profit_old_sma5 = False
|
||||
profit_over_rsi = True
|
||||
profit_quick_gain = True
|
||||
profit_quick_gain_3 = True
|
||||
profit_quick_lost = True
|
||||
profit_short_loss = False
|
||||
profit_sma5 = True
|
||||
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_real_num0 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy')
|
||||
buy_real_num1 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy')
|
||||
buy_real_num2 = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy')
|
||||
buy_1_percent_5m_num = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.01, space='buy')
|
||||
buy_2_percent_5m_num = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.01, space='buy')
|
||||
buy_3_percent_5m_num = DecimalParameter(-0.1, 0.1, decimals=2, default=-0.01, space='buy')
|
||||
buy_4_day_week_percent = DecimalParameter(0, 0.1, decimals=2, default=0.01, space='buy')
|
||||
|
||||
buy_day_week = CategoricalParameter([
|
||||
'percent_1d', 'percent3_1d', 'percent5_1d', 'percent_1w', 'percent3_1w'],
|
||||
default="percent_1d", space='buy')
|
||||
#buy_3_cond_1h_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy')
|
||||
# buy_1_percent_4h_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy')
|
||||
# buy_2_percent_4h_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy')
|
||||
# buy_3_percent_4h_num = DecimalParameter(-0.1, 0.1, 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_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_0_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_decalage_deb_0 = IntParameter(0, 3, default=5, space='buy')
|
||||
buy_decalage_deb_2 = IntParameter(0, 3, default=5, space='buy')
|
||||
buy_decalage_deb_3 = IntParameter(0, 3, default=5, space='buy')
|
||||
|
||||
buy_decalage0 = IntParameter(buy_decalage_deb_0.value + 1, 8, default=5, space='buy')
|
||||
buy_decalage2 = IntParameter(buy_decalage_deb_2.value + 1, 8, default=5, space='buy')
|
||||
buy_decalage3 = IntParameter(buy_decalage_deb_3.value + 1, 8, default=5, space='buy')
|
||||
|
||||
buy_1_pente_sma10 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_2_pente_sma10 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_3_pente_sma10 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_4_pente_sma10 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
|
||||
buy_1_pente_sma20 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_2_pente_sma20 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_3_pente_sma20 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_4_pente_sma20 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
|
||||
# buy_1_bb_lower_var_5 = DecimalParameter(0, 0.4, decimals=2, default=0.07, space='buy')
|
||||
# buy_2_bb_lower_var_5 = DecimalParameter(0, 0.4, decimals=2, default=0.07, space='buy')
|
||||
# buy_3_bb_lower_var_5 = DecimalParameter(0, 0.4, decimals=2, default=0.07, space='buy')
|
||||
|
||||
buy_1_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_2_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_3_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, 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')
|
||||
|
||||
sell_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell')
|
||||
sell_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell')
|
||||
sell_candels = IntParameter(0, 48, default=12, space='sell')
|
||||
|
||||
sell_too_old_day = IntParameter(0, 10, default=5, space='sell')
|
||||
sell_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell')
|
||||
|
||||
sell_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell')
|
||||
sell_profit_percent10 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell')
|
||||
|
||||
sell_RSI = IntParameter(70, 98, default=88, space='sell')
|
||||
sell_RSI2 = IntParameter(70, 98, default=88, space='sell')
|
||||
sell_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell')
|
||||
|
||||
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
|
||||
# },
|
||||
# {
|
||||
# "method": "EmergencyStop",
|
||||
# "min_percent": -0.05,
|
||||
# "candels": 1
|
||||
# }
|
||||
]
|
||||
|
||||
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 >= - self.sell_too_old_percent.value) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value)\
|
||||
& ((current_time - trade.open_date_utc).days < self.sell_too_old_day.value * 2)\
|
||||
& (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0):
|
||||
return "too_old_0.01"
|
||||
if (current_profit >= - self.sell_too_old_percent.value * 2) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value * 2)\
|
||||
& ((current_time - trade.open_date_utc).days < self.sell_too_old_day.value * 3) \
|
||||
& (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0):
|
||||
return "too_old_0.02"
|
||||
if (current_profit >= - self.sell_too_old_percent.value * 3) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value * 3) \
|
||||
& (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0):
|
||||
return "too_old_0.03"
|
||||
|
||||
if self.profit_quick_lost and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005):
|
||||
return "quick_lost"
|
||||
|
||||
if self.profit_no_change and (current_profit > self.sell_profit_no_change.value) \
|
||||
& (last_candle['percent10'] < self.sell_profit_percent10.value) & (last_candle['percent5'] < 0) \
|
||||
& ((current_time - trade.open_date_utc).seconds >= 3600):
|
||||
return "no_change"
|
||||
|
||||
#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 (current_profit > 0 & last_candle['bb_width'] < current_profit):
|
||||
# return "more_bb_width"
|
||||
|
||||
|
||||
if (current_profit > self.sell_percent.value) & (last_candle['percent3'] < - self.sell_percent3.value) \
|
||||
& ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_candels.value):
|
||||
return "quick_gain_param"
|
||||
|
||||
if self.profit_sma5:
|
||||
if (current_profit > 0.01) \
|
||||
& ((previous_5_candle['sma5'] > last_candle['sma5']) \
|
||||
| (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_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'] > self.sell_RSI.value): # & (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'] > self.sell_RSI2.value) & \
|
||||
(last_candle['percent'] < - self.sell_RSI2_percent.value): #| (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, "5m") 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 = [("BTC/USDT", "1w"), ("BTC/USDT", "1d"), ("BTC/USDT", "5m")]
|
||||
|
||||
return informative_pairs
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
# dataframe['profit'] = 0
|
||||
# RSI
|
||||
dataframe['rsi'] = ta.RSI(dataframe)
|
||||
dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5)
|
||||
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'] - dataframe['min50']).rolling(5).var()
|
||||
dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1)
|
||||
# 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_20'] = dataframe['normal'].rolling(20).var()
|
||||
dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var()
|
||||
|
||||
# dataframe['TR'] = ta.TRANGE(dataframe)
|
||||
# dataframe['ATR'] = ta.SMA(dataframe['TR'], 21)
|
||||
|
||||
# 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["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="1w")
|
||||
informative["percent"] = (informative["close"] - informative["open"]) / informative["open"]
|
||||
informative["percent5"] = informative["percent"].rolling(5).sum()
|
||||
informative["percent3"] = informative["percent"].rolling(3).sum()
|
||||
# logger.info("Strategy informative using %s %s", "BTC/TUSD", "5m")
|
||||
dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1w", ffill=True)
|
||||
|
||||
informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="5m")
|
||||
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, "5m", ffill=True)
|
||||
|
||||
informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d")
|
||||
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)
|
||||
|
||||
# logger.info("Strategy informative using %s %s", "BTC/TUSD", "1h")
|
||||
|
||||
# # Get the informative pair
|
||||
# informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="4h")
|
||||
# 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()
|
||||
# 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, "4h", 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['max_open'] = ta.MAX(informative["open"], timeperiod=2)
|
||||
# informative['max_close'] = ta.MIN(informative["close"], timeperiod=2)
|
||||
# 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))
|
||||
|
||||
# self.protections.global_stop(current_time);
|
||||
|
||||
for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value):
|
||||
#if self.buy_0.value:
|
||||
conditions = list()
|
||||
condition1, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator0,
|
||||
buy_indicator0,
|
||||
buy_crossed_indicator0,
|
||||
self.buy_real_num0.value,
|
||||
self.buy_decalage0.value
|
||||
)
|
||||
conditions.append(condition1)
|
||||
dataframe.loc[
|
||||
(
|
||||
reduce(lambda x, y: x & y, conditions)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
& (dataframe['sma10'].shift(1) <= dataframe['sma10'])
|
||||
& (dataframe['close'] < dataframe['bb_middleband'])
|
||||
& (dataframe['open'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma20'])
|
||||
& (dataframe['min50'].shift(decalage) == dataframe['min50'])
|
||||
& (dataframe['min10'] <= dataframe['min50'] * 1.02)
|
||||
& (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value)
|
||||
# & (dataframe['min20'] == dataframe['min50'])
|
||||
& (dataframe['distance_min'] <= self.buy_0_distance.value)
|
||||
& ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(decalage) <= 0.005)
|
||||
# & (dataframe['bb_lower_var_5'] <= self.buy_1_bb_lower_var_5.value)
|
||||
& (dataframe['bb_lower_5'] <= self.buy_1_bb_lower_5.value)
|
||||
& (((dataframe['sma10'].shift(1) - dataframe['sma10']) / dataframe['sma10']) < self.buy_1_pente_sma10.value / 100)
|
||||
& (((dataframe['sma20'].shift(1) - dataframe['sma20']) / dataframe['sma20']) < self.buy_1_pente_sma20.value / 100)
|
||||
& (dataframe['percent_5m'].shift(1) >= self.buy_1_percent_5m_num.value)
|
||||
& (dataframe[self.buy_day_week.value] < self.buy_4_day_week_percent.value)
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage))
|
||||
for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value):
|
||||
#if self.buy_2.value:
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_real_num0.value / 2)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (dataframe['sma10'].shift(1) <= dataframe['sma10'])
|
||||
& (dataframe['close'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma20'])
|
||||
& (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['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(
|
||||
decalage) <= 0.005)
|
||||
# & (dataframe['bb_lower_var_5'] <= self.buy_2_bb_lower_var_5.value)
|
||||
& (dataframe['bb_lower_5'] <= self.buy_2_bb_lower_5.value)
|
||||
& (((dataframe['sma10'].shift(1) - dataframe['sma10']) / dataframe[
|
||||
'sma10']) < self.buy_2_pente_sma10.value / 100)
|
||||
& (((dataframe['sma20'].shift(1) - dataframe['sma20']) / dataframe[
|
||||
'sma20']) < self.buy_2_pente_sma20.value / 100)
|
||||
& (dataframe['percent_5m'].shift(1) >= self.buy_2_percent_5m_num.value)
|
||||
& (dataframe[self.buy_day_week.value] < self.buy_4_day_week_percent.value)
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage))
|
||||
for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value):
|
||||
#if self.buy_3.value:
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['cond1'].shift(decalage) <= 0.2)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (dataframe['sma10'].shift(1) <= dataframe['sma10'])
|
||||
& (dataframe['close'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma20'])
|
||||
& (dataframe['open'] < dataframe['sma10'])
|
||||
& (dataframe['min50'].shift(decalage) == dataframe['min50'])
|
||||
#& (dataframe['min10'] <= dataframe['min50'] * 1.02)
|
||||
& (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value)
|
||||
& (dataframe['distance_min'] <= self.buy_3_distance.value)
|
||||
& ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(
|
||||
decalage) <= 0.005)
|
||||
# & (dataframe['bb_lower_var_5'] <= self.buy_3_bb_lower_var_5.value)
|
||||
& (dataframe['bb_lower_5'] <= self.buy_3_bb_lower_5.value)
|
||||
& (((dataframe['sma10'].shift(1) - dataframe['sma10']) / dataframe[
|
||||
'sma10']) < self.buy_3_pente_sma10.value / 100)
|
||||
& (((dataframe['sma20'].shift(1) - dataframe['sma20']) / dataframe[
|
||||
'sma20']) < self.buy_3_pente_sma20.value / 100)
|
||||
& (dataframe['percent_5m'].shift(1) >= self.buy_3_percent_5m_num.value)
|
||||
& (dataframe[self.buy_day_week.value] < self.buy_4_day_week_percent.value)
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage))
|
||||
|
||||
# "buy_2_distance": 0.09,
|
||||
# "buy_2_percent20": 0.05,
|
||||
decalage = 1
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['cond1'].shift(decalage) <= 0.45) # self.buy_real_num0.value / 2)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 19)
|
||||
& (dataframe['close'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma100'])
|
||||
& (dataframe['open'] < dataframe['sma10'])
|
||||
& (dataframe['min50'].shift(decalage) == dataframe['min50'])
|
||||
& (dataframe['percent20'].shift(decalage) <= 0.05) #self.buy_2_percent20.value)
|
||||
& (dataframe['distance_min'] <= 0.09) #self.buy_2_distance.value)
|
||||
& (dataframe[self.buy_day_week.value] >= self.buy_4_day_week_percent.value)
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_4_' + str(decalage))
|
||||
|
||||
# dataframe.loc[
|
||||
# (
|
||||
# (dataframe['close'] < dataframe['close_1d'])
|
||||
# & (dataframe['close'] > dataframe['bb_upperband'])
|
||||
# ), ['buy', 'buy_tag']] = (1, 'buy_4')
|
||||
|
||||
# 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
|
||||
|
||||
51
GodStraJD3_7_5_2.json
Normal file
51
GodStraJD3_7_5_2.json
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_7_5_2",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 2
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.02,
|
||||
"trailing_stop_positive_offset": 0.03,
|
||||
"trailing_only_offset_is_reached": false
|
||||
},
|
||||
"buy": {
|
||||
"buy_1": false,
|
||||
"buy_1_bb_diff_lower": 0.0007,
|
||||
"buy_1_decalage": 6,
|
||||
"buy_1_decalage_deb": 1,
|
||||
"buy_1_distance": 0.03,
|
||||
"buy_1_percent20": 0.06,
|
||||
"buy_1_real_num": 0.1,
|
||||
"buy_2": false,
|
||||
"buy_2_bb_diff_lower": 0.0004,
|
||||
"buy_2_decalage": 7,
|
||||
"buy_2_decalage_deb": 3,
|
||||
"buy_2_distance": 0.06,
|
||||
"buy_2_percent20": 0.01,
|
||||
"buy_2_real_num": 1.7,
|
||||
"buy_3": true,
|
||||
"buy_3_bb_diff_lower": 0.0,
|
||||
"buy_3_decalage": 7,
|
||||
"buy_3_decalage_deb": 2,
|
||||
"buy_3_distance": 0.09,
|
||||
"buy_3_percent20": 0.01,
|
||||
"buy_3_real_num": 0.99,
|
||||
"buy_min_horizon": 191
|
||||
},
|
||||
"sell": {},
|
||||
"protection": {
|
||||
"lookback": 133,
|
||||
"protection_max_allowed_dd": 0.71,
|
||||
"protection_stop": 61,
|
||||
"protection_stoploss_stop": 50,
|
||||
"trade_limit": 9
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-03-12 21:14:24.255458+00:00"
|
||||
}
|
||||
781
GodStraJD3_7_5_2.py
Normal file
781
GodStraJD3_7_5_2.py
Normal file
@@ -0,0 +1,781 @@
|
||||
# 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
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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_2(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'},
|
||||
"bb_diff_lower": {'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_real_num = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy')
|
||||
buy_2_real_num = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy')
|
||||
buy_3_real_num = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy')
|
||||
|
||||
buy_min_horizon = IntParameter(50, 200, default=72, space='buy')
|
||||
|
||||
buy_1 = BooleanParameter(default=True, space="buy")
|
||||
buy_2 = BooleanParameter(default=True, space="buy")
|
||||
buy_3 = BooleanParameter(default=True, space="buy")
|
||||
|
||||
buy_1_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_bb_diff_lower = DecimalParameter(0, 0.001, decimals=4, default=0.0009, space='buy')
|
||||
buy_2_bb_diff_lower = DecimalParameter(0, 0.001, decimals=4, default=0.0009, space='buy')
|
||||
buy_3_bb_diff_lower = DecimalParameter(0, 0.001, decimals=4, default=0.0009, 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')
|
||||
|
||||
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')
|
||||
|
||||
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'
|
||||
|
||||
days = (current_time - trade.open_date_utc).days
|
||||
# if (current_profit >= -0.01 * days) & (days >= 5) \
|
||||
# & (previous_last_candle['sma20'] > last_candle['sma20']):
|
||||
# return "too_old_" + days
|
||||
if (current_profit >= -0.01) & (days >= 5) & (days < 10)\
|
||||
& (previous_last_candle['sma20'] > last_candle['sma20']):
|
||||
return "too_old_0.01"
|
||||
if (current_profit >= -0.02) & (days >= 10) & (days < 15) \
|
||||
& (previous_last_candle['sma20'] > last_candle['sma20']):
|
||||
return "too_old_0.02"
|
||||
if (current_profit >= -0.03) & (days >= 15) \
|
||||
& (previous_last_candle['sma20'] > last_candle['sma20']):
|
||||
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.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'] * 1.005) \
|
||||
| (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) \
|
||||
# & (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) \
|
||||
# & (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'] < - current_profit / 3) | (last_candle['percent3'] < - current_profit / 3)):
|
||||
# # print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
|
||||
# return 'over_rsi'
|
||||
|
||||
if (current_profit > 0) & (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)\
|
||||
& (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):
|
||||
return []
|
||||
|
||||
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['volume_max'] = dataframe['volume10'] * dataframe['close'] / 1000
|
||||
|
||||
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_diff_lower"] = (dataframe["bb_lowerband"] - dataframe["bb_lowerband"].shift(1)) / dataframe["bb_lowerband"]
|
||||
# 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()) - 100
|
||||
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["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)
|
||||
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_1.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['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
& (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['min10'] <= dataframe['min50'] * 1.02)
|
||||
& (dataframe['percent20'].shift(decalage) <= self.buy_1_percent20.value)
|
||||
# & (dataframe['min20'] == dataframe['min50'])
|
||||
& (dataframe['bb_diff_lower'] >= - self.buy_1_bb_diff_lower.value)
|
||||
# & (dataframe['distance_min'] <= self.buy_1_distance.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_real_num.value)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (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)
|
||||
), ['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_real_num.value)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (dataframe['sma10'].shift(1) <= dataframe['sma10'])
|
||||
# & (dataframe['bb_width'] >= 0.07)
|
||||
& (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_3_percent20.value)
|
||||
& (dataframe['distance_min'] <= self.buy_3_distance.value)
|
||||
& (dataframe['bb_diff_lower'] >= - self.buy_3_bb_diff_lower.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
|
||||
|
||||
51
GodStraJD3_7_5_3.json
Normal file
51
GodStraJD3_7_5_3.json
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_7_5_3",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.026,
|
||||
"trailing_stop_positive_offset": 0.077,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_0": false,
|
||||
"buy_0_percent20": -0.07,
|
||||
"buy_1_decalage": 6,
|
||||
"buy_1_decalage_deb": 3,
|
||||
"buy_1_distance": 0.02,
|
||||
"buy_1_normal_var": 5.0,
|
||||
"buy_1_real_num": 0.61,
|
||||
"buy_2": true,
|
||||
"buy_2_decalage": 6,
|
||||
"buy_2_decalage_deb": 1,
|
||||
"buy_2_distance": 0.1,
|
||||
"buy_2_normal_var": 0.0,
|
||||
"buy_2_percent20": 0.02,
|
||||
"buy_2_real_num": 0.35,
|
||||
"buy_3": true,
|
||||
"buy_3_decalage": 6,
|
||||
"buy_3_decalage_deb": 2,
|
||||
"buy_3_distance": 0.01,
|
||||
"buy_3_normal_var": 1.8,
|
||||
"buy_3_percent20": -0.03,
|
||||
"buy_3_real_num": 1.18,
|
||||
"buy_min_horizon": 165
|
||||
},
|
||||
"sell": {},
|
||||
"protection": {
|
||||
"lookback": 133,
|
||||
"protection_max_allowed_dd": 0.71,
|
||||
"protection_stop": 61,
|
||||
"protection_stoploss_stop": 50,
|
||||
"trade_limit": 9
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-03-13 17:21:19.281512+00:00"
|
||||
}
|
||||
51
GodStraJD3_7_5_3.json1
Normal file
51
GodStraJD3_7_5_3.json1
Normal file
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_7_5_3",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.026,
|
||||
"trailing_stop_positive_offset": 0.077,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_0": true,
|
||||
"buy_0_percent20": 0.09,
|
||||
"buy_1_decalage": 6,
|
||||
"buy_1_decalage_deb": 1,
|
||||
"buy_1_distance": 0.06,
|
||||
"buy_1_normal_var": 4.7,
|
||||
"buy_1_real_num": 0.96,
|
||||
"buy_2": true,
|
||||
"buy_2_decalage": 6,
|
||||
"buy_2_decalage_deb": 2,
|
||||
"buy_2_distance": 0.03,
|
||||
"buy_2_normal_var": 1.6,
|
||||
"buy_2_percent20": 0.09,
|
||||
"buy_2_real_num": 0.08,
|
||||
"buy_3": false,
|
||||
"buy_3_decalage": 6,
|
||||
"buy_3_decalage_deb": 2,
|
||||
"buy_3_distance": -0.08,
|
||||
"buy_3_normal_var": 1.9,
|
||||
"buy_3_percent20": -0.06,
|
||||
"buy_3_real_num": 0.81,
|
||||
"buy_min_horizon": 186
|
||||
},
|
||||
"sell": {},
|
||||
"protection": {
|
||||
"lookback": 133,
|
||||
"protection_max_allowed_dd": 0.71,
|
||||
"protection_stop": 61,
|
||||
"protection_stoploss_stop": 50,
|
||||
"trade_limit": 9
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-03-12 23:10:38.145463+00:00"
|
||||
}
|
||||
808
GodStraJD3_7_5_3.py
Normal file
808
GodStraJD3_7_5_3.py
Normal file
@@ -0,0 +1,808 @@
|
||||
# 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
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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_3(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_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_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')
|
||||
|
||||
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')
|
||||
|
||||
# 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()
|
||||
#
|
||||
# # 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['sma20'] > last_candle['sma20']):
|
||||
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['sma20'] > last_candle['sma20']):
|
||||
return "too_old_0.02"
|
||||
if (current_profit >= -0.03) & ((current_time - trade.open_date_utc).days >= 15) \
|
||||
& (previous_last_candle['sma20'] > last_candle['sma20']):
|
||||
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) & (last_candle['percent3'] < 0):
|
||||
return "no_change_20"
|
||||
|
||||
if (current_profit > 0.01) & (last_candle['normal_var_10'] < 0.008) & (last_candle['percent3'] < 0):
|
||||
return "no_change_10"
|
||||
if (current_profit > 0.01) & (last_candle['normal_var_5'] < 0.005) & (last_candle['percent3'] < 0):
|
||||
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) & (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):
|
||||
return []
|
||||
|
||||
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_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["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)
|
||||
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['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
& (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['min10'] <= dataframe['min50'] * 1.02)
|
||||
& (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) <= 0.45) #self.buy_1_real_num.value / 2)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (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) <= 0.2)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (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_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
|
||||
|
||||
57
GodStraJD3_7_5_4.json
Normal file
57
GodStraJD3_7_5_4.json
Normal file
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_7_5_4",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.026,
|
||||
"trailing_stop_positive_offset": 0.077,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_0": false,
|
||||
"buy_0_percent20": 0.02,
|
||||
"buy_1_decalage": 8,
|
||||
"buy_1_decalage_deb": 3,
|
||||
"buy_1_distance": 0.07,
|
||||
"buy_1_min": 1.029,
|
||||
"buy_1_normal_var": 3.5,
|
||||
"buy_1_real_num": 0.47,
|
||||
"buy_1_volume": 71,
|
||||
"buy_2": true,
|
||||
"buy_2_decalage": 8,
|
||||
"buy_2_decalage_deb": 2,
|
||||
"buy_2_distance": 0.06,
|
||||
"buy_2_min": 1.029,
|
||||
"buy_2_normal_var": 0.3,
|
||||
"buy_2_percent20": 0.06,
|
||||
"buy_2_real_num": 0.38,
|
||||
"buy_2_volume": 13,
|
||||
"buy_3": true,
|
||||
"buy_3_decalage": 7,
|
||||
"buy_3_decalage_deb": 2,
|
||||
"buy_3_distance": 0.03,
|
||||
"buy_3_min": 1.008,
|
||||
"buy_3_normal_var": 3.2,
|
||||
"buy_3_percent20": 0.09,
|
||||
"buy_3_real_num": 0.73,
|
||||
"buy_3_volume": 12,
|
||||
"buy_min_horizon": 141
|
||||
},
|
||||
"sell": {},
|
||||
"protection": {
|
||||
"lookback": 133,
|
||||
"protection_max_allowed_dd": 0.71,
|
||||
"protection_stop": 61,
|
||||
"protection_stoploss_stop": 50,
|
||||
"trade_limit": 9
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-03-17 23:12:39.259525+00:00"
|
||||
}
|
||||
827
GodStraJD3_7_5_4.py
Normal file
827
GodStraJD3_7_5_4.py
Normal file
@@ -0,0 +1,827 @@
|
||||
# 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
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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_4(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_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_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')
|
||||
|
||||
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['sma20'] > last_candle['sma20']):
|
||||
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['sma20'] > last_candle['sma20']):
|
||||
return "too_old_0.02"
|
||||
if (current_profit >= -0.03) & ((current_time - trade.open_date_utc).days >= 15) \
|
||||
& (previous_last_candle['sma20'] > last_candle['sma20']):
|
||||
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) & (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):
|
||||
return []
|
||||
|
||||
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_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)
|
||||
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['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) <= 0.45) #self.buy_1_real_num.value / 2)
|
||||
& (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['open'] <= dataframe['min200'] * self.buy_2_min.value)
|
||||
& (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) <= 0.2)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= self.buy_3_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['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
|
||||
|
||||
63
GodStraJD3_7_5_5.json
Normal file
63
GodStraJD3_7_5_5.json
Normal file
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_7_5_5",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.026,
|
||||
"trailing_stop_positive_offset": 0.077,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_0": true,
|
||||
"buy_0_percent20": 0.03,
|
||||
"buy_1_cmf100_inf": 0.3,
|
||||
"buy_1_cmf100_sup": 0.6,
|
||||
"buy_1_decalage": 7,
|
||||
"buy_1_decalage_deb": 2,
|
||||
"buy_1_distance": -0.01,
|
||||
"buy_1_min": 1.002,
|
||||
"buy_1_normal_var": 2.2,
|
||||
"buy_1_real_num": 0.53,
|
||||
"buy_1_volume": 65,
|
||||
"buy_2": true,
|
||||
"buy_2_cmf100_inf": 1.0,
|
||||
"buy_2_cmf100_sup": 0.0,
|
||||
"buy_2_decalage": 6,
|
||||
"buy_2_decalage_deb": 2,
|
||||
"buy_2_distance": 0.08,
|
||||
"buy_2_min": 1.025,
|
||||
"buy_2_normal_var": 1.3,
|
||||
"buy_2_percent20": -0.09,
|
||||
"buy_2_real_num": 0.32,
|
||||
"buy_2_volume": 38,
|
||||
"buy_3": true,
|
||||
"buy_3_cmf100_inf": -0.4,
|
||||
"buy_3_cmf100_sup": -0.1,
|
||||
"buy_3_decalage": 7,
|
||||
"buy_3_decalage_deb": 1,
|
||||
"buy_3_distance": 0.1,
|
||||
"buy_3_min": 1.016,
|
||||
"buy_3_normal_var": 1.6,
|
||||
"buy_3_percent20": 0.03,
|
||||
"buy_3_real_num": 1.94,
|
||||
"buy_3_volume": 97,
|
||||
"buy_min_horizon": 98
|
||||
},
|
||||
"sell": {},
|
||||
"protection": {
|
||||
"lookback": 133,
|
||||
"protection_max_allowed_dd": 0.71,
|
||||
"protection_stop": 61,
|
||||
"protection_stoploss_stop": 50,
|
||||
"trade_limit": 9
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-03-19 16:02:08.220681+00:00"
|
||||
}
|
||||
875
GodStraJD3_7_5_5.py
Normal file
875
GodStraJD3_7_5_5.py
Normal file
@@ -0,0 +1,875 @@
|
||||
# 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_5(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_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 = '1h'
|
||||
|
||||
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]
|
||||
|
||||
# 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_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)
|
||||
# Get the 14 day rsi
|
||||
informative['rsi'] = ta.RSI(informative, timeperiod=14)
|
||||
|
||||
# informative['cmf'] = cmf(informative, timeperiod=14)
|
||||
|
||||
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))
|
||||
|
||||
# Use the helper function merge_informative_pair to safely merge the pair
|
||||
# Automatically renames the columns and merges a shorter timeframe dataframe and a longer timeframe informative pair
|
||||
# use ffill to have the 1d value available in every row throughout the day.
|
||||
# Without this, comparisons between columns of the original and the informative pair would only work once per day.
|
||||
# Full documentation of this method, see below
|
||||
dataframe = merge_informative_pair(dataframe, informative, self.timeframe, self.inf_tf, 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) <= 0.45) #self.buy_2_real_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) <= 0.2) #self.buy_3_real_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['close'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma100'])
|
||||
& (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
|
||||
|
||||
48
GodStraJD3_7_5_6.json
Normal file
48
GodStraJD3_7_5_6.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_7_5_6",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.026,
|
||||
"trailing_stop_positive_offset": 0.077,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_0": true,
|
||||
"buy_0_percent20": 0.08,
|
||||
"buy_1_volume": 0,
|
||||
"buy_3": true,
|
||||
"buy_3_cmf100_inf": 0.4,
|
||||
"buy_3_cmf100_sup": -0.6,
|
||||
"buy_3_cond_1h_num": 0.56,
|
||||
"buy_3_cond_num": 0.76,
|
||||
"buy_3_decalage": 7,
|
||||
"buy_3_decalage_deb": 3,
|
||||
"buy_3_distance": 0.08,
|
||||
"buy_3_min": 1.016,
|
||||
"buy_3_normal_var": 3.3,
|
||||
"buy_3_percent20": 0.1,
|
||||
"buy_3_percent_1d_num": 0.01,
|
||||
"buy_3_percent_1w_num": -0.04,
|
||||
"buy_3_real_num": 0.23,
|
||||
"buy_3_volume": 96,
|
||||
"buy_min_horizon": 198
|
||||
},
|
||||
"sell": {},
|
||||
"protection": {
|
||||
"lookback": 133,
|
||||
"protection_max_allowed_dd": 0.71,
|
||||
"protection_stop": 61,
|
||||
"protection_stoploss_stop": 50,
|
||||
"trade_limit": 9
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-03-22 20:30:50.351361+00:00"
|
||||
}
|
||||
898
GodStraJD3_7_5_6.py
Normal file
898
GodStraJD3_7_5_6.py
Normal file
@@ -0,0 +1,898 @@
|
||||
# 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
|
||||
|
||||
63
GodStraJD3_7_5_7.json
Normal file
63
GodStraJD3_7_5_7.json
Normal file
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_7_5_7",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.026,
|
||||
"trailing_stop_positive_offset": 0.077,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_0": true,
|
||||
"buy_0_percent20": 0.05,
|
||||
"buy_1_cmf100_inf": 0.5,
|
||||
"buy_1_cmf100_sup": -0.6,
|
||||
"buy_1_decalage": 6,
|
||||
"buy_1_decalage_deb": 2,
|
||||
"buy_1_distance": 0.1,
|
||||
"buy_1_min": 1.01,
|
||||
"buy_1_normal_var": 1.0,
|
||||
"buy_1_real_num": 0.01,
|
||||
"buy_1_volume": 60,
|
||||
"buy_2": true,
|
||||
"buy_2_cmf100_inf": -0.9,
|
||||
"buy_2_cmf100_sup": -1.0,
|
||||
"buy_2_decalage": 7,
|
||||
"buy_2_decalage_deb": 1,
|
||||
"buy_2_distance": 0.09,
|
||||
"buy_2_min": 1.025,
|
||||
"buy_2_normal_var": 4.0,
|
||||
"buy_2_percent20": 0.06,
|
||||
"buy_2_real_num": 0.61,
|
||||
"buy_2_volume": 33,
|
||||
"buy_3": false,
|
||||
"buy_3_cmf100_inf": 0.0,
|
||||
"buy_3_cmf100_sup": 0.7,
|
||||
"buy_3_decalage": 7,
|
||||
"buy_3_decalage_deb": 3,
|
||||
"buy_3_distance": -0.06,
|
||||
"buy_3_min": 1.006,
|
||||
"buy_3_normal_var": 4.5,
|
||||
"buy_3_percent20": 0.1,
|
||||
"buy_3_real_num": 1.41,
|
||||
"buy_3_volume": 15,
|
||||
"buy_min_horizon": 197
|
||||
},
|
||||
"sell": {},
|
||||
"protection": {
|
||||
"lookback": 133,
|
||||
"protection_max_allowed_dd": 0.71,
|
||||
"protection_stop": 61,
|
||||
"protection_stoploss_stop": 50,
|
||||
"trade_limit": 9
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-03-20 19:38:37.829599+00:00"
|
||||
}
|
||||
878
GodStraJD3_7_5_7.py
Normal file
878
GodStraJD3_7_5_7.py
Normal file
@@ -0,0 +1,878 @@
|
||||
# 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_7(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_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 = '1h'
|
||||
|
||||
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['percent3'] < 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]
|
||||
|
||||
# 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_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)
|
||||
|
||||
# Get the 14 day rsi
|
||||
informative['rsi'] = ta.RSI(informative, timeperiod=14)
|
||||
|
||||
# informative['cmf'] = cmf(informative, timeperiod=14)
|
||||
|
||||
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))
|
||||
|
||||
# Use the helper function merge_informative_pair to safely merge the pair
|
||||
# Automatically renames the columns and merges a shorter timeframe dataframe and a longer timeframe informative pair
|
||||
# use ffill to have the 1d value available in every row throughout the day.
|
||||
# Without this, comparisons between columns of the original and the informative pair would only work once per day.
|
||||
# Full documentation of this method, see below
|
||||
dataframe = merge_informative_pair(dataframe, informative, self.timeframe, self.inf_tf, 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) <= 0.45) #self.buy_2_real_num.value)
|
||||
& (dataframe['cond1_1h'] <= self.buy_2_real_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) <= 0.2) #self.buy_3_real_num.value)
|
||||
& (dataframe['cond1_1h'] <= self.buy_3_real_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['close'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma100'])
|
||||
& (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
|
||||
|
||||
46
GodStraJD3_7_5_8.json
Normal file
46
GodStraJD3_7_5_8.json
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_7_5_8",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.026,
|
||||
"trailing_stop_positive_offset": 0.077,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_0": true,
|
||||
"buy_0_percent20": -0.07,
|
||||
"buy_1_volume": 43,
|
||||
"buy_3": true,
|
||||
"buy_3_cmf100_inf": -0.9,
|
||||
"buy_3_cmf100_sup": 1.0,
|
||||
"buy_3_cond_1h_num": 0.37,
|
||||
"buy_3_cond_num": 1.78,
|
||||
"buy_3_decalage": 8,
|
||||
"buy_3_decalage_deb": 1,
|
||||
"buy_3_distance": 0.1,
|
||||
"buy_3_min": 1.022,
|
||||
"buy_3_normal_var": 2.1,
|
||||
"buy_3_percent20": 0.09,
|
||||
"buy_3_real_num": 0.37,
|
||||
"buy_3_volume": 60,
|
||||
"buy_min_horizon": 58
|
||||
},
|
||||
"sell": {},
|
||||
"protection": {
|
||||
"lookback": 133,
|
||||
"protection_max_allowed_dd": 0.71,
|
||||
"protection_stop": 61,
|
||||
"protection_stoploss_stop": 50,
|
||||
"trade_limit": 9
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-03-20 17:59:02.967586+00:00"
|
||||
}
|
||||
889
GodStraJD3_7_5_8.py
Normal file
889
GodStraJD3_7_5_8.py
Normal file
@@ -0,0 +1,889 @@
|
||||
# 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_8(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_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 = '1h'
|
||||
|
||||
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):
|
||||
return "quick_gain_3"
|
||||
if self.profit_quick_gain:
|
||||
if (0.01 < current_profit < 0.03) & (last_candle['percent3'] < 0):
|
||||
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]
|
||||
|
||||
# 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_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)
|
||||
# Get the 14 day rsi
|
||||
informative['rsi'] = ta.RSI(informative, timeperiod=14)
|
||||
# informative["percent"] = (informative["close"] - informative["open"]) / informative["open"]
|
||||
# informative["percent5"] = informative["percent"].rolling(5).sum()
|
||||
# informative["percent3"] = informative["percent"].rolling(3).sum()
|
||||
|
||||
|
||||
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))
|
||||
|
||||
# Use the helper function merge_informative_pair to safely merge the pair
|
||||
# Automatically renames the columns and merges a shorter timeframe dataframe and a longer timeframe informative pair
|
||||
# use ffill to have the 1d value available in every row throughout the day.
|
||||
# Without this, comparisons between columns of the original and the informative pair would only work once per day.
|
||||
# Full documentation of this method, see below
|
||||
dataframe = merge_informative_pair(dataframe, informative, self.timeframe, self.inf_tf, 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['cond1_1h'] <= self.buy_3_cond_1h_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['sma100'])
|
||||
& (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
|
||||
|
||||
52
GodStraJD3_7_5_9.json
Normal file
52
GodStraJD3_7_5_9.json
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_7_5_9",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.026,
|
||||
"trailing_stop_positive_offset": 0.077,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_0_distance": -0.08,
|
||||
"buy_0_percent20": 0.01,
|
||||
"buy_1_bb_lower_5": 0.06,
|
||||
"buy_2_bb_lower_5": 0.59,
|
||||
"buy_2_distance": 0.1,
|
||||
"buy_2_percent20": 0.05,
|
||||
"buy_3_bb_lower_5": 0.47,
|
||||
"buy_3_distance": 0.05,
|
||||
"buy_3_percent20": -0.07,
|
||||
"buy_decalage0": 7,
|
||||
"buy_decalage2": 6,
|
||||
"buy_decalage3": 8,
|
||||
"buy_decalage_deb_0": 1,
|
||||
"buy_decalage_deb_2": 1,
|
||||
"buy_decalage_deb_3": 2,
|
||||
"buy_min_horizon": 119,
|
||||
"buy_real_num0": 0.14,
|
||||
"buy_real_num1": 0.36,
|
||||
"buy_real_num2": 1.71
|
||||
},
|
||||
"sell": {
|
||||
"sell_candels": 40,
|
||||
"sell_percent": 0.0,
|
||||
"sell_percent3": 0.014
|
||||
},
|
||||
"protection": {
|
||||
"lookback": 133,
|
||||
"protection_max_allowed_dd": 0.71,
|
||||
"protection_stop": 61,
|
||||
"protection_stoploss_stop": 50,
|
||||
"trade_limit": 9
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-03-25 00:29:29.617986+00:00"
|
||||
}
|
||||
861
GodStraJD3_7_5_9.py
Normal file
861
GodStraJD3_7_5_9.py
Normal file
@@ -0,0 +1,861 @@
|
||||
# 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 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_9(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'},
|
||||
'open_1d': {'color': 'white'},
|
||||
'close_1d': {'color': 'white'}
|
||||
},
|
||||
'subplots': {
|
||||
# Subplots - each dict defines one additional plot
|
||||
"BB": {
|
||||
'bb_width': {'color': 'white'},
|
||||
'bb_lower_5': {'color': 'yellow'}
|
||||
},
|
||||
# "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 = True
|
||||
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_real_num0 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy')
|
||||
buy_real_num1 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy')
|
||||
buy_real_num2 = 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_1_percent_4h_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy')
|
||||
# buy_2_percent_4h_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy')
|
||||
# buy_3_percent_4h_num = DecimalParameter(-0.1, 0.1, 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_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_0_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_decalage_deb_0 = IntParameter(0, 3, default=5, space='buy')
|
||||
buy_decalage_deb_2 = IntParameter(0, 3, default=5, space='buy')
|
||||
buy_decalage_deb_3 = IntParameter(0, 3, default=5, space='buy')
|
||||
|
||||
buy_decalage0 = IntParameter(buy_decalage_deb_0.value + 1, 8, default=5, space='buy')
|
||||
buy_decalage2 = IntParameter(buy_decalage_deb_2.value + 1, 8, default=5, space='buy')
|
||||
buy_decalage3 = IntParameter(buy_decalage_deb_3.value + 1, 8, default=5, space='buy')
|
||||
|
||||
# buy_1_bb_lower_var_5 = DecimalParameter(0, 0.4, decimals=2, default=0.07, space='buy')
|
||||
# buy_2_bb_lower_var_5 = DecimalParameter(0, 0.4, decimals=2, default=0.07, space='buy')
|
||||
# buy_3_bb_lower_var_5 = DecimalParameter(0, 0.4, decimals=2, default=0.07, space='buy')
|
||||
|
||||
buy_1_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_2_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_3_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, 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')
|
||||
|
||||
sell_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell')
|
||||
sell_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell')
|
||||
sell_candels = IntParameter(0, 48, default=12, space='sell')
|
||||
|
||||
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.015) & (last_candle['percent3'] < -0.005):
|
||||
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.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 (current_profit > self.sell_percent.value) & (last_candle['percent3'] < - self.sell_percent3.value) \
|
||||
& ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_candels.value):
|
||||
return "quick_gain_param"
|
||||
|
||||
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, "4h") 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'] - dataframe['min50']).rolling(5).var()
|
||||
dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1)
|
||||
# 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_20'] = dataframe['normal'].rolling(20).var()
|
||||
dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var()
|
||||
|
||||
# dataframe['TR'] = ta.TRANGE(dataframe)
|
||||
# dataframe['ATR'] = ta.SMA(dataframe['TR'], 21)
|
||||
|
||||
# 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["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="4h")
|
||||
# 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()
|
||||
# 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, "4h", 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['max_open'] = ta.MAX(informative["open"], timeperiod=2)
|
||||
# informative['max_close'] = ta.MIN(informative["close"], timeperiod=2)
|
||||
# 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_decalage_deb_0.value, self.buy_decalage0.value):
|
||||
#if self.buy_0.value:
|
||||
conditions = list()
|
||||
condition1, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator0,
|
||||
buy_indicator0,
|
||||
buy_crossed_indicator0,
|
||||
self.buy_real_num0.value,
|
||||
self.buy_decalage0.value
|
||||
)
|
||||
conditions.append(condition1)
|
||||
dataframe.loc[
|
||||
(
|
||||
reduce(lambda x, y: x & y, conditions)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
& (dataframe['sma10'].shift(1) <= dataframe['sma10'])
|
||||
& (dataframe['close'] < dataframe['bb_middleband'])
|
||||
& (dataframe['open'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma20'])
|
||||
& (dataframe['min50'].shift(decalage) == dataframe['min50'])
|
||||
& (dataframe['min10'] <= dataframe['min50'] * 1.02)
|
||||
& (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value)
|
||||
# & (dataframe['min20'] == dataframe['min50'])
|
||||
& (dataframe['distance_min'] <= self.buy_0_distance.value)
|
||||
& ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(decalage) <= 0.005)
|
||||
# & (dataframe['bb_lower_var_5'] <= self.buy_1_bb_lower_var_5.value)
|
||||
& (dataframe['bb_lower_5'] <= self.buy_1_bb_lower_5.value)
|
||||
#& (dataframe['percent_1d'] >= self.buy_1_percent_1d_num.value)
|
||||
#& (dataframe['percent_4h'] > 0)
|
||||
#& (dataframe['percent3_4h'] <= self.buy_1_percent_4h_num.value)
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage))
|
||||
for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value):
|
||||
#if self.buy_2.value:
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_real_num0.value / 2)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (dataframe['sma10'].shift(1) <= dataframe['sma10'])
|
||||
& (dataframe['close'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma20'])
|
||||
& (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['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(
|
||||
decalage) <= 0.005)
|
||||
# & (dataframe['bb_lower_var_5'] <= self.buy_2_bb_lower_var_5.value)
|
||||
& (dataframe['bb_lower_5'] <= self.buy_2_bb_lower_5.value)
|
||||
#& (dataframe['percent_4h'] > 0)
|
||||
#& (dataframe['percent3_4h'] <= self.buy_2_percent_4h_num.value)
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage))
|
||||
for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value):
|
||||
#if self.buy_3.value:
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['cond1'].shift(decalage) <= 0.2)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (dataframe['sma10'].shift(1) <= dataframe['sma10'])
|
||||
& (dataframe['close'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma20'])
|
||||
& (dataframe['open'] < dataframe['sma10'])
|
||||
& (dataframe['min50'].shift(decalage) == dataframe['min50'])
|
||||
#& (dataframe['min10'] <= dataframe['min50'] * 1.02)
|
||||
& (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value)
|
||||
& (dataframe['distance_min'] <= self.buy_3_distance.value)
|
||||
& ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(
|
||||
decalage) <= 0.005)
|
||||
# & (dataframe['bb_lower_var_5'] <= self.buy_3_bb_lower_var_5.value)
|
||||
& (dataframe['bb_lower_5'] <= self.buy_3_bb_lower_5.value)
|
||||
#& (dataframe['percent_4h'] > 0)
|
||||
#& (dataframe['percent3_4h'] <= self.buy_3_percent_4h_num.value)
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage))
|
||||
|
||||
# dataframe.loc[
|
||||
# (
|
||||
# (dataframe['close'] < dataframe['close_1d'])
|
||||
# & (dataframe['close'] > dataframe['bb_upperband'])
|
||||
# ), ['buy', 'buy_tag']] = (1, 'buy_4')
|
||||
|
||||
# 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
|
||||
|
||||
67
GodStraJD3_7_5_9_1.json
Normal file
67
GodStraJD3_7_5_9_1.json
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_7_5_9_1",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.026,
|
||||
"trailing_stop_positive_offset": 0.077,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_0_distance": -0.03,
|
||||
"buy_0_percent20": -0.03,
|
||||
"buy_1_bb_lower_5": 0.19,
|
||||
"buy_1_pente_sma10": 0.48,
|
||||
"buy_1_pente_sma20": 0.33,
|
||||
"buy_2_bb_lower_5": 0.59,
|
||||
"buy_2_distance": 0.08,
|
||||
"buy_2_pente_sma10": 0.46,
|
||||
"buy_2_pente_sma20": 0.08,
|
||||
"buy_2_percent20": 0.06,
|
||||
"buy_3_bb_lower_5": 0.05,
|
||||
"buy_3_distance": 0.01,
|
||||
"buy_3_pente_sma10": 0.12,
|
||||
"buy_3_pente_sma20": 0.27,
|
||||
"buy_3_percent20": -0.03,
|
||||
"buy_4_pente_sma10": 0.35,
|
||||
"buy_4_pente_sma20": 0.22,
|
||||
"buy_decalage0": 7,
|
||||
"buy_decalage2": 6,
|
||||
"buy_decalage3": 7,
|
||||
"buy_decalage_deb_0": 1,
|
||||
"buy_decalage_deb_2": 1,
|
||||
"buy_decalage_deb_3": 1,
|
||||
"buy_min_horizon": 192,
|
||||
"buy_real_num0": 0.61,
|
||||
"buy_real_num1": 0.34,
|
||||
"buy_real_num2": 0.35
|
||||
},
|
||||
"sell": {
|
||||
"sell_RSI": 95,
|
||||
"sell_RSI2": 81,
|
||||
"sell_RSI2_percent": 0.008,
|
||||
"sell_candels": 17,
|
||||
"sell_percent": 0.016,
|
||||
"sell_percent3": 0.001,
|
||||
"sell_profit_no_change": 0.016,
|
||||
"sell_profit_percent10": 0.0002,
|
||||
"sell_too_old_day": 7,
|
||||
"sell_too_old_percent": 0.005
|
||||
},
|
||||
"protection": {
|
||||
"lookback": 133,
|
||||
"protection_max_allowed_dd": 0.71,
|
||||
"protection_stop": 61,
|
||||
"protection_stoploss_stop": 50,
|
||||
"trade_limit": 9
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-03-29 20:57:57.922162+00:00"
|
||||
}
|
||||
863
GodStraJD3_7_5_9_1.py
Normal file
863
GodStraJD3_7_5_9_1.py
Normal file
@@ -0,0 +1,863 @@
|
||||
# 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 logging
|
||||
import calendar
|
||||
from freqtrade.loggers import setup_logging
|
||||
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
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
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_9_1(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'},
|
||||
'open_1d': {'color': 'white'},
|
||||
'close_1d': {'color': 'white'}
|
||||
},
|
||||
'subplots': {
|
||||
# Subplots - each dict defines one additional plot
|
||||
"BB": {
|
||||
'bb_width': {'color': 'white'},
|
||||
'bb_lower_5': {'color': 'yellow'}
|
||||
},
|
||||
# "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 = True
|
||||
profit_old_sma10 = False
|
||||
profit_over_rsi = True
|
||||
profit_quick_gain = True
|
||||
profit_quick_gain_3 = True
|
||||
profit_quick_lost = True
|
||||
profit_short_loss = False
|
||||
profit_sma5 = True
|
||||
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_real_num0 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy')
|
||||
buy_real_num1 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy')
|
||||
buy_real_num2 = 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_1_percent_4h_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy')
|
||||
# buy_2_percent_4h_num = DecimalParameter(-0.1, 0.1, decimals=2, default=0.67, space='buy')
|
||||
# buy_3_percent_4h_num = DecimalParameter(-0.1, 0.1, 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_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_0_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_decalage_deb_0 = IntParameter(0, 3, default=5, space='buy')
|
||||
buy_decalage_deb_2 = IntParameter(0, 3, default=5, space='buy')
|
||||
buy_decalage_deb_3 = IntParameter(0, 3, default=5, space='buy')
|
||||
|
||||
buy_decalage0 = IntParameter(buy_decalage_deb_0.value + 1, 8, default=5, space='buy')
|
||||
buy_decalage2 = IntParameter(buy_decalage_deb_2.value + 1, 8, default=5, space='buy')
|
||||
buy_decalage3 = IntParameter(buy_decalage_deb_3.value + 1, 8, default=5, space='buy')
|
||||
|
||||
buy_1_pente_sma10 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_2_pente_sma10 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_3_pente_sma10 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_4_pente_sma10 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
|
||||
buy_1_pente_sma20 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_2_pente_sma20 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_3_pente_sma20 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_4_pente_sma20 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
|
||||
# buy_1_bb_lower_var_5 = DecimalParameter(0, 0.4, decimals=2, default=0.07, space='buy')
|
||||
# buy_2_bb_lower_var_5 = DecimalParameter(0, 0.4, decimals=2, default=0.07, space='buy')
|
||||
# buy_3_bb_lower_var_5 = DecimalParameter(0, 0.4, decimals=2, default=0.07, space='buy')
|
||||
|
||||
buy_1_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_2_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_3_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, 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')
|
||||
|
||||
sell_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell')
|
||||
sell_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell')
|
||||
sell_candels = IntParameter(0, 48, default=12, space='sell')
|
||||
|
||||
sell_too_old_day = IntParameter(0, 10, default=5, space='sell')
|
||||
sell_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell')
|
||||
|
||||
sell_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell')
|
||||
sell_profit_percent10 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell')
|
||||
|
||||
sell_RSI = IntParameter(70, 98, default=88, space='sell')
|
||||
sell_RSI2 = IntParameter(70, 98, default=88, space='sell')
|
||||
sell_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell')
|
||||
|
||||
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
|
||||
# },
|
||||
# {
|
||||
# "method": "EmergencyStop",
|
||||
# "min_percent": -0.05,
|
||||
# "candels": 1
|
||||
# }
|
||||
]
|
||||
|
||||
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 (current_profit > 0.015) & (last_candle['percent'] < -0.005):
|
||||
# return 'percent_quick'
|
||||
|
||||
# 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 >= - self.sell_too_old_percent.value) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value)\
|
||||
& ((current_time - trade.open_date_utc).days < self.sell_too_old_day.value * 2)\
|
||||
& (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0):
|
||||
return "too_old_0.01"
|
||||
if (current_profit >= - self.sell_too_old_percent.value * 2) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value * 2)\
|
||||
& ((current_time - trade.open_date_utc).days < self.sell_too_old_day.value * 3) \
|
||||
& (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0):
|
||||
return "too_old_0.02"
|
||||
if (current_profit >= - self.sell_too_old_percent.value * 3) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value * 3) \
|
||||
& (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0):
|
||||
return "too_old_0.03"
|
||||
|
||||
if self.profit_quick_lost and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005):
|
||||
return "quick_lost"
|
||||
|
||||
if self.profit_no_change and (current_profit > self.sell_profit_no_change.value) \
|
||||
& (last_candle['percent10'] < self.sell_profit_percent10.value) & (last_candle['percent5'] < 0) \
|
||||
& ((current_time - trade.open_date_utc).seconds >= 3600):
|
||||
return "no_change"
|
||||
|
||||
#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 (current_profit > self.sell_percent.value) & (last_candle['percent3'] < - self.sell_percent3.value) \
|
||||
& ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_candels.value):
|
||||
return "quick_gain_param"
|
||||
|
||||
if self.profit_sma5:
|
||||
if (current_profit > 0.01) \
|
||||
& ((previous_5_candle['sma5'] > last_candle['sma5']) \
|
||||
| (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_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'] > self.sell_RSI.value): # & (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'] > self.sell_RSI2.value) & \
|
||||
(last_candle['percent'] < - self.sell_RSI2_percent.value): #| (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, "4h") 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['sma5'] = ta.SMA(dataframe, timeperiod=5)
|
||||
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'] - dataframe['min50']).rolling(5).var()
|
||||
dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1)
|
||||
# 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_20'] = dataframe['normal'].rolling(20).var()
|
||||
dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var()
|
||||
|
||||
# dataframe['TR'] = ta.TRANGE(dataframe)
|
||||
# dataframe['ATR'] = ta.SMA(dataframe['TR'], 21)
|
||||
|
||||
# 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["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="4h")
|
||||
# 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()
|
||||
# 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, "4h", 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['max_open'] = ta.MAX(informative["open"], timeperiod=2)
|
||||
# informative['max_close'] = ta.MIN(informative["close"], timeperiod=2)
|
||||
# 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_decalage_deb_0.value, self.buy_decalage0.value):
|
||||
#if self.buy_0.value:
|
||||
conditions = list()
|
||||
condition1, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator0,
|
||||
buy_indicator0,
|
||||
buy_crossed_indicator0,
|
||||
self.buy_real_num0.value,
|
||||
self.buy_decalage0.value
|
||||
)
|
||||
conditions.append(condition1)
|
||||
dataframe.loc[
|
||||
(
|
||||
reduce(lambda x, y: x & y, conditions)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
& (dataframe['sma10'].shift(1) <= dataframe['sma10'])
|
||||
& (dataframe['bb_width'] >= 0.05)
|
||||
& (dataframe['close'] < dataframe['bb_middleband'])
|
||||
& (dataframe['open'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma20'])
|
||||
& (dataframe['min50'].shift(decalage) == dataframe['min50'])
|
||||
& (dataframe['min10'] <= dataframe['min50'] * 1.02)
|
||||
& (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value)
|
||||
# & (dataframe['min20'] == dataframe['min50'])
|
||||
& (dataframe['distance_min'] <= self.buy_0_distance.value)
|
||||
& ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(decalage) <= 0.005)
|
||||
# & (dataframe['bb_lower_var_5'] <= self.buy_1_bb_lower_var_5.value)
|
||||
& (dataframe['bb_lower_5'] <= self.buy_1_bb_lower_5.value)
|
||||
#& (dataframe['percent_1d'] >= self.buy_1_percent_1d_num.value)
|
||||
#& (dataframe['percent_4h'] > 0)
|
||||
#& (dataframe['percent3_4h'] <= self.buy_1_percent_4h_num.value)
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage))
|
||||
for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value):
|
||||
#if self.buy_2.value:
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_real_num0.value / 2)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (dataframe['sma10'].shift(1) <= dataframe['sma10'])
|
||||
& (dataframe['bb_width'] >= 0.05)
|
||||
& (dataframe['close'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma20'])
|
||||
& (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['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(
|
||||
decalage) <= 0.005)
|
||||
# & (dataframe['bb_lower_var_5'] <= self.buy_2_bb_lower_var_5.value)
|
||||
& (dataframe['bb_lower_5'] <= self.buy_2_bb_lower_5.value)
|
||||
#& (dataframe['percent_4h'] > 0)
|
||||
#& (dataframe['percent3_4h'] <= self.buy_2_percent_4h_num.value)
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage))
|
||||
for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value):
|
||||
#if self.buy_3.value:
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['cond1'].shift(decalage) <= 0.2)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (dataframe['sma10'].shift(1) <= dataframe['sma10'])
|
||||
& (dataframe['bb_width'] >= 0.05)
|
||||
& (dataframe['close'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma20'])
|
||||
& (dataframe['open'] < dataframe['sma10'])
|
||||
& (dataframe['min50'].shift(decalage) == dataframe['min50'])
|
||||
#& (dataframe['min10'] <= dataframe['min50'] * 1.02)
|
||||
& (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value)
|
||||
& (dataframe['distance_min'] <= self.buy_3_distance.value)
|
||||
& ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(
|
||||
decalage) <= 0.005)
|
||||
# & (dataframe['bb_lower_var_5'] <= self.buy_3_bb_lower_var_5.value)
|
||||
& (dataframe['bb_lower_5'] <= self.buy_3_bb_lower_5.value)
|
||||
#& (dataframe['percent_4h'] > 0)
|
||||
#& (dataframe['percent3_4h'] <= self.buy_3_percent_4h_num.value)
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage))
|
||||
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
return dataframe
|
||||
|
||||
97
GodStraJD3_7_5_9_2.json
Normal file
97
GodStraJD3_7_5_9_2.json
Normal file
@@ -0,0 +1,97 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_7_5_9_2",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.026,
|
||||
"trailing_stop_positive_offset": 0.077,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_0_distance": -0.05,
|
||||
"buy_0_percent20": 0.04,
|
||||
"buy_1_bb_lower_5": 0.36,
|
||||
"buy_1_pente_sma10": 0.22,
|
||||
"buy_1_pente_sma20": 0.6,
|
||||
"buy_2_bb_lower_5": 0.23,
|
||||
"buy_2_distance": 0.09,
|
||||
"buy_2_pente_sma10": 0.36,
|
||||
"buy_2_pente_sma20": 0.46,
|
||||
"buy_2_percent20": 0.02,
|
||||
"buy_3_bb_lower_5": 0.48,
|
||||
"buy_3_distance": 0.01,
|
||||
"buy_3_pente_sma10": 0.53,
|
||||
"buy_3_pente_sma20": 0.11,
|
||||
"buy_3_percent20": -0.09,
|
||||
"buy_4_pente_sma10": 0.48,
|
||||
"buy_4_pente_sma20": 0.38,
|
||||
"buy_bb_lowerband": 1.02,
|
||||
"buy_bb_width": 0.08,
|
||||
"buy_cat": "<R",
|
||||
"buy_decalage0": 6,
|
||||
"buy_decalage2": 6,
|
||||
"buy_decalage3": 8,
|
||||
"buy_decalage_deb_0": 3,
|
||||
"buy_decalage_deb_2": 0,
|
||||
"buy_decalage_deb_3": 2,
|
||||
"buy_min_horizon": 179,
|
||||
"buy_pct": 0.001,
|
||||
"buy_pct_1": 0.0,
|
||||
"buy_pct_3": 0.0,
|
||||
"buy_pct_5": 0.0,
|
||||
"buy_real": 0.3488,
|
||||
"buy_real_num0": 0.88,
|
||||
"buy_real_num1": 0.25,
|
||||
"buy_real_num2": 0.59
|
||||
},
|
||||
"sell": {
|
||||
"profit_h_no_change": false,
|
||||
"profit_h_old_sma10": false,
|
||||
"profit_h_over_rsi": true,
|
||||
"profit_h_quick_gain": true,
|
||||
"profit_h_quick_gain_3": true,
|
||||
"profit_h_quick_lost": false,
|
||||
"profit_h_short_loss": true,
|
||||
"profit_h_sma10": false,
|
||||
"profit_h_sma20": true,
|
||||
"profit_h_sma5": false,
|
||||
"profit_h_very_old_sma10": false,
|
||||
"profit_no_change": true,
|
||||
"profit_old_sma10": true,
|
||||
"profit_over_rsi": false,
|
||||
"profit_quick_gain": false,
|
||||
"profit_quick_gain_3": false,
|
||||
"profit_quick_lost": false,
|
||||
"profit_short_loss": false,
|
||||
"profit_sma10": true,
|
||||
"profit_sma20": false,
|
||||
"profit_sma5": true,
|
||||
"profit_very_old_sma10": true,
|
||||
"sell_RSI": 96,
|
||||
"sell_RSI2": 93,
|
||||
"sell_RSI2_percent": 0.005,
|
||||
"sell_candels": 10,
|
||||
"sell_percent": 0.008,
|
||||
"sell_percent3": 0.013,
|
||||
"sell_profit_no_change": 0.009,
|
||||
"sell_profit_percent10": 0.0016,
|
||||
"sell_too_old_day": 10,
|
||||
"sell_too_old_percent": 0.001
|
||||
},
|
||||
"protection": {
|
||||
"lookback": 133,
|
||||
"protection_max_allowed_dd": 0.71,
|
||||
"protection_stop": 61,
|
||||
"protection_stoploss_stop": 50,
|
||||
"trade_limit": 9
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-04-02 11:22:43.739711+00:00"
|
||||
}
|
||||
811
GodStraJD3_7_5_9_2.py
Normal file
811
GodStraJD3_7_5_9_2.py
Normal file
@@ -0,0 +1,811 @@
|
||||
# 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 logging
|
||||
import ta as ta2
|
||||
import calendar
|
||||
from freqtrade.loggers import setup_logging
|
||||
from freqtrade.strategy.strategy_helper import merge_informative_pair
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# Add your lib to import here
|
||||
# TODO: ta 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
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
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_9_2(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'},
|
||||
'open_1d': {'color': 'white'},
|
||||
'close_1d': {'color': 'white'}
|
||||
},
|
||||
'subplots': {
|
||||
# Subplots - each dict defines one additional plot
|
||||
"BB": {
|
||||
'bb_width': {'color': 'white'},
|
||||
'bb_lower_5': {'color': 'yellow'}
|
||||
},
|
||||
# "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 ####################
|
||||
|
||||
trades = list()
|
||||
profit_no_change = BooleanParameter(default=True, space="sell")
|
||||
profit_quick_lost = BooleanParameter(default=True, space="sell")
|
||||
profit_sma5 = BooleanParameter(default=True, space="sell")
|
||||
profit_sma10 = BooleanParameter(default=True, space="sell")
|
||||
profit_sma20 = BooleanParameter(default=True, space="sell")
|
||||
profit_quick_gain = BooleanParameter(default=True, space="sell")
|
||||
profit_quick_gain_3 = BooleanParameter(default=True, space="sell")
|
||||
profit_old_sma10 = BooleanParameter(default=True, space="sell")
|
||||
profit_very_old_sma10 = BooleanParameter(default=True, space="sell")
|
||||
profit_over_rsi = BooleanParameter(default=True, space="sell")
|
||||
profit_short_loss = BooleanParameter(default=True, space="sell")
|
||||
|
||||
profit_h_no_change = BooleanParameter(default=True, space="sell")
|
||||
profit_h_quick_lost = BooleanParameter(default=True, space="sell")
|
||||
profit_h_sma5 = BooleanParameter(default=True, space="sell")
|
||||
profit_h_sma10 = BooleanParameter(default=True, space="sell")
|
||||
profit_h_sma20 = BooleanParameter(default=True, space="sell")
|
||||
profit_h_quick_gain = BooleanParameter(default=True, space="sell")
|
||||
profit_h_quick_gain_3 = BooleanParameter(default=True, space="sell")
|
||||
profit_h_old_sma10 = BooleanParameter(default=True, space="sell")
|
||||
profit_h_very_old_sma10 = BooleanParameter(default=True, space="sell")
|
||||
profit_h_over_rsi = BooleanParameter(default=True, space="sell")
|
||||
profit_h_short_loss = BooleanParameter(default=True, space="sell")
|
||||
|
||||
# buy_signal_bb_width = DecimalParameter(0.06, 0.15, decimals=2, default=0.065, space='buy')
|
||||
buy_real = DecimalParameter(0.001, 0.999, decimals=4, default=0.11908, space='buy')
|
||||
buy_cat = CategoricalParameter([">R", "=R", "<R"], default='<R', space='buy')
|
||||
buy_pct = DecimalParameter(0.001, 0.02, decimals=3, default=0.005, space='buy')
|
||||
buy_pct_1 = DecimalParameter(-0.2, 0.2, decimals=2, default=0.005, space='buy')
|
||||
buy_pct_3 = DecimalParameter(-0.2, 0.2, decimals=2, default=0.005, space='buy')
|
||||
buy_pct_5 = DecimalParameter(-0.2, 0.2, decimals=2, default=0.005, space='buy')
|
||||
buy_bb_lowerband = DecimalParameter(1, 1.05, default=1, decimals=2, space='buy')
|
||||
buy_bb_width = DecimalParameter(0.01, 0.15, default=0.065, decimals=2, space='buy')
|
||||
|
||||
buy_real_num0 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy')
|
||||
buy_real_num1 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy')
|
||||
buy_real_num2 = DecimalParameter(0, 2, decimals=2, default=0.67, space='buy')
|
||||
|
||||
buy_min_horizon = IntParameter(50, 200, default=72, 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_0_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_decalage_deb_0 = IntParameter(0, 3, default=5, space='buy')
|
||||
buy_decalage_deb_2 = IntParameter(0, 3, default=5, space='buy')
|
||||
buy_decalage_deb_3 = IntParameter(0, 3, default=5, space='buy')
|
||||
|
||||
buy_decalage0 = IntParameter(buy_decalage_deb_0.value + 1, 8, default=5, space='buy')
|
||||
buy_decalage2 = IntParameter(buy_decalage_deb_2.value + 1, 8, default=5, space='buy')
|
||||
buy_decalage3 = IntParameter(buy_decalage_deb_3.value + 1, 8, default=5, space='buy')
|
||||
|
||||
buy_1_pente_sma10 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_2_pente_sma10 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_3_pente_sma10 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_4_pente_sma10 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
|
||||
buy_1_pente_sma20 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_2_pente_sma20 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_3_pente_sma20 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_4_pente_sma20 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
|
||||
buy_1_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_2_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, space='buy')
|
||||
buy_3_bb_lower_5 = DecimalParameter(0, 0.6, decimals=2, default=0.7, 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')
|
||||
|
||||
sell_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell')
|
||||
sell_percent3 = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell')
|
||||
sell_candels = IntParameter(0, 48, default=12, space='sell')
|
||||
|
||||
sell_too_old_day = IntParameter(0, 10, default=5, space='sell')
|
||||
sell_too_old_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell')
|
||||
|
||||
sell_profit_no_change = DecimalParameter(0, 0.02, decimals=3, default=0.005, space='sell')
|
||||
sell_profit_percent10 = DecimalParameter(0, 0.002, decimals=4, default=0.001, space='sell')
|
||||
|
||||
sell_RSI = IntParameter(70, 98, default=88, space='sell')
|
||||
sell_RSI2 = IntParameter(70, 98, default=88, space='sell')
|
||||
sell_RSI2_percent = DecimalParameter(0, 0.02, decimals=3, default=0.01, space='sell')
|
||||
|
||||
@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
|
||||
# },
|
||||
# {
|
||||
# "method": "EmergencyStop",
|
||||
# "min_percent": -0.05,
|
||||
# "candels": 1
|
||||
# }
|
||||
]
|
||||
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()
|
||||
|
||||
expected_profit = 0.01
|
||||
# if (last_candle['pct_change_1_1d'] < 0):
|
||||
# expected_profit = self.sell_expected_profit.value
|
||||
#
|
||||
# if (current_profit > expected_profit) & (last_candle['pct_change_1_1d'] < 0):
|
||||
# return "exp_profit_down"
|
||||
|
||||
if (current_profit >= - self.sell_too_old_percent.value) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value)\
|
||||
& ((current_time - trade.open_date_utc).days < self.sell_too_old_day.value * 2)\
|
||||
& (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0):
|
||||
return "too_old_0.01"
|
||||
if (current_profit >= - self.sell_too_old_percent.value * 2) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value * 2)\
|
||||
& ((current_time - trade.open_date_utc).days < self.sell_too_old_day.value * 3) \
|
||||
& (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0):
|
||||
return "too_old_0.02"
|
||||
if (current_profit >= - self.sell_too_old_percent.value * 3) & ((current_time - trade.open_date_utc).days >= self.sell_too_old_day.value * 3) \
|
||||
& (previous_last_candle['sma10'] > last_candle['sma10']) & (last_candle['percent3'] < 0):
|
||||
return "too_old_0.03"
|
||||
|
||||
if (last_candle['pct_change_1_1d'] > 0):
|
||||
if self.profit_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005):
|
||||
return "quick_lost"
|
||||
|
||||
if self.profit_no_change.value and (current_profit > self.sell_profit_no_change.value) \
|
||||
& (last_candle['percent10'] < self.sell_profit_percent10.value) & (last_candle['percent5'] < 0) \
|
||||
& ((current_time - trade.open_date_utc).seconds >= 3600):
|
||||
return "no_change"
|
||||
|
||||
if (current_profit > self.sell_percent.value) & (last_candle['percent3'] < - self.sell_percent3.value) \
|
||||
& ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_candels.value):
|
||||
return "quick_gain_param"
|
||||
|
||||
if self.profit_sma5.value:
|
||||
if (current_profit > expected_profit) \
|
||||
& ((previous_5_candle['sma5'] > last_candle['sma5']) \
|
||||
| (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \
|
||||
& ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)):
|
||||
# print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
|
||||
return 'sma5'
|
||||
|
||||
if self.profit_sma10.value:
|
||||
if (current_profit > expected_profit) \
|
||||
& ((previous_5_candle['sma10'] > last_candle['sma10']) \
|
||||
| (last_candle['percent3'] < -expected_profit) | (last_candle['percent5'] < -expected_profit)) \
|
||||
& ((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.value:
|
||||
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_over_rsi.value:
|
||||
if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_RSI.value): # & (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'] > self.sell_RSI2.value) & \
|
||||
(last_candle['percent'] < - self.sell_RSI2_percent.value): #| (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.value:
|
||||
if (current_profit > -expected_profit) & (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'
|
||||
else:
|
||||
if self.profit_h_quick_lost.value and (current_profit >= 0.015) & (last_candle['percent3'] < -0.005):
|
||||
return "h_quick_lost"
|
||||
|
||||
if self.profit_h_no_change.value and (current_profit > self.sell_profit_no_change.value) \
|
||||
& (last_candle['percent10'] < self.sell_profit_percent10.value) & (last_candle['percent5'] < 0) \
|
||||
& ((current_time - trade.open_date_utc).seconds >= 3600):
|
||||
return "h_no_change"
|
||||
|
||||
if (current_profit > self.sell_percent.value) & (last_candle['percent3'] < - self.sell_percent3.value) \
|
||||
& ((current_time - trade.open_date_utc).seconds <= 300 * self.sell_candels.value):
|
||||
return "h_quick_gain_param"
|
||||
|
||||
if self.profit_h_sma5.value:
|
||||
if (current_profit > expected_profit) \
|
||||
& ((previous_5_candle['sma5'] > last_candle['sma5']) \
|
||||
| (last_candle['percent3'] < -expected_profit) | (
|
||||
last_candle['percent5'] < -expected_profit)) \
|
||||
& ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)):
|
||||
# print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
|
||||
return 'h_sma5'
|
||||
|
||||
if self.profit_h_sma10.value:
|
||||
if (current_profit > expected_profit) \
|
||||
& ((previous_5_candle['sma10'] > last_candle['sma10']) \
|
||||
| (last_candle['percent3'] < -expected_profit) | (
|
||||
last_candle['percent5'] < -expected_profit)) \
|
||||
& ((last_candle['percent'] < 0) & (last_candle['percent3'] < 0)):
|
||||
# print("over_bb_band_sma10_desc", pair, trade, " profit=", current_profit, " rate=", current_rate)
|
||||
return 'h_sma10'
|
||||
|
||||
if self.profit_h_sma20.value:
|
||||
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 'h_sma20'
|
||||
|
||||
if self.profit_h_over_rsi.value:
|
||||
if (current_profit > 0) & (previous_last_candle[
|
||||
'rsi'] > self.sell_RSI.value): # & (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 'h_over_rsi'
|
||||
|
||||
if (current_profit > 0) & (previous_last_candle['rsi'] > self.sell_RSI2.value) & \
|
||||
(last_candle[
|
||||
'percent'] < - self.sell_RSI2_percent.value): # | (previous_last_candle['rsi'] > 75 & last_candle['rsi'] < 70)):
|
||||
# print("over_rsi", pair, trade, " profit=", current_profit, " rate=", current_rate)
|
||||
return 'h_over_rsi_2'
|
||||
|
||||
if self.profit_h_short_loss.value:
|
||||
if (current_profit > -expected_profit) & (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 'h_short_lost'
|
||||
|
||||
def informative_pairs(self):
|
||||
pairs = self.dp.current_whitelist()
|
||||
informative_pairs = [(pair, '1d') for pair in pairs]
|
||||
return informative_pairs
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
# dataframe['profit'] = 0
|
||||
# RSI
|
||||
dataframe['trend_ichimoku_base'] = ta2.trend.ichimoku_base_line(
|
||||
dataframe['high'],
|
||||
dataframe['low'],
|
||||
window1=9,
|
||||
window2=26,
|
||||
visual=False,
|
||||
fillna=False
|
||||
)
|
||||
KST = ta2.trend.KSTIndicator(
|
||||
close=dataframe['close'],
|
||||
roc1=10,
|
||||
roc2=15,
|
||||
roc3=20,
|
||||
roc4=30,
|
||||
window1=10,
|
||||
window2=10,
|
||||
window3=10,
|
||||
window4=15,
|
||||
nsig=9,
|
||||
fillna=False
|
||||
)
|
||||
|
||||
dataframe['trend_kst_diff'] = KST.kst_diff()
|
||||
dataframe['pct_change'] = dataframe['close'].pct_change(5)
|
||||
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['max50'] = ta.MAX(dataframe['close'], timeperiod=50)
|
||||
dataframe['max200'] = ta.MAX(dataframe['close'], timeperiod=200)
|
||||
dataframe['rsi'] = ta.RSI(dataframe)
|
||||
dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5)
|
||||
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()
|
||||
|
||||
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'] - dataframe['min50']).rolling(5).var()
|
||||
dataframe['bb_lower_5'] = 100 * ((dataframe['bb_lowerband'].rolling(5).mean() / dataframe['bb_lowerband']) - 1)
|
||||
# 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_20'] = dataframe['normal'].rolling(20).var()
|
||||
dataframe['normal_var_50'] = dataframe['normal'].rolling(50).var()
|
||||
|
||||
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])
|
||||
|
||||
# Normalization
|
||||
tib = dataframe['trend_ichimoku_base']
|
||||
dataframe['trend_ichimoku_base'] = (tib-tib.min())/(tib.max()-tib.min())
|
||||
tkd = dataframe['trend_kst_diff']
|
||||
dataframe['trend_kst_diff'] = (tkd-tkd.min())/(tkd.max()-tkd.min())
|
||||
|
||||
informative = self.dp.get_pair_dataframe(pair=metadata['pair'], timeframe="1d")
|
||||
informative["rsi"] = ta.RSI(informative)
|
||||
informative["max3"] = ta.MAX(informative['close'], timeperiod=3)
|
||||
informative["min3"] = ta.MIN(informative['close'], timeperiod=3)
|
||||
informative['pct_change_1'] = informative['close'].pct_change(1)
|
||||
informative['pct_change_3'] = informative['close'].pct_change(3)
|
||||
informative['pct_change_5'] = informative['close'].pct_change(5)
|
||||
informative['sma3'] = ta.SMA(informative, timeperiod=3)
|
||||
informative['sma5'] = ta.SMA(informative, timeperiod=5)
|
||||
informative['sma10'] = ta.SMA(informative, timeperiod=10)
|
||||
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(informative), window=20, stds=2)
|
||||
informative['bb_lowerband'] = bollinger['lower']
|
||||
informative['bb_middleband'] = bollinger['mid']
|
||||
informative['bb_upperband'] = bollinger['upper']
|
||||
informative["bb_percent"] = (
|
||||
(informative["close"] - informative["bb_lowerband"]) /
|
||||
(informative["bb_upperband"] - informative["bb_lowerband"])
|
||||
)
|
||||
informative["bb_width"] = (
|
||||
(informative["bb_upperband"] - informative["bb_lowerband"]) / informative["bb_middleband"]
|
||||
)
|
||||
|
||||
dataframe = merge_informative_pair(dataframe, informative, self.timeframe, "1d", ffill=True)
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
for decalage in range(self.buy_decalage_deb_0.value, self.buy_decalage0.value):
|
||||
#if self.buy_0.value:
|
||||
conditions = list()
|
||||
condition1, dataframe = condition_generator(
|
||||
dataframe,
|
||||
buy_operator0,
|
||||
buy_indicator0,
|
||||
buy_crossed_indicator0,
|
||||
self.buy_real_num0.value,
|
||||
self.buy_decalage0.value
|
||||
)
|
||||
conditions.append(condition1)
|
||||
dataframe.loc[
|
||||
(
|
||||
reduce(lambda x, y: x & y, conditions)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
& (dataframe['sma10'].shift(1) <= dataframe['sma10'])
|
||||
& (dataframe['close'] < dataframe['bb_middleband'])
|
||||
& (dataframe['open'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma20'])
|
||||
& (dataframe['min50'].shift(decalage) == dataframe['min50'])
|
||||
& (dataframe['min10'] <= dataframe['min50'] * 1.02)
|
||||
& (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value)
|
||||
# & (dataframe['min20'] == dataframe['min50'])
|
||||
& (dataframe['distance_min'] <= self.buy_0_distance.value)
|
||||
& ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(decalage) <= 0.005)
|
||||
# & (dataframe['bb_lower_var_5'] <= self.buy_1_bb_lower_var_5.value)
|
||||
& (dataframe['bb_lower_5'] <= self.buy_1_bb_lower_5.value)
|
||||
#& (dataframe['percent_1d'] >= self.buy_1_percent_1d_num.value)
|
||||
#& (dataframe['percent_4h'] > 0)
|
||||
#& (dataframe['percent3_4h'] <= self.buy_1_percent_4h_num.value)
|
||||
& (dataframe['pct_change_1_1d'] < self.buy_pct_1.value)
|
||||
& (dataframe['pct_change_3_1d'] < self.buy_pct_3.value)
|
||||
& (dataframe['pct_change_5_1d'] < self.buy_pct_5.value)
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage))
|
||||
for decalage in range(self.buy_decalage_deb_2.value, self.buy_decalage2.value):
|
||||
#if self.buy_2.value:
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['cond1'].shift(decalage) <= 0.45) #self.buy_real_num0.value / 2)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (dataframe['sma10'].shift(1) <= dataframe['sma10'])
|
||||
& (dataframe['close'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma20'])
|
||||
& (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['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(
|
||||
decalage) <= 0.005)
|
||||
# & (dataframe['bb_lower_var_5'] <= self.buy_2_bb_lower_var_5.value)
|
||||
& (dataframe['bb_lower_5'] <= self.buy_2_bb_lower_5.value)
|
||||
#& (dataframe['percent_4h'] > 0)
|
||||
#& (dataframe['percent3_4h'] <= self.buy_2_percent_4h_num.value)
|
||||
& (dataframe['pct_change_1_1d'] < self.buy_pct_1.value)
|
||||
& (dataframe['pct_change_3_1d'] < self.buy_pct_3.value)
|
||||
& (dataframe['pct_change_5_1d'] < self.buy_pct_5.value)
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_2_' + str(decalage))
|
||||
for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value):
|
||||
#if self.buy_3.value:
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['cond1'].shift(decalage) <= 0.2)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (dataframe['sma10'].shift(1) <= dataframe['sma10'])
|
||||
& (dataframe['close'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma20'])
|
||||
& (dataframe['open'] < dataframe['sma10'])
|
||||
& (dataframe['min50'].shift(decalage) == dataframe['min50'])
|
||||
#& (dataframe['min10'] <= dataframe['min50'] * 1.02)
|
||||
& (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value)
|
||||
& (dataframe['distance_min'] <= self.buy_3_distance.value)
|
||||
& ((dataframe['close'] - dataframe['open'].shift(decalage)) / dataframe['open'].shift(
|
||||
decalage) <= 0.005)
|
||||
# & (dataframe['bb_lower_var_5'] <= self.buy_3_bb_lower_var_5.value)
|
||||
& (dataframe['bb_lower_5'] <= self.buy_3_bb_lower_5.value)
|
||||
#& (dataframe['percent_4h'] > 0)
|
||||
#& (dataframe['percent3_4h'] <= self.buy_3_percent_4h_num.value)
|
||||
& (dataframe['pct_change_1_1d'] < self.buy_pct_1.value)
|
||||
& (dataframe['pct_change_3_1d'] < self.buy_pct_3.value)
|
||||
& (dataframe['pct_change_5_1d'] < self.buy_pct_5.value)
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_3_' + str(decalage))
|
||||
|
||||
conditions = []
|
||||
IND = 'trend_ichimoku_base'
|
||||
REAL = self.buy_real.value
|
||||
OPR = self.buy_cat.value
|
||||
DFIND = dataframe[IND]
|
||||
# print(DFIND.mean())
|
||||
if OPR == ">R":
|
||||
conditions.append(DFIND > REAL)
|
||||
elif OPR == "=R":
|
||||
conditions.append(np.isclose(DFIND, REAL))
|
||||
elif OPR == "<R":
|
||||
conditions.append(DFIND < REAL)
|
||||
|
||||
if conditions:
|
||||
dataframe.loc[
|
||||
(reduce(lambda x, y: x & y, conditions))
|
||||
& (dataframe['pct_change'] < - self.buy_pct.value)
|
||||
& (dataframe['close'] <= dataframe['min200'] * 1.002)
|
||||
& (dataframe['pct_change_1_1d'] > self.buy_pct_1.value)
|
||||
& (dataframe['pct_change_3_1d'] > self.buy_pct_3.value)
|
||||
& (dataframe['pct_change_5_1d'] > self.buy_pct_5.value)
|
||||
#& (dataframe['close_1d'] < dataframe['bb_lowerband_1d'] * self.buy_bb_lowerband.value)
|
||||
& (dataframe['bb_width_1d'] >= self.buy_bb_width.value)
|
||||
& (dataframe['close'] <= dataframe['sma5_1d'])
|
||||
& (dataframe['sma10_1d'].shift(1) <= dataframe['sma10_1d'])
|
||||
,
|
||||
'buy'] = 1
|
||||
return dataframe
|
||||
|
||||
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
return dataframe
|
||||
|
||||
63
GodStraJD3_7_6.json
Normal file
63
GodStraJD3_7_6.json
Normal file
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_7_6",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.026,
|
||||
"trailing_stop_positive_offset": 0.077,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_1_distance": 0.06,
|
||||
"buy_1_percent20": -0.04,
|
||||
"buy_3_distance": 0.01,
|
||||
"buy_3_percent20": 0.08,
|
||||
"buy_decalage1": 8,
|
||||
"buy_decalage3": 7,
|
||||
"buy_decalage_deb_1": 2,
|
||||
"buy_decalage_deb_3": 3,
|
||||
"buy_min_horizon": 111,
|
||||
"buy_real_num1": 0.77,
|
||||
"buy_real_num3": 0.52
|
||||
},
|
||||
"sell": {
|
||||
"profit_no_change": false,
|
||||
"profit_old_sma10": true,
|
||||
"profit_over_rsi": false,
|
||||
"profit_over_rsi2_percent": 0.002,
|
||||
"profit_over_rsi_max_rsi": 90,
|
||||
"profit_over_rsi_max_rsi2": 94,
|
||||
"profit_quick_gain": false,
|
||||
"profit_quick_gain_3": false,
|
||||
"profit_quick_lost": true,
|
||||
"profit_quick_lost_max": 0.0,
|
||||
"profit_quick_lost_max_profit": 0.013,
|
||||
"profit_short_loss": true,
|
||||
"profit_sma10": true,
|
||||
"profit_sma10_current_profit": 0.027,
|
||||
"profit_sma10_facteur": 1.0,
|
||||
"profit_sma20": true,
|
||||
"profit_sma20_current_profit": 0.021,
|
||||
"profit_sma20_facteur": 1.006,
|
||||
"profit_too_old": true,
|
||||
"profit_too_old_days": 9,
|
||||
"profit_too_old_max": 0.02,
|
||||
"profit_very_old_sma10": false
|
||||
},
|
||||
"protection": {
|
||||
"lookback": 133,
|
||||
"protection_max_allowed_dd": 0.71,
|
||||
"protection_stop": 61,
|
||||
"protection_stoploss_stop": 50,
|
||||
"trade_limit": 9
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-03-12 10:23:55.007196+00:00"
|
||||
}
|
||||
787
GodStraJD3_7_6.py
Normal file
787
GodStraJD3_7_6.py
Normal file
@@ -0,0 +1,787 @@
|
||||
# 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
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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_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": {
|
||||
'ecart_20': {'color': 'red'},
|
||||
'ecart_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 = False
|
||||
# profit_sma20 = True
|
||||
# profit_very_old_sma10 = False
|
||||
|
||||
trades = list()
|
||||
profit_too_old = BooleanParameter(default=True, space="sell")
|
||||
profit_no_change = BooleanParameter(default=True, space="sell")
|
||||
profit_quick_lost = BooleanParameter(default=True, space="sell")
|
||||
profit_sma10 = BooleanParameter(default=True, space="sell")
|
||||
profit_sma20 = BooleanParameter(default=True, space="sell")
|
||||
profit_quick_gain = BooleanParameter(default=True, space="sell")
|
||||
profit_quick_gain_3 = BooleanParameter(default=True, space="sell")
|
||||
profit_old_sma10 = BooleanParameter(default=True, space="sell")
|
||||
profit_very_old_sma10 = BooleanParameter(default=True, space="sell")
|
||||
profit_over_rsi = BooleanParameter(default=True, space="sell")
|
||||
profit_short_loss = BooleanParameter(default=True, space="sell")
|
||||
|
||||
profit_too_old_max = DecimalParameter(0, 0.05, decimals=2, default=0.01, space='sell')
|
||||
profit_too_old_days = IntParameter(1, 10, default=5, space='sell')
|
||||
profit_quick_lost_max = DecimalParameter(0, 0.03, decimals=3, default=0.015, space='sell')
|
||||
profit_quick_lost_max_profit = DecimalParameter(0, 0.03, decimals=3, default=0.015, space='sell')
|
||||
profit_sma10_current_profit = DecimalParameter(0, 0.03, decimals=3, default=0.015, space='sell')
|
||||
profit_sma10_facteur = DecimalParameter(1, 1.01, decimals=3, default=1.005, space='sell')
|
||||
|
||||
profit_sma20_current_profit = DecimalParameter(0, 0.03, decimals=3, default=0.015, space='sell')
|
||||
profit_sma20_facteur = DecimalParameter(1, 1.01, decimals=3, default=1.005, space='sell')
|
||||
|
||||
profit_over_rsi_max_rsi = IntParameter(70, 100, default=88, space='sell')
|
||||
profit_over_rsi_max_rsi2 = IntParameter(70, 100, default=82, space='sell')
|
||||
|
||||
profit_over_rsi2_percent = DecimalParameter(0, 0.05, decimals=3, default=0.02, space='sell')
|
||||
|
||||
# buy_signal_bb_width = DecimalParameter(0.06, 0.15, decimals=2, default=0.065, space='buy')
|
||||
|
||||
# buy_real_num0 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy')
|
||||
buy_real_num1 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy')
|
||||
buy_real_num3 = 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_1_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_0_distance = 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_3_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy')
|
||||
|
||||
# buy_decalage_deb_0 = IntParameter(1, 3, default=5, space='buy')
|
||||
buy_decalage_deb_1 = IntParameter(1, 3, default=5, space='buy')
|
||||
buy_decalage_deb_3 = IntParameter(1, 3, default=5, space='buy')
|
||||
|
||||
# buy_decalage0 = IntParameter(buy_decalage_deb_0.value + 1, 8, default=5, space='buy')
|
||||
buy_decalage1 = IntParameter(buy_decalage_deb_1.value + 1, 8, default=5, space='buy')
|
||||
buy_decalage3 = IntParameter(buy_decalage_deb_3.value + 1, 8, default=5, 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')
|
||||
|
||||
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 self.profit_too_old.value:
|
||||
if (current_profit >= - self.profit_too_old_max.value) \
|
||||
& ((current_time - trade.open_date_utc).days >= self.profit_too_old_days.value)\
|
||||
& ((current_time - trade.open_date_utc).days < (self.profit_too_old_days.value * 2))\
|
||||
& (previous_last_candle['sma20'] > last_candle['sma20']):
|
||||
return "too_old_0.01"
|
||||
if (current_profit >= - (2 * self.profit_too_old_max.value)) \
|
||||
& ((current_time - trade.open_date_utc).days >= (self.profit_too_old_days.value * 2))\
|
||||
& ((current_time - trade.open_date_utc).days < (self.profit_too_old_days.value * 3)) \
|
||||
& (previous_last_candle['sma20'] > last_candle['sma20']):
|
||||
return "too_old_0.02"
|
||||
if (current_profit >= - (3 * self.profit_too_old_max.value)) \
|
||||
& ((current_time - trade.open_date_utc).days >= (self.profit_too_old_days.value * 3)) \
|
||||
& (previous_last_candle['sma20'] > last_candle['sma20']):
|
||||
return "too_old_0.03"
|
||||
|
||||
if self.profit_quick_lost.value:
|
||||
if (current_profit >= self.profit_quick_lost_max_profit.value) \
|
||||
& (last_candle['percent3'] < - self.profit_quick_lost_max.value):
|
||||
return "quick_lost"
|
||||
|
||||
if self.profit_no_change.value:
|
||||
if (current_profit > 0.005) \
|
||||
& (last_candle['percent10'] < 0.000) \
|
||||
& (last_candle['percent5'] < 0) \
|
||||
& ((current_time - trade.open_date_utc).seconds >= 3600):
|
||||
return "no_change"
|
||||
|
||||
#if (current_profit > 0.01) & (last_candle['rsi'] < 30):
|
||||
# return "small_rsi"
|
||||
if self.profit_quick_gain_3.value:
|
||||
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.value:
|
||||
if (0.01 < current_profit < 0.03) \
|
||||
& (last_candle['percent'] < 0) \
|
||||
& ((current_time - trade.open_date_utc).seconds <= 3600):
|
||||
return "quick_gain"
|
||||
|
||||
if self.profit_sma10.value:
|
||||
if (current_profit > self.profit_sma10_current_profit.value) \
|
||||
& ((previous_5_candle['sma10'] > (last_candle['sma10'] * self.profit_sma10_facteur.value)) \
|
||||
| (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.value:
|
||||
if (current_profit > self.profit_sma20_current_profit.value) & (last_candle['percent5'] < 0) \
|
||||
& (previous_5_candle['sma10'] > last_candle['sma10']) \
|
||||
& ((current_time - trade.open_date_utc).seconds >= 3600) \
|
||||
& ((previous_last_candle['sma20'] > (last_candle['sma20'] * self.profit_sma20_facteur.value)) &
|
||||
((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.value:
|
||||
if (current_profit > 0) & (last_candle['rsi'] > self.profit_over_rsi_max_rsi.value): # & (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'] > self.profit_over_rsi_max_rsi2.value) \
|
||||
& (last_candle['percent'] < - self.profit_over_rsi2_percent.value): #| (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.value:
|
||||
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):
|
||||
return []
|
||||
|
||||
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["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_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36)
|
||||
|
||||
dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close']
|
||||
dataframe['min1.1'] = 1.01 * dataframe['min']
|
||||
|
||||
# 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["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)
|
||||
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_decalage_deb_0.value, self.buy_decalage0.value):
|
||||
# if self.buy_0.value:
|
||||
# conditions = list()
|
||||
# condition1, dataframe = condition_generator(
|
||||
# dataframe,
|
||||
# buy_operator0,
|
||||
# buy_indicator0,
|
||||
# buy_crossed_indicator0,
|
||||
# self.buy_real_num0.value,
|
||||
# self.buy_decalage0.value
|
||||
# )
|
||||
# conditions.append(condition1)
|
||||
# dataframe.loc[
|
||||
# (
|
||||
# reduce(lambda x, y: x & y, conditions)
|
||||
# & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (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['min10'] <= dataframe['min50'] * 1.02)
|
||||
# & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value)
|
||||
# # & (dataframe['min20'] == dataframe['min50'])
|
||||
# & (dataframe['distance_min'] <= self.buy_0_distance.value)
|
||||
# ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage))
|
||||
for decalage in range(self.buy_decalage_deb_1.value, self.buy_decalage1.value):
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['cond1'].shift(decalage) <= self.buy_real_num1.value)
|
||||
& (dataframe['bb_width'].shift(decalage) >= 0.07)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (dataframe['close'] < dataframe['sma10'])
|
||||
& (dataframe['sma50'].shift(decalage) < dataframe['sma50'])
|
||||
#& (dataframe['open'] < dataframe['min1.1'])
|
||||
# & (dataframe['open'] < dataframe['sma10'])
|
||||
& (dataframe['min50'].shift(decalage) == dataframe['min50'])
|
||||
#& (dataframe['min10'] <= dataframe['min50'] * 1.02)
|
||||
& (dataframe['percent20'].shift(decalage) <= self.buy_1_percent20.value)
|
||||
# & (dataframe['min20'] == dataframe['min50'])
|
||||
& (dataframe['distance_min'] <= self.buy_1_distance.value)
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage))
|
||||
for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value):
|
||||
# if self.buy_3.value:
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['cond1'].shift(decalage) <= self.buy_real_num3.value)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (dataframe['sma10'].shift(1) <= dataframe['sma10'])
|
||||
& (dataframe['close'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma100'])
|
||||
& (dataframe['open'] < dataframe['sma10'])
|
||||
#& (dataframe['open'] < dataframe['min1.1'])
|
||||
& (dataframe['min50'].shift(decalage) == dataframe['min50'])
|
||||
#& (dataframe['min10'] <= dataframe['min50'] * 1.02)
|
||||
& (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value)
|
||||
& (dataframe['distance_min'] <= self.buy_3_distance.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
|
||||
|
||||
63
GodStraJD3_7_6_2.json
Normal file
63
GodStraJD3_7_6_2.json
Normal file
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_7_6_2",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.026,
|
||||
"trailing_stop_positive_offset": 0.077,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_1_distance": -0.02,
|
||||
"buy_1_percent20": 0.03,
|
||||
"buy_3_distance": 0.05,
|
||||
"buy_3_percent20": 0.01,
|
||||
"buy_decalage1": 8,
|
||||
"buy_decalage3": 8,
|
||||
"buy_decalage_deb_1": 2,
|
||||
"buy_decalage_deb_3": 1,
|
||||
"buy_min_horizon": 195,
|
||||
"buy_real_num1": 0.55,
|
||||
"buy_real_num3": 0.55
|
||||
},
|
||||
"sell": {
|
||||
"profit_no_change": false,
|
||||
"profit_old_sma10": true,
|
||||
"profit_over_rsi": false,
|
||||
"profit_over_rsi2_percent": 0.002,
|
||||
"profit_over_rsi_max_rsi": 90,
|
||||
"profit_over_rsi_max_rsi2": 94,
|
||||
"profit_quick_gain": false,
|
||||
"profit_quick_gain_3": false,
|
||||
"profit_quick_lost": true,
|
||||
"profit_quick_lost_max": 0.0,
|
||||
"profit_quick_lost_max_profit": 0.013,
|
||||
"profit_short_loss": true,
|
||||
"profit_sma10": true,
|
||||
"profit_sma10_current_profit": 0.027,
|
||||
"profit_sma10_facteur": 1.0,
|
||||
"profit_sma20": true,
|
||||
"profit_sma20_current_profit": 0.021,
|
||||
"profit_sma20_facteur": 1.006,
|
||||
"profit_too_old": true,
|
||||
"profit_too_old_days": 9,
|
||||
"profit_too_old_max": 0.02,
|
||||
"profit_very_old_sma10": false
|
||||
},
|
||||
"protection": {
|
||||
"lookback": 133,
|
||||
"protection_max_allowed_dd": 0.71,
|
||||
"protection_stop": 61,
|
||||
"protection_stoploss_stop": 50,
|
||||
"trade_limit": 9
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-03-12 00:18:04.975397+00:00"
|
||||
}
|
||||
788
GodStraJD3_7_6_2.py
Normal file
788
GodStraJD3_7_6_2.py
Normal file
@@ -0,0 +1,788 @@
|
||||
# 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
|
||||
|
||||
# --------------------------------
|
||||
|
||||
# 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_6_2(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": {
|
||||
'ecart_20': {'color': 'red'},
|
||||
'ecart_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 = False
|
||||
# profit_sma20 = True
|
||||
# profit_very_old_sma10 = False
|
||||
|
||||
trades = list()
|
||||
profit_too_old = BooleanParameter(default=True, space="sell")
|
||||
profit_no_change = BooleanParameter(default=True, space="sell")
|
||||
profit_quick_lost = BooleanParameter(default=True, space="sell")
|
||||
profit_sma10 = BooleanParameter(default=True, space="sell")
|
||||
profit_sma20 = BooleanParameter(default=True, space="sell")
|
||||
profit_quick_gain = BooleanParameter(default=True, space="sell")
|
||||
profit_quick_gain_3 = BooleanParameter(default=True, space="sell")
|
||||
profit_old_sma10 = BooleanParameter(default=True, space="sell")
|
||||
profit_very_old_sma10 = BooleanParameter(default=True, space="sell")
|
||||
profit_over_rsi = BooleanParameter(default=True, space="sell")
|
||||
profit_short_loss = BooleanParameter(default=True, space="sell")
|
||||
|
||||
profit_too_old_max = DecimalParameter(0, 0.05, decimals=2, default=0.01, space='sell')
|
||||
profit_too_old_days = IntParameter(1, 10, default=5, space='sell')
|
||||
profit_quick_lost_max = DecimalParameter(0, 0.03, decimals=3, default=0.015, space='sell')
|
||||
profit_quick_lost_max_profit = DecimalParameter(0, 0.03, decimals=3, default=0.015, space='sell')
|
||||
profit_sma10_current_profit = DecimalParameter(0, 0.03, decimals=3, default=0.015, space='sell')
|
||||
profit_sma10_facteur = DecimalParameter(1, 1.01, decimals=3, default=1.005, space='sell')
|
||||
|
||||
profit_sma20_current_profit = DecimalParameter(0, 0.03, decimals=3, default=0.015, space='sell')
|
||||
profit_sma20_facteur = DecimalParameter(1, 1.01, decimals=3, default=1.005, space='sell')
|
||||
|
||||
profit_over_rsi_max_rsi = IntParameter(70, 100, default=88, space='sell')
|
||||
profit_over_rsi_max_rsi2 = IntParameter(70, 100, default=82, space='sell')
|
||||
|
||||
profit_over_rsi2_percent = DecimalParameter(0, 0.05, decimals=3, default=0.02, space='sell')
|
||||
|
||||
# buy_signal_bb_width = DecimalParameter(0.06, 0.15, decimals=2, default=0.065, space='buy')
|
||||
|
||||
# buy_real_num0 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy')
|
||||
buy_real_num1 = DecimalParameter(0, 1, decimals=2, default=0.67, space='buy')
|
||||
buy_real_num3 = 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_1_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_0_distance = 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_3_distance = DecimalParameter(-0.1, 0.1, decimals=2, default=0.02, space='buy')
|
||||
|
||||
# buy_decalage_deb_0 = IntParameter(1, 3, default=5, space='buy')
|
||||
buy_decalage_deb_1 = IntParameter(1, 3, default=5, space='buy')
|
||||
buy_decalage_deb_3 = IntParameter(1, 3, default=5, space='buy')
|
||||
|
||||
# buy_decalage0 = IntParameter(buy_decalage_deb_0.value + 1, 8, default=5, space='buy')
|
||||
buy_decalage1 = IntParameter(buy_decalage_deb_1.value + 1, 8, default=5, space='buy')
|
||||
buy_decalage3 = IntParameter(buy_decalage_deb_3.value + 1, 8, default=5, 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')
|
||||
|
||||
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 self.profit_too_old.value:
|
||||
if (current_profit >= - self.profit_too_old_max.value) \
|
||||
& ((current_time - trade.open_date_utc).days >= self.profit_too_old_days.value)\
|
||||
& ((current_time - trade.open_date_utc).days < (self.profit_too_old_days.value * 2))\
|
||||
& (previous_last_candle['sma20'] > last_candle['sma20']):
|
||||
return "too_old_0.01"
|
||||
if (current_profit >= - (2 * self.profit_too_old_max.value)) \
|
||||
& ((current_time - trade.open_date_utc).days >= (self.profit_too_old_days.value * 2))\
|
||||
& ((current_time - trade.open_date_utc).days < (self.profit_too_old_days.value * 3)) \
|
||||
& (previous_last_candle['sma20'] > last_candle['sma20']):
|
||||
return "too_old_0.02"
|
||||
if (current_profit >= - (3 * self.profit_too_old_max.value)) \
|
||||
& ((current_time - trade.open_date_utc).days >= (self.profit_too_old_days.value * 3)) \
|
||||
& (previous_last_candle['sma20'] > last_candle['sma20']):
|
||||
return "too_old_0.03"
|
||||
|
||||
if self.profit_quick_lost.value:
|
||||
if (current_profit >= self.profit_quick_lost_max_profit.value) \
|
||||
& (last_candle['percent3'] < - self.profit_quick_lost_max.value):
|
||||
return "quick_lost"
|
||||
|
||||
if self.profit_no_change.value:
|
||||
if (current_profit > 0.005) \
|
||||
& (last_candle['percent10'] < 0.000) \
|
||||
& (last_candle['percent5'] < 0) \
|
||||
& ((current_time - trade.open_date_utc).seconds >= 3600):
|
||||
return "no_change"
|
||||
|
||||
#if (current_profit > 0.01) & (last_candle['rsi'] < 30):
|
||||
# return "small_rsi"
|
||||
if self.profit_quick_gain_3.value:
|
||||
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.value:
|
||||
if (0.01 < current_profit < 0.03) \
|
||||
& (last_candle['percent'] < 0) \
|
||||
& ((current_time - trade.open_date_utc).seconds <= 3600):
|
||||
return "quick_gain"
|
||||
|
||||
if self.profit_sma10.value:
|
||||
if (current_profit > self.profit_sma10_current_profit.value) \
|
||||
& ((previous_5_candle['sma10'] > (last_candle['sma10'] * self.profit_sma10_facteur.value)) \
|
||||
| (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.value:
|
||||
if (current_profit > self.profit_sma20_current_profit.value) & (last_candle['percent5'] < 0) \
|
||||
& (previous_5_candle['sma10'] > last_candle['sma10']) \
|
||||
& ((current_time - trade.open_date_utc).seconds >= 3600) \
|
||||
& ((previous_last_candle['sma20'] > (last_candle['sma20'] * self.profit_sma20_facteur.value)) &
|
||||
((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.value:
|
||||
if (current_profit > 0) & (last_candle['rsi'] > self.profit_over_rsi_max_rsi.value): # & (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'] > self.profit_over_rsi_max_rsi2.value) \
|
||||
& (last_candle['percent'] < - self.profit_over_rsi2_percent.value): #| (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.value:
|
||||
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):
|
||||
return []
|
||||
|
||||
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["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_min'] = ta.MIN(dataframe['bb_lowerband'], timeperiod=36)
|
||||
|
||||
dataframe['distance_min'] = (dataframe['close'] - dataframe['min']) / dataframe['close']
|
||||
dataframe['min1.1'] = 1.01 * dataframe['min']
|
||||
|
||||
# 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["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)
|
||||
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_decalage_deb_0.value, self.buy_decalage0.value):
|
||||
# if self.buy_0.value:
|
||||
# conditions = list()
|
||||
# condition1, dataframe = condition_generator(
|
||||
# dataframe,
|
||||
# buy_operator0,
|
||||
# buy_indicator0,
|
||||
# buy_crossed_indicator0,
|
||||
# self.buy_real_num0.value,
|
||||
# self.buy_decalage0.value
|
||||
# )
|
||||
# conditions.append(condition1)
|
||||
# dataframe.loc[
|
||||
# (
|
||||
# reduce(lambda x, y: x & y, conditions)
|
||||
# & (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
# & (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['min10'] <= dataframe['min50'] * 1.02)
|
||||
# & (dataframe['percent20'].shift(decalage) <= self.buy_0_percent20.value)
|
||||
# # & (dataframe['min20'] == dataframe['min50'])
|
||||
# & (dataframe['distance_min'] <= self.buy_0_distance.value)
|
||||
# ), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage))
|
||||
for decalage in range(self.buy_decalage_deb_1.value, self.buy_decalage1.value):
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['cond1'].shift(decalage) <= self.buy_real_num1.value)
|
||||
& (dataframe['bb_width'].shift(decalage) >= 0.07)
|
||||
# & (dataframe['close'].shift(decalage) < dataframe['bb_lowerband'].shift(decalage))
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
& (dataframe['close'] < dataframe['sma10'])
|
||||
& (dataframe['sma50'].shift(decalage) < dataframe['sma50'])
|
||||
#& (dataframe['open'] < dataframe['min1.1'])
|
||||
# & (dataframe['open'] < dataframe['sma10'])
|
||||
& (dataframe['min50'].shift(decalage) == dataframe['min50'])
|
||||
#& (dataframe['min10'] <= dataframe['min50'] * 1.02)
|
||||
& (dataframe['percent20'].shift(decalage) <= self.buy_1_percent20.value)
|
||||
# & (dataframe['min20'] == dataframe['min50'])
|
||||
& (dataframe['distance_min'] <= self.buy_1_distance.value)
|
||||
), ['buy', 'buy_tag']] = (1, 'buy_1_' + str(decalage))
|
||||
for decalage in range(self.buy_decalage_deb_3.value, self.buy_decalage3.value):
|
||||
# if self.buy_3.value:
|
||||
dataframe.loc[
|
||||
(
|
||||
(dataframe['cond1'].shift(decalage) <= self.buy_real_num3.value)
|
||||
& (dataframe['volume10'].shift(decalage) * dataframe['close'].shift(decalage) / 1000 >= 10)
|
||||
& (dataframe['sma10'].shift(1) <= dataframe['sma10'])
|
||||
& (dataframe['close'] < dataframe['sma10'])
|
||||
& (dataframe['open'] < dataframe['sma100'])
|
||||
& (dataframe['open'] < dataframe['sma10'])
|
||||
#& (dataframe['open'] < dataframe['min1.1'])
|
||||
& (dataframe['min50'].shift(decalage) == dataframe['min50'])
|
||||
#& (dataframe['min10'] <= dataframe['min50'] * 1.02)
|
||||
& (dataframe['percent20'].shift(decalage) <= self.buy_3_percent20.value)
|
||||
& (dataframe['distance_min'] <= self.buy_3_distance.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
|
||||
|
||||
54
GodStraJD3_8.json
Normal file
54
GodStraJD3_8.json
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_8",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.058,
|
||||
"trailing_stop_positive_offset": 0.079,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_bbwidth_num0": 0.05,
|
||||
"buy_bbwidth_num1": 0.99,
|
||||
"buy_cond1_num0": 1.29,
|
||||
"buy_cond1_num1": 1.67,
|
||||
"profit_no_change": true,
|
||||
"profit_old_sma10": true,
|
||||
"profit_over_rsi": true,
|
||||
"profit_quick_gain": false,
|
||||
"profit_quick_gain_3": false,
|
||||
"profit_quick_lost": true,
|
||||
"profit_short_loss": true,
|
||||
"profit_sma10": true,
|
||||
"profit_sma20": true,
|
||||
"profit_very_old_sma10": false
|
||||
},
|
||||
"sell": {
|
||||
"sell_crossed_indicator0": "CDLCONCEALBABYSWALL-100",
|
||||
"sell_indicator0": "BBANDS-2-5",
|
||||
"sell_operator0": "D",
|
||||
"sell_percent": 0.01,
|
||||
"sell_percent3": 0.002,
|
||||
"sell_percent5": 0.025,
|
||||
"sell_real_num0": 0.01
|
||||
},
|
||||
"protection": {
|
||||
"lookback": 46,
|
||||
"lookback_stoploss": 144,
|
||||
"protection_cooldown": 19,
|
||||
"protection_max_allowed_dd": 0.36,
|
||||
"protection_stop": 79,
|
||||
"protection_stoploss_stop": 13,
|
||||
"trade_limit": 7,
|
||||
"trade_limit_stoploss": 5
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-02-14 03:19:36.837525+00:00"
|
||||
}
|
||||
1043
GodStraJD3_8.py
Normal file
1043
GodStraJD3_8.py
Normal file
File diff suppressed because it is too large
Load Diff
48
GodStraJD3_9.json
Normal file
48
GodStraJD3_9.json
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_9",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.058,
|
||||
"trailing_stop_positive_offset": 0.079,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_signal_bb_width": 1.21,
|
||||
"buy_signal_condition_high": 1.02,
|
||||
"buy_signal_minus": 1.22,
|
||||
"buy_signal_sma10": 1.08,
|
||||
"buy_signal_sma10_pente": 0.041,
|
||||
"buy_signal_sma_max": 1.09,
|
||||
"buy_signal_sma_min": 1.0,
|
||||
"buy_signal_sma_percent50": 0.061
|
||||
},
|
||||
"sell": {
|
||||
"sell_crossed_indicator0": "CDL3INSIDE-50",
|
||||
"sell_indicator0": "CDLGAPSIDESIDEWHITE-50",
|
||||
"sell_operator0": "CUT",
|
||||
"sell_percent": 0.006,
|
||||
"sell_percent3": 0.0,
|
||||
"sell_percent5": 0.004,
|
||||
"sell_real_num0": 0.13
|
||||
},
|
||||
"protection": {
|
||||
"lookback": 46,
|
||||
"lookback_stoploss": 144,
|
||||
"protection_cooldown": 19,
|
||||
"protection_max_allowed_dd": 0.36,
|
||||
"protection_stop": 79,
|
||||
"protection_stoploss_stop": 13,
|
||||
"trade_limit": 7,
|
||||
"trade_limit_stoploss": 5
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-02-17 19:22:05.539646+00:00"
|
||||
}
|
||||
48
GodStraJD3_9.jsonBest
Normal file
48
GodStraJD3_9.jsonBest
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_9",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.058,
|
||||
"trailing_stop_positive_offset": 0.079,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_signal_bb_width": 1.09,
|
||||
"buy_signal_condition_high": 1.1,
|
||||
"buy_signal_minus": 1.09,
|
||||
"buy_signal_sma10": 1.02,
|
||||
"buy_signal_sma10_pente": 0.001,
|
||||
"buy_signal_sma_max": 1.03,
|
||||
"buy_signal_sma_min": 1.08,
|
||||
"buy_signal_sma_percent50": 0.036
|
||||
},
|
||||
"sell": {
|
||||
"sell_crossed_indicator0": "CDLSHORTLINE-50",
|
||||
"sell_indicator0": "CDLSEPARATINGLINES-20",
|
||||
"sell_operator0": "=R",
|
||||
"sell_percent": 0.01,
|
||||
"sell_percent3": 0.021,
|
||||
"sell_percent5": 0.006,
|
||||
"sell_real_num0": 0.84
|
||||
},
|
||||
"protection": {
|
||||
"lookback": 46,
|
||||
"lookback_stoploss": 144,
|
||||
"protection_cooldown": 19,
|
||||
"protection_max_allowed_dd": 0.36,
|
||||
"protection_stop": 79,
|
||||
"protection_stoploss_stop": 13,
|
||||
"trade_limit": 7,
|
||||
"trade_limit_stoploss": 5
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-02-17 00:06:37.000718+00:00"
|
||||
}
|
||||
47
GodStraJD3_9.jsonOld
Normal file
47
GodStraJD3_9.jsonOld
Normal file
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_9",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.058,
|
||||
"trailing_stop_positive_offset": 0.079,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_signal_bb_width": 1.1,
|
||||
"buy_signal_condition_high": 1.07,
|
||||
"buy_signal_minus": 1.07,
|
||||
"buy_signal_sma": 1.08,
|
||||
"buy_signal_sma10": 1.08,
|
||||
"buy_signal_sma10_pente": 0.041,
|
||||
"buy_signal_sma_percent50": 0.092
|
||||
},
|
||||
"sell": {
|
||||
"sell_crossed_indicator0": "CDLSHORTLINE-50",
|
||||
"sell_indicator0": "CDLSEPARATINGLINES-20",
|
||||
"sell_operator0": "=R",
|
||||
"sell_percent": 0.01,
|
||||
"sell_percent3": 0.021,
|
||||
"sell_percent5": 0.006,
|
||||
"sell_real_num0": 0.84
|
||||
},
|
||||
"protection": {
|
||||
"lookback": 46,
|
||||
"lookback_stoploss": 144,
|
||||
"protection_cooldown": 19,
|
||||
"protection_max_allowed_dd": 0.36,
|
||||
"protection_stop": 79,
|
||||
"protection_stoploss_stop": 13,
|
||||
"trade_limit": 7,
|
||||
"trade_limit_stoploss": 5
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-02-16 18:51:17.244506+00:00"
|
||||
}
|
||||
48
GodStraJD3_9.jsonOld2
Normal file
48
GodStraJD3_9.jsonOld2
Normal file
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"strategy_name": "GodStraJD3_9",
|
||||
"params": {
|
||||
"roi": {
|
||||
"0": 10
|
||||
},
|
||||
"stoploss": {
|
||||
"stoploss": -1.0
|
||||
},
|
||||
"trailing": {
|
||||
"trailing_stop": false,
|
||||
"trailing_stop_positive": 0.058,
|
||||
"trailing_stop_positive_offset": 0.079,
|
||||
"trailing_only_offset_is_reached": true
|
||||
},
|
||||
"buy": {
|
||||
"buy_signal_bb_width": 1.81,
|
||||
"buy_signal_condition_high": 1.28,
|
||||
"buy_signal_minus": 1.95,
|
||||
"buy_signal_sma10": 1.02,
|
||||
"buy_signal_sma10_pente": 0.055,
|
||||
"buy_signal_sma_max": 1.02,
|
||||
"buy_signal_sma_min": 1.03,
|
||||
"buy_signal_sma_percent50": 0.089
|
||||
},
|
||||
"sell": {
|
||||
"sell_crossed_indicator0": "CDLSHORTLINE-50",
|
||||
"sell_indicator0": "CDLSEPARATINGLINES-20",
|
||||
"sell_operator0": "=R",
|
||||
"sell_percent": 0.01,
|
||||
"sell_percent3": 0.021,
|
||||
"sell_percent5": 0.006,
|
||||
"sell_real_num0": 0.84
|
||||
},
|
||||
"protection": {
|
||||
"lookback": 46,
|
||||
"lookback_stoploss": 144,
|
||||
"protection_cooldown": 19,
|
||||
"protection_max_allowed_dd": 0.36,
|
||||
"protection_stop": 79,
|
||||
"protection_stoploss_stop": 13,
|
||||
"trade_limit": 7,
|
||||
"trade_limit_stoploss": 5
|
||||
}
|
||||
},
|
||||
"ft_stratparam_v": 1,
|
||||
"export_time": "2022-02-17 15:42:20.763706+00:00"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user