From a18d52babedd1e2a923368ca6b2c9b5c4d275b5b Mon Sep 17 00:00:00 2001 From: Masoud Azizi Date: Tue, 18 May 2021 21:51:44 +0430 Subject: [PATCH] GodStraNew hyperoptable Strategy --- user_data/strategies/GodStraNew.py | 619 +++++++++++++++++++++++++++++ 1 file changed, 619 insertions(+) create mode 100644 user_data/strategies/GodStraNew.py diff --git a/user_data/strategies/GodStraNew.py b/user_data/strategies/GodStraNew.py new file mode 100644 index 0000000..96876c7 --- /dev/null +++ b/user_data/strategies/GodStraNew.py @@ -0,0 +1,619 @@ +# 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.hyper 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 + 'ROCP', # Rate of change Percentage: (price-prevPrice)/prevPrice + 'ROCR', # Rate of change ratio: (price/prevPrice) + 'ROCR100', # Rate of change ratio 100 scale: (price/prevPrice)*100 + '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 + 'TRIX', # 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA + '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 + 'CDLTAKURI', # Takuri (Dragonfly Doji with very long lower shadow) + '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 devided to cross indicator, bigger than real number + "/=R", # Normalized indicator devided to cross indicator, equal with real number + "/ 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].div(dataframe[crossed_indicator]) > real_num + ) + elif operator == "/=R": + condition = ( + np.isclose(dataframe[indicator].div(dataframe[crossed_indicator]), real_num) + ) + elif operator == "/ 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 GodStraNew(IStrategy): + # #################### RESULTS PASTE PLACE #################### + + # #################### 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="/ 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 + ''' + 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), + '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