Add some strategies for binance futures
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||
# flake8: noqa: F401
|
||||
# isort: skip_file
|
||||
# --- Do not remove these libs ---
|
||||
from functools import reduce
|
||||
import numpy as np # noqa
|
||||
import pandas as pd # noqa
|
||||
from pandas import DataFrame
|
||||
|
||||
from freqtrade.strategy import (
|
||||
BooleanParameter,
|
||||
CategoricalParameter,
|
||||
DecimalParameter,
|
||||
IStrategy,
|
||||
IntParameter,
|
||||
)
|
||||
|
||||
# --------------------------------
|
||||
# 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 FAdxSmaStrategy(IStrategy):
|
||||
|
||||
INTERFACE_VERSION = 3
|
||||
timeframe = "1h"
|
||||
# Minimal ROI designed for the strategy.
|
||||
# This attribute will be overridden if the config file contains "minimal_roi".
|
||||
minimal_roi = {"60": 0.075, "30": 0.1, "0": 0.05}
|
||||
# minimal_roi = {"0": 1}
|
||||
|
||||
stoploss = -0.05
|
||||
can_short = True
|
||||
|
||||
# Trailing stoploss
|
||||
trailing_stop = False
|
||||
# trailing_only_offset_is_reached = False
|
||||
# trailing_stop_positive = 0.01
|
||||
# trailing_stop_positive_offset = 0.0 # Disabled / not configured
|
||||
|
||||
# Run "populate_indicators()" only for new candle.
|
||||
process_only_new_candles = False
|
||||
|
||||
# Number of candles the strategy requires before producing valid signals
|
||||
startup_candle_count: int = 14
|
||||
|
||||
# Hyperoptable parameters
|
||||
|
||||
# Define the guards spaces
|
||||
pos_entry_adx = DecimalParameter(15, 40, decimals=1, default=30.0, space="buy")
|
||||
pos_exit_adx = DecimalParameter(15, 40, decimals=1, default=30.0, space="sell")
|
||||
|
||||
# Define the parameter spaces
|
||||
adx_period = IntParameter(4, 24, default=14)
|
||||
sma_short_period = IntParameter(4, 24, default=12)
|
||||
sma_long_period = IntParameter(12, 175, default=48)
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
# Calculate all adx values
|
||||
for val in self.adx_period.range:
|
||||
dataframe[f"adx_{val}"] = ta.ADX(dataframe, timeperiod=val)
|
||||
|
||||
# Calculate all sma_short values
|
||||
for val in self.sma_short_period.range:
|
||||
dataframe[f"sma_short_{val}"] = ta.SMA(dataframe, timeperiod=val)
|
||||
|
||||
# Calculate all sma_long values
|
||||
for val in self.sma_long_period.range:
|
||||
dataframe[f"sma_long_{val}"] = ta.SMA(dataframe, timeperiod=val)
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
conditions_long = []
|
||||
conditions_short = []
|
||||
|
||||
# GUARDS AND TRIGGERS
|
||||
conditions_long.append(
|
||||
dataframe[f"adx_{self.adx_period.value}"] > self.pos_entry_adx.value
|
||||
)
|
||||
conditions_short.append(
|
||||
dataframe[f"adx_{self.adx_period.value}"] > self.pos_entry_adx.value
|
||||
)
|
||||
|
||||
conditions_long.append(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[f"sma_short_{self.sma_short_period.value}"],
|
||||
dataframe[f"sma_long_{self.sma_long_period.value}"],
|
||||
)
|
||||
)
|
||||
conditions_short.append(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[f"sma_short_{self.sma_short_period.value}"],
|
||||
dataframe[f"sma_long_{self.sma_long_period.value}"],
|
||||
)
|
||||
)
|
||||
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions_long),
|
||||
"enter_long",
|
||||
] = 1
|
||||
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions_short),
|
||||
"enter_short",
|
||||
] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions_close = []
|
||||
conditions_close.append(
|
||||
dataframe[f"adx_{self.adx_period.value}"] < self.pos_entry_adx.value
|
||||
)
|
||||
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions_close),
|
||||
"exit_long",
|
||||
] = 1
|
||||
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions_close),
|
||||
"exit_short",
|
||||
] = 1
|
||||
|
||||
return dataframe
|
||||
@@ -0,0 +1,187 @@
|
||||
import logging
|
||||
from numpy.lib import math
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
from freqtrade.strategy.hyper import IntParameter
|
||||
from pandas import DataFrame
|
||||
import talib.abstract as ta
|
||||
import numpy as np
|
||||
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||
|
||||
|
||||
|
||||
class FOttStrategy(IStrategy):
|
||||
# Buy params, Sell params, ROI, Stoploss and Trailing Stop are values generated by 'freqtrade hyperopt --strategy Supertrend --hyperopt-loss ShortTradeDurHyperOptLoss --timerange=20210101- --timeframe=1h --spaces all'
|
||||
# It's encourage you find the values that better suites your needs and risk management strategies
|
||||
|
||||
# ROI table:
|
||||
minimal_roi = {"0": 0.1, "30": 0.75, "60": 0.05, "120": 0.025}
|
||||
# minimal_roi = {"0": 1}
|
||||
|
||||
# Stoploss:
|
||||
stoploss = -0.265
|
||||
|
||||
# Trailing stop:
|
||||
trailing_stop = True
|
||||
trailing_stop_positive = 0.05
|
||||
trailing_stop_positive_offset = 0.1
|
||||
trailing_only_offset_is_reached = False
|
||||
|
||||
timeframe = "1h"
|
||||
|
||||
startup_candle_count = 18
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
dataframe["ott"] = self.ott(dataframe)["OTT"]
|
||||
dataframe["var"] = self.ott(dataframe)["VAR"]
|
||||
dataframe["adx"] = ta.ADX(dataframe, timeperiod=14)
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
dataframe.loc[
|
||||
(qtpylib.crossed_above(dataframe["var"], dataframe["ott"])),
|
||||
"enter_long",
|
||||
] = 1
|
||||
|
||||
dataframe.loc[
|
||||
(qtpylib.crossed_below(dataframe["var"], dataframe["ott"])),
|
||||
"enter_short",
|
||||
] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
dataframe.loc[
|
||||
(
|
||||
dataframe["adx"]>60
|
||||
),
|
||||
"exit_long",
|
||||
] = 1
|
||||
|
||||
dataframe.loc[
|
||||
(
|
||||
dataframe["adx"]>60
|
||||
),
|
||||
"exit_short",
|
||||
] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
"""
|
||||
Supertrend Indicator; adapted for freqtrade
|
||||
from: https://github.com/freqtrade/freqtrade-strategies/issues/30
|
||||
"""
|
||||
|
||||
def ott(self, dataframe: DataFrame):
|
||||
df = dataframe.copy()
|
||||
|
||||
pds = 2
|
||||
percent = 1.4
|
||||
alpha = 2 / (pds + 1)
|
||||
|
||||
df["ud1"] = np.where(
|
||||
df["close"] > df["close"].shift(1), (df["close"] - df["close"].shift()), 0
|
||||
)
|
||||
df["dd1"] = np.where(
|
||||
df["close"] < df["close"].shift(1), (df["close"].shift() - df["close"]), 0
|
||||
)
|
||||
df["UD"] = df["ud1"].rolling(9).sum()
|
||||
df["DD"] = df["dd1"].rolling(9).sum()
|
||||
df["CMO"] = ((df["UD"] - df["DD"]) / (df["UD"] + df["DD"])).fillna(0).abs()
|
||||
|
||||
# df['Var'] = talib.EMA(df['close'], timeperiod=5)
|
||||
df["Var"] = 0.0
|
||||
for i in range(pds, len(df)):
|
||||
df["Var"].iat[i] = (alpha * df["CMO"].iat[i] * df["close"].iat[i]) + (
|
||||
1 - alpha * df["CMO"].iat[i]
|
||||
) * df["Var"].iat[i - 1]
|
||||
|
||||
df["fark"] = df["Var"] * percent * 0.01
|
||||
df["newlongstop"] = df["Var"] - df["fark"]
|
||||
df["newshortstop"] = df["Var"] + df["fark"]
|
||||
df["longstop"] = 0.0
|
||||
df["shortstop"] = 999999999999999999
|
||||
# df['dir'] = 1
|
||||
for i in df["UD"]:
|
||||
|
||||
def maxlongstop():
|
||||
df.loc[(df["newlongstop"] > df["longstop"].shift(1)), "longstop"] = df[
|
||||
"newlongstop"
|
||||
]
|
||||
df.loc[(df["longstop"].shift(1) > df["newlongstop"]), "longstop"] = df[
|
||||
"longstop"
|
||||
].shift(1)
|
||||
|
||||
return df["longstop"]
|
||||
|
||||
def minshortstop():
|
||||
df.loc[
|
||||
(df["newshortstop"] < df["shortstop"].shift(1)), "shortstop"
|
||||
] = df["newshortstop"]
|
||||
df.loc[
|
||||
(df["shortstop"].shift(1) < df["newshortstop"]), "shortstop"
|
||||
] = df["shortstop"].shift(1)
|
||||
|
||||
return df["shortstop"]
|
||||
|
||||
df["longstop"] = np.where(
|
||||
((df["Var"] > df["longstop"].shift(1))),
|
||||
maxlongstop(),
|
||||
df["newlongstop"],
|
||||
)
|
||||
|
||||
df["shortstop"] = np.where(
|
||||
((df["Var"] < df["shortstop"].shift(1))),
|
||||
minshortstop(),
|
||||
df["newshortstop"],
|
||||
)
|
||||
|
||||
# get xover
|
||||
|
||||
df["xlongstop"] = np.where(
|
||||
(
|
||||
(df["Var"].shift(1) > df["longstop"].shift(1))
|
||||
& (df["Var"] < df["longstop"].shift(1))
|
||||
),
|
||||
1,
|
||||
0,
|
||||
)
|
||||
|
||||
df["xshortstop"] = np.where(
|
||||
(
|
||||
(df["Var"].shift(1) < df["shortstop"].shift(1))
|
||||
& (df["Var"] > df["shortstop"].shift(1))
|
||||
),
|
||||
1,
|
||||
0,
|
||||
)
|
||||
|
||||
df["trend"] = 0
|
||||
df["dir"] = 0
|
||||
for i in df["UD"]:
|
||||
df["trend"] = np.where(
|
||||
((df["xshortstop"] == 1)),
|
||||
1,
|
||||
(np.where((df["xlongstop"] == 1), -1, df["trend"].shift(1))),
|
||||
)
|
||||
|
||||
df["dir"] = np.where(
|
||||
((df["xshortstop"] == 1)),
|
||||
1,
|
||||
(np.where((df["xlongstop"] == 1), -1, df["dir"].shift(1).fillna(1))),
|
||||
)
|
||||
|
||||
# get OTT
|
||||
|
||||
df["MT"] = np.where(df["dir"] == 1, df["longstop"], df["shortstop"])
|
||||
df["OTT"] = np.where(
|
||||
df["Var"] > df["MT"],
|
||||
(df["MT"] * (200 + percent) / 200),
|
||||
(df["MT"] * (200 - percent) / 200),
|
||||
)
|
||||
df["OTT"] = df["OTT"].shift(2)
|
||||
|
||||
return DataFrame(index=df.index, data={"OTT": df["OTT"], "VAR": df["Var"]})
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||
# flake8: noqa: F401
|
||||
# isort: skip_file
|
||||
# --- Do not remove these libs ---
|
||||
from functools import reduce
|
||||
import numpy as np # noqa
|
||||
import pandas as pd # noqa
|
||||
from pandas import DataFrame
|
||||
|
||||
from freqtrade.strategy import (
|
||||
BooleanParameter,
|
||||
CategoricalParameter,
|
||||
DecimalParameter,
|
||||
IStrategy,
|
||||
IntParameter,
|
||||
)
|
||||
|
||||
# --------------------------------
|
||||
# Add your lib to import here
|
||||
import talib.abstract as ta
|
||||
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||
from freqtrade.exchange import timeframe_to_minutes
|
||||
from technical.util import resample_to_interval, resampled_merge
|
||||
|
||||
|
||||
# This class is a sample. Feel free to customize it.
|
||||
class FReinforcedStrategy(IStrategy):
|
||||
|
||||
INTERFACE_VERSION = 3
|
||||
timeframe = "5m"
|
||||
# Minimal ROI designed for the strategy.
|
||||
# This attribute will be overridden if the config file contains "minimal_roi".
|
||||
minimal_roi = {"60": 0.075, "30": 0.1, "0": 0.05}
|
||||
# minimal_roi = {"0": 1}
|
||||
|
||||
stoploss = -0.05
|
||||
can_short = True
|
||||
|
||||
# Trailing stoploss
|
||||
trailing_stop = False
|
||||
# trailing_only_offset_is_reached = False
|
||||
# trailing_stop_positive = 0.01
|
||||
# trailing_stop_positive_offset = 0.0 # Disabled / not configured
|
||||
|
||||
# Run "populate_indicators()" only for new candle.
|
||||
process_only_new_candles = False
|
||||
|
||||
# Number of candles the strategy requires before producing valid signals
|
||||
startup_candle_count: int = 14
|
||||
|
||||
# Hyperoptable parameters
|
||||
|
||||
# Define the guards spaces
|
||||
pos_entry_adx = DecimalParameter(15, 40, decimals=1, default=30.0, space="buy")
|
||||
pos_exit_adx = DecimalParameter(15, 40, decimals=1, default=30.0, space="sell")
|
||||
|
||||
# Define the parameter spaces
|
||||
adx_period = IntParameter(4, 24, default=14)
|
||||
ema_short_period = IntParameter(4, 24, default=8)
|
||||
ema_long_period = IntParameter(12, 175, default=21)
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
# Calculate all adx values
|
||||
for val in self.adx_period.range:
|
||||
dataframe[f"adx_{val}"] = ta.ADX(dataframe, timeperiod=val)
|
||||
|
||||
# Calculate all ema_short values
|
||||
for val in self.ema_short_period.range:
|
||||
dataframe[f"ema_short_{val}"] = ta.EMA(dataframe, timeperiod=val)
|
||||
|
||||
# Calculate all ema_long values
|
||||
for val in self.ema_long_period.range:
|
||||
dataframe[f"ema_long_{val}"] = ta.EMA(dataframe, timeperiod=val)
|
||||
|
||||
# required for graphing
|
||||
bollinger = qtpylib.bollinger_bands(dataframe["close"], window=20, stds=2)
|
||||
dataframe["bb_lowerband"] = bollinger["lower"]
|
||||
dataframe["bb_upperband"] = bollinger["upper"]
|
||||
dataframe["bb_middleband"] = bollinger["mid"]
|
||||
|
||||
self.resample_interval = timeframe_to_minutes(self.timeframe) * 12
|
||||
dataframe_long = resample_to_interval(dataframe, self.resample_interval)
|
||||
dataframe_long["sma"] = ta.SMA(dataframe_long, timeperiod=50, price="close")
|
||||
dataframe = resampled_merge(dataframe, dataframe_long, fill_na=True)
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
conditions_long = []
|
||||
conditions_short = []
|
||||
|
||||
# GUARDS AND TRIGGERS
|
||||
conditions_long.append(
|
||||
dataframe["close"] > dataframe[f"resample_{self.resample_interval}_sma"]
|
||||
)
|
||||
|
||||
conditions_short.append(
|
||||
dataframe["close"] < dataframe[f"resample_{self.resample_interval}_sma"]
|
||||
)
|
||||
|
||||
conditions_long.append(
|
||||
qtpylib.crossed_above(
|
||||
dataframe[f"ema_short_{self.ema_short_period.value}"],
|
||||
dataframe[f"ema_long_{self.ema_long_period.value}"],
|
||||
)
|
||||
)
|
||||
conditions_short.append(
|
||||
qtpylib.crossed_below(
|
||||
dataframe[f"ema_short_{self.ema_short_period.value}"],
|
||||
dataframe[f"ema_long_{self.ema_long_period.value}"],
|
||||
)
|
||||
)
|
||||
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions_long),
|
||||
"enter_long",
|
||||
] = 1
|
||||
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions_short),
|
||||
"enter_short",
|
||||
] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
conditions_close = []
|
||||
conditions_close.append(
|
||||
dataframe[f"adx_{self.adx_period.value}"] < self.pos_entry_adx.value
|
||||
)
|
||||
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions_close),
|
||||
"exit_long",
|
||||
] = 1
|
||||
|
||||
dataframe.loc[
|
||||
reduce(lambda x, y: x & y, conditions_close),
|
||||
"exit_short",
|
||||
] = 1
|
||||
|
||||
return dataframe
|
||||
@@ -0,0 +1,162 @@
|
||||
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||
# flake8: noqa: F401
|
||||
# isort: skip_file
|
||||
# --- Do not remove these libs ---
|
||||
import numpy as np # noqa
|
||||
import pandas as pd # noqa
|
||||
from pandas import DataFrame
|
||||
|
||||
from freqtrade.strategy import (
|
||||
BooleanParameter,
|
||||
CategoricalParameter,
|
||||
DecimalParameter,
|
||||
IStrategy,
|
||||
IntParameter,
|
||||
)
|
||||
|
||||
# --------------------------------
|
||||
# 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 FSampleStrategy(IStrategy):
|
||||
|
||||
INTERFACE_VERSION = 3
|
||||
timeframe = "1h"
|
||||
# Minimal ROI designed for the strategy.
|
||||
# This attribute will be overridden if the config file contains "minimal_roi".
|
||||
# minimal_roi = {"60": 0.1, "30": 0.2, "0": 0.2}
|
||||
minimal_roi = {"0": 1}
|
||||
|
||||
stoploss = -0.05
|
||||
can_short = True
|
||||
|
||||
# Trailing stoploss
|
||||
trailing_stop = False
|
||||
# trailing_only_offset_is_reached = False
|
||||
# trailing_stop_positive = 0.01
|
||||
# trailing_stop_positive_offset = 0.0 # Disabled / not configured
|
||||
|
||||
# Run "populate_indicators()" only for new candle.
|
||||
process_only_new_candles = False
|
||||
|
||||
# Number of candles the strategy requires before producing valid signals
|
||||
startup_candle_count: int = 30
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
dataframe["adx"] = ta.ADX(dataframe)
|
||||
# RSI
|
||||
dataframe["rsi"] = ta.RSI(dataframe)
|
||||
|
||||
# Stochastic Fast
|
||||
stoch_fast = ta.STOCHF(dataframe)
|
||||
dataframe["fastd"] = stoch_fast["fastd"]
|
||||
dataframe["fastk"] = stoch_fast["fastk"]
|
||||
|
||||
# MACD
|
||||
macd = ta.MACD(dataframe)
|
||||
dataframe["macd"] = macd["macd"]
|
||||
dataframe["macdsignal"] = macd["macdsignal"]
|
||||
dataframe["macdhist"] = macd["macdhist"]
|
||||
|
||||
# MFI
|
||||
dataframe["mfi"] = ta.MFI(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"]
|
||||
|
||||
# Parabolic SAR
|
||||
dataframe["sar"] = ta.SAR(dataframe)
|
||||
|
||||
# TEMA - Triple Exponential Moving Average
|
||||
dataframe["tema"] = ta.TEMA(dataframe, timeperiod=9)
|
||||
|
||||
# Cycle Indicator
|
||||
# ------------------------------------
|
||||
# Hilbert Transform Indicator - SineWave
|
||||
hilbert = ta.HT_SINE(dataframe)
|
||||
dataframe["htsine"] = hilbert["sine"]
|
||||
dataframe["htleadsine"] = hilbert["leadsine"]
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
dataframe.loc[
|
||||
(
|
||||
# Signal: RSI crosses above 30
|
||||
(qtpylib.crossed_above(dataframe["rsi"], 30))
|
||||
& (dataframe["tema"] <= dataframe["bb_middleband"])
|
||||
& ( # Guard: tema below BB middle
|
||||
dataframe["tema"] > dataframe["tema"].shift(1)
|
||||
)
|
||||
& ( # Guard: tema is raising
|
||||
dataframe["volume"] > 0
|
||||
) # Make sure Volume is not 0
|
||||
),
|
||||
"enter_long",
|
||||
] = 1
|
||||
|
||||
dataframe.loc[
|
||||
(
|
||||
# Signal: RSI crosses above 70
|
||||
(qtpylib.crossed_above(dataframe["rsi"], 70))
|
||||
& (dataframe["tema"] > dataframe["bb_middleband"])
|
||||
& ( # Guard: tema above BB middle
|
||||
dataframe["tema"] < dataframe["tema"].shift(1)
|
||||
)
|
||||
& ( # Guard: tema is falling
|
||||
dataframe["volume"] > 0
|
||||
) # Make sure Volume is not 0
|
||||
),
|
||||
"enter_short",
|
||||
] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
dataframe.loc[
|
||||
(
|
||||
# Signal: RSI crosses above 70
|
||||
(qtpylib.crossed_above(dataframe["rsi"], 70))
|
||||
& (dataframe["tema"] > dataframe["bb_middleband"])
|
||||
& ( # Guard: tema above BB middle
|
||||
dataframe["tema"] < dataframe["tema"].shift(1)
|
||||
)
|
||||
& ( # Guard: tema is falling
|
||||
dataframe["volume"] > 0
|
||||
) # Make sure Volume is not 0
|
||||
),
|
||||
"exit_long",
|
||||
] = 1
|
||||
|
||||
dataframe.loc[
|
||||
(
|
||||
# Signal: RSI crosses above 30
|
||||
(qtpylib.crossed_above(dataframe["rsi"], 30))
|
||||
&
|
||||
# Guard: tema below BB middle
|
||||
(dataframe["tema"] <= dataframe["bb_middleband"])
|
||||
& (dataframe["tema"] > dataframe["tema"].shift(1))
|
||||
& ( # Guard: tema is raising
|
||||
dataframe["volume"] > 0
|
||||
) # Make sure Volume is not 0
|
||||
),
|
||||
"exit_short",
|
||||
] = 1
|
||||
|
||||
return dataframe
|
||||
@@ -0,0 +1,249 @@
|
||||
"""
|
||||
Supertrend strategy:
|
||||
* Description: Generate a 3 supertrend indicators for 'buy' strategies & 3 supertrend indicators for 'sell' strategies
|
||||
Buys if the 3 'buy' indicators are 'up'
|
||||
Sells if the 3 'sell' indicators are 'down'
|
||||
* Author: @juankysoriano (Juan Carlos Soriano)
|
||||
* github: https://github.com/juankysoriano/
|
||||
*** NOTE: This Supertrend strategy is just one of many possible strategies using `Supertrend` as indicator. It should on any case used at your own risk.
|
||||
It comes with at least a couple of caveats:
|
||||
1. The implementation for the `supertrend` indicator is based on the following discussion: https://github.com/freqtrade/freqtrade-strategies/issues/30 . Concretelly https://github.com/freqtrade/freqtrade-strategies/issues/30#issuecomment-853042401
|
||||
2. The implementation for `supertrend` on this strategy is not validated; meaning this that is not proven to match the results by the paper where it was originally introduced or any other trusted academic resources
|
||||
"""
|
||||
|
||||
import logging
|
||||
from numpy.lib import math
|
||||
from freqtrade.strategy.interface import IStrategy
|
||||
from freqtrade.strategy.hyper import IntParameter
|
||||
from pandas import DataFrame
|
||||
import talib.abstract as ta
|
||||
import numpy as np
|
||||
|
||||
|
||||
class FSupertrendStrategy(IStrategy):
|
||||
# Buy params, Sell params, ROI, Stoploss and Trailing Stop are values generated by 'freqtrade hyperopt --strategy Supertrend --hyperopt-loss ShortTradeDurHyperOptLoss --timerange=20210101- --timeframe=1h --spaces all'
|
||||
# It's encourage you find the values that better suites your needs and risk management strategies
|
||||
|
||||
# Buy hyperspace params:
|
||||
buy_params = {
|
||||
"buy_m1": 4,
|
||||
"buy_m2": 7,
|
||||
"buy_m3": 1,
|
||||
"buy_p1": 8,
|
||||
"buy_p2": 9,
|
||||
"buy_p3": 8,
|
||||
}
|
||||
|
||||
# Sell hyperspace params:
|
||||
sell_params = {
|
||||
"sell_m1": 1,
|
||||
"sell_m2": 3,
|
||||
"sell_m3": 6,
|
||||
"sell_p1": 16,
|
||||
"sell_p2": 18,
|
||||
"sell_p3": 18,
|
||||
}
|
||||
|
||||
# ROI table:
|
||||
minimal_roi = {"0": 0.1, "30": 0.75, "60": 0.05, "120": 0.025}
|
||||
# minimal_roi = {"0": 1}
|
||||
|
||||
# Stoploss:
|
||||
stoploss = -0.265
|
||||
|
||||
# Trailing stop:
|
||||
trailing_stop = True
|
||||
trailing_stop_positive = 0.05
|
||||
trailing_stop_positive_offset = 0.1
|
||||
trailing_only_offset_is_reached = False
|
||||
|
||||
timeframe = "1h"
|
||||
|
||||
startup_candle_count = 18
|
||||
|
||||
buy_m1 = IntParameter(1, 7, default=1)
|
||||
buy_m2 = IntParameter(1, 7, default=3)
|
||||
buy_m3 = IntParameter(1, 7, default=4)
|
||||
buy_p1 = IntParameter(7, 21, default=14)
|
||||
buy_p2 = IntParameter(7, 21, default=10)
|
||||
buy_p3 = IntParameter(7, 21, default=10)
|
||||
|
||||
sell_m1 = IntParameter(1, 7, default=1)
|
||||
sell_m2 = IntParameter(1, 7, default=3)
|
||||
sell_m3 = IntParameter(1, 7, default=4)
|
||||
sell_p1 = IntParameter(7, 21, default=14)
|
||||
sell_p2 = IntParameter(7, 21, default=10)
|
||||
sell_p3 = IntParameter(7, 21, default=10)
|
||||
|
||||
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
for multiplier in self.buy_m1.range:
|
||||
for period in self.buy_p1.range:
|
||||
dataframe[f"supertrend_1_buy_{multiplier}_{period}"] = self.supertrend(
|
||||
dataframe, multiplier, period
|
||||
)["STX"]
|
||||
|
||||
for multiplier in self.buy_m2.range:
|
||||
for period in self.buy_p2.range:
|
||||
dataframe[f"supertrend_2_buy_{multiplier}_{period}"] = self.supertrend(
|
||||
dataframe, multiplier, period
|
||||
)["STX"]
|
||||
|
||||
for multiplier in self.buy_m3.range:
|
||||
for period in self.buy_p3.range:
|
||||
dataframe[f"supertrend_3_buy_{multiplier}_{period}"] = self.supertrend(
|
||||
dataframe, multiplier, period
|
||||
)["STX"]
|
||||
|
||||
for multiplier in self.sell_m1.range:
|
||||
for period in self.sell_p1.range:
|
||||
dataframe[f"supertrend_1_sell_{multiplier}_{period}"] = self.supertrend(
|
||||
dataframe, multiplier, period
|
||||
)["STX"]
|
||||
|
||||
for multiplier in self.sell_m2.range:
|
||||
for period in self.sell_p2.range:
|
||||
dataframe[f"supertrend_2_sell_{multiplier}_{period}"] = self.supertrend(
|
||||
dataframe, multiplier, period
|
||||
)["STX"]
|
||||
|
||||
for multiplier in self.sell_m3.range:
|
||||
for period in self.sell_p3.range:
|
||||
dataframe[f"supertrend_3_sell_{multiplier}_{period}"] = self.supertrend(
|
||||
dataframe, multiplier, period
|
||||
)["STX"]
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
|
||||
dataframe.loc[
|
||||
(
|
||||
dataframe[f"supertrend_1_buy_{self.buy_m1.value}_{self.buy_p1.value}"]
|
||||
== "up"
|
||||
)
|
||||
& (
|
||||
dataframe[f"supertrend_2_buy_{self.buy_m2.value}_{self.buy_p2.value}"]
|
||||
== "up"
|
||||
)
|
||||
& (
|
||||
dataframe[f"supertrend_3_buy_{self.buy_m3.value}_{self.buy_p3.value}"]
|
||||
== "up"
|
||||
)
|
||||
& ( # The three indicators are 'up' for the current candle
|
||||
dataframe["volume"] > 0
|
||||
),
|
||||
"enter_long",
|
||||
] = 1
|
||||
|
||||
dataframe.loc[
|
||||
(
|
||||
dataframe[
|
||||
f"supertrend_1_sell_{self.sell_m1.value}_{self.sell_p1.value}"
|
||||
]
|
||||
== "down"
|
||||
)
|
||||
& (
|
||||
dataframe[
|
||||
f"supertrend_2_sell_{self.sell_m2.value}_{self.sell_p2.value}"
|
||||
]
|
||||
== "down"
|
||||
)
|
||||
& (
|
||||
dataframe[
|
||||
f"supertrend_3_sell_{self.sell_m3.value}_{self.sell_p3.value}"
|
||||
]
|
||||
== "down"
|
||||
)
|
||||
& ( # The three indicators are 'down' for the current candle
|
||||
dataframe["volume"] > 0
|
||||
),
|
||||
"enter_short",
|
||||
] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||
dataframe.loc[
|
||||
(
|
||||
dataframe[
|
||||
f"supertrend_2_sell_{self.sell_m2.value}_{self.sell_p2.value}"
|
||||
]
|
||||
== "down"
|
||||
),
|
||||
"exit_long",
|
||||
] = 1
|
||||
|
||||
dataframe.loc[
|
||||
(
|
||||
dataframe[f"supertrend_2_buy_{self.buy_m2.value}_{self.buy_p2.value}"]
|
||||
== "up"
|
||||
),
|
||||
"exit_short",
|
||||
] = 1
|
||||
|
||||
return dataframe
|
||||
|
||||
"""
|
||||
Supertrend Indicator; adapted for freqtrade
|
||||
from: https://github.com/freqtrade/freqtrade-strategies/issues/30
|
||||
"""
|
||||
|
||||
def supertrend(self, dataframe: DataFrame, multiplier, period):
|
||||
df = dataframe.copy()
|
||||
|
||||
df["TR"] = ta.TRANGE(df)
|
||||
df["ATR"] = ta.SMA(df["TR"], period)
|
||||
|
||||
st = "ST_" + str(period) + "_" + str(multiplier)
|
||||
stx = "STX_" + str(period) + "_" + str(multiplier)
|
||||
|
||||
# Compute basic upper and lower bands
|
||||
df["basic_ub"] = (df["high"] + df["low"]) / 2 + multiplier * df["ATR"]
|
||||
df["basic_lb"] = (df["high"] + df["low"]) / 2 - multiplier * df["ATR"]
|
||||
|
||||
# Compute final upper and lower bands
|
||||
df["final_ub"] = 0.00
|
||||
df["final_lb"] = 0.00
|
||||
for i in range(period, len(df)):
|
||||
df["final_ub"].iat[i] = (
|
||||
df["basic_ub"].iat[i]
|
||||
if df["basic_ub"].iat[i] < df["final_ub"].iat[i - 1]
|
||||
or df["close"].iat[i - 1] > df["final_ub"].iat[i - 1]
|
||||
else df["final_ub"].iat[i - 1]
|
||||
)
|
||||
df["final_lb"].iat[i] = (
|
||||
df["basic_lb"].iat[i]
|
||||
if df["basic_lb"].iat[i] > df["final_lb"].iat[i - 1]
|
||||
or df["close"].iat[i - 1] < df["final_lb"].iat[i - 1]
|
||||
else df["final_lb"].iat[i - 1]
|
||||
)
|
||||
|
||||
# Set the Supertrend value
|
||||
df[st] = 0.00
|
||||
for i in range(period, len(df)):
|
||||
df[st].iat[i] = (
|
||||
df["final_ub"].iat[i]
|
||||
if df[st].iat[i - 1] == df["final_ub"].iat[i - 1]
|
||||
and df["close"].iat[i] <= df["final_ub"].iat[i]
|
||||
else df["final_lb"].iat[i]
|
||||
if df[st].iat[i - 1] == df["final_ub"].iat[i - 1]
|
||||
and df["close"].iat[i] > df["final_ub"].iat[i]
|
||||
else df["final_lb"].iat[i]
|
||||
if df[st].iat[i - 1] == df["final_lb"].iat[i - 1]
|
||||
and df["close"].iat[i] >= df["final_lb"].iat[i]
|
||||
else df["final_ub"].iat[i]
|
||||
if df[st].iat[i - 1] == df["final_lb"].iat[i - 1]
|
||||
and df["close"].iat[i] < df["final_lb"].iat[i]
|
||||
else 0.00
|
||||
)
|
||||
# Mark the trend direction up/down
|
||||
df[stx] = np.where(
|
||||
(df[st] > 0.00), np.where((df["close"] < df[st]), "down", "up"), np.NaN
|
||||
)
|
||||
|
||||
# Remove basic and final bands from the columns
|
||||
df.drop(["basic_ub", "basic_lb", "final_ub", "final_lb"], inplace=True, axis=1)
|
||||
|
||||
df.fillna(0, inplace=True)
|
||||
|
||||
return DataFrame(index=df.index, data={"ST": df[st], "STX": df[stx]})
|
||||
Reference in New Issue
Block a user