This is a strategy template to get you started. More information in https://www.freqtrade.io/en/latest/strategy-customization/
Timeframe
5m
Direction
Long Only
Stoploss
-10.0%
Trailing Stop
Yes
ROI
0m: 4.0%, 30m: 2.0%, 60m: 1.0%
Interface Version
3
Startup Candles
N/A
Indicators
18
freqtrade/freqtrade-strategies
Strategy 003 author@: Gerald Lonlas github@: https://github.com/freqtrade/freqtrade-strategies
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
# flake8: noqa: F401
# isort: skip_file
# --- Do not remove these imports ---
import numpy as np
import pandas as pd
from datetime import datetime, timedelta, timezone
from pandas import DataFrame
from typing import Dict, Optional, Union, Tuple
from freqtrade.strategy import (
IStrategy,
Trade,
Order,
PairLocks,
informative, # @informative decorator
# Hyperopt Parameters
BooleanParameter,
CategoricalParameter,
DecimalParameter,
IntParameter,
RealParameter,
# timeframe helpers
timeframe_to_minutes,
timeframe_to_next_date,
timeframe_to_prev_date,
# Strategy helper functions
merge_informative_pair,
stoploss_from_absolute,
stoploss_from_open,
AnnotationType,
)
# --------------------------------
# Add your lib to import here
import talib.abstract as ta
from technical import qtpylib
class SwingTradingStrategy(IStrategy):
"""
This is a strategy template to get you started.
More information in https://www.freqtrade.io/en/latest/strategy-customization/
You can:
:return: a Dataframe with all mandatory indicators for the strategies
- Rename the class name (Do not forget to update class_name)
- Add any methods you want to build your strategy
- Add any lib you need to build your strategy
You must keep:
- the lib in the section "Do not remove these libs"
- the methods: populate_indicators, populate_entry_trend, populate_exit_trend
You should keep:
- timeframe, minimal_roi, stoploss, trailing_*
"""
# 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 = "5m"
# Can this strategy go short?
can_short: bool = True
# Minimal ROI designed for the strategy.
# This attribute will be overridden if the config file contains "minimal_roi".
minimal_roi = {"60": 0.01, "30": 0.02, "0": 0.04}
# Optimal stoploss designed for the strategy.
# This attribute will be overridden if the config file contains "stoploss".
stoploss = -0.10
# Trailing stoploss
trailing_stop = True
# 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 = 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
# Optional order type mapping.
order_types = {
"entry": "limit",
"exit": "limit",
"stoploss": "market",
"stoploss_on_exchange": False,
}
# EMA timeperiod parameter
ema_timeperiod = IntParameter(
low=2, high=90, default=8, space="timeperiod", optimize=True, load=True
)
# Return on investment parameters
enter_long_ror = DecimalParameter(
low=0, high=1, default=0.0, decimals=1, space="enter", optimize=True, load=True
)
exit_long_ror = DecimalParameter(
low=-1, high=0, default=0.0, decimals=1, space="exit", optimize=True, load=True
)
enter_short_ror = DecimalParameter(
low=-1, high=0, default=0.0, decimals=1, space="enter", optimize=True, load=True
)
exit_short_ror = DecimalParameter(
low=0, high=1, default=0.0, decimals=1, space="exit", optimize=True, load=True
)
# # Return on investment parameters
# enter_aroon_up = DecimalParameter(
# low=0, high=100, default=80, decimals=1, space="enter", optimize=True, load=True
# )
# enter_aroon_down = DecimalParameter(
# low=0, high=100, default=80, decimals=1, space="enter", optimize=True, load=True
# )
# # Return on investment parameters
# exit_aroon_up = DecimalParameter(
# low=0, high=100, default=20, decimals=1, space="exit", optimize=True, load=True
# )
# exit_aroon_down = DecimalParameter(
# low=0, high=100, default=20, decimals=1, space="exit", optimize=True, load=True
# )
# Optional order time in force.
order_time_in_force = {"entry": "GTC", "exit": "GTC"}
@property
def plot_config(self):
return {
"main_plot": {
"ema2": {"color": "yellow"},
"ema8": {"color": "black"},
"ema44": {"color": "red"},
},
"subplots": {
"AROON": {
"aroonup": {"color": "orange"},
"aroondown": {"color": "blue"},
},
},
}
def version(self) -> str | None:
return super().version()
def leverage(
self,
pair: str,
current_time: datetime,
current_rate: float,
proposed_leverage: float,
max_leverage: float,
entry_tag: str | None,
side: str,
**kwargs,
) -> float:
return 5.0
def informative_pairs(self):
"""
Define additional, informative pair/interval combinations to be cached from the exchange.
These pair/interval combinations are non-tradeable, unless they are part
of the whitelist as well.
For more information, please consult the documentation
:return: List of tuples in the format (pair, interval)
Sample: return [("ETH/USDT", "5m"),
("BTC/USDT", "15m"),
]
"""
return []
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Momentum Indicators
# ------------------------------------
# ADX
# dataframe["adx"] = ta.ADX(dataframe)
# # 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)
# # Awesome Oscillator
# dataframe["ao"] = qtpylib.awesome_oscillator(dataframe)
# # 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)
# # Commodity Channel Index: values [Oversold:-100, Overbought:100]
# dataframe["cci"] = ta.CCI(dataframe)
# RSI
# dataframe["rsi"] = ta.RSI(dataframe)
# # Inverse Fisher transform on RSI: values [-1.0, 1.0] (https://goo.gl/2JGGoy)
# rsi = 0.1 * (dataframe["rsi"] - 50)
# dataframe["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_norma"] = 50 * (dataframe["fisher_rsi"] + 1)
# # 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"]
# dataframe["fastk"] = stoch_fast["fastk"]
# # Stochastic RSI
# Please read https://github.com/freqtrade/freqtrade/issues/2961 before using this.
# STOCHRSI is NOT aligned with tradingview, which may result in non-expected results.
# 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)
# # ROC
# dataframe["roc"] = ta.ROC(dataframe)
# 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"]
# )
# # 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["sma21"] = ta.SMA(dataframe, timeperiod=21)
# dataframe["sma50"] = ta.SMA(dataframe, timeperiod=50)
# dataframe["sma100"] = ta.SMA(dataframe, timeperiod=100)
# 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"]
# Pattern Recognition - Bullish candlestick patterns
# ------------------------------------
# # Hammer: values [0, 100]
# dataframe["CDLHAMMER"] = ta.CDLHAMMER(dataframe)
# # Inverted Hammer: values [0, 100]
# dataframe["CDLINVERTEDHAMMER"] = ta.CDLINVERTEDHAMMER(dataframe)
# # Dragonfly Doji: values [0, 100]
# dataframe["CDLDRAGONFLYDOJI"] = ta.CDLDRAGONFLYDOJI(dataframe)
# # Piercing Line: values [0, 100]
# dataframe["CDLPIERCING"] = ta.CDLPIERCING(dataframe) # values [0, 100]
# # Morningstar: values [0, 100]
# dataframe["CDLMORNINGSTAR"] = ta.CDLMORNINGSTAR(dataframe) # values [0, 100]
# # Three White Soldiers: values [0, 100]
# dataframe["CDL3WHITESOLDIERS"] = ta.CDL3WHITESOLDIERS(dataframe) # values [0, 100]
# Pattern Recognition - Bearish candlestick patterns
# ------------------------------------
# # Hanging Man: values [0, 100]
# dataframe["CDLHANGINGMAN"] = ta.CDLHANGINGMAN(dataframe)
# # Shooting Star: values [0, 100]
# dataframe["CDLSHOOTINGSTAR"] = ta.CDLSHOOTINGSTAR(dataframe)
# # Gravestone Doji: values [0, 100]
# dataframe["CDLGRAVESTONEDOJI"] = ta.CDLGRAVESTONEDOJI(dataframe)
# # Dark Cloud Cover: values [0, 100]
# dataframe["CDLDARKCLOUDCOVER"] = ta.CDLDARKCLOUDCOVER(dataframe)
# # Evening Doji Star: values [0, 100]
# dataframe["CDLEVENINGDOJISTAR"] = ta.CDLEVENINGDOJISTAR(dataframe)
# # Evening Star: values [0, 100]
# dataframe["CDLEVENINGSTAR"] = ta.CDLEVENINGSTAR(dataframe)
# Pattern Recognition - Bullish/Bearish candlestick patterns
# ------------------------------------
# # Three Line Strike: values [0, -100, 100]
# dataframe["CDL3LINESTRIKE"] = ta.CDL3LINESTRIKE(dataframe)
# # Spinning Top: values [0, -100, 100]
# dataframe["CDLSPINNINGTOP"] = ta.CDLSPINNINGTOP(dataframe) # values [0, -100, 100]
# # Engulfing: values [0, -100, 100]
# dataframe["CDLENGULFING"] = ta.CDLENGULFING(dataframe) # values [0, -100, 100]
# # Harami: values [0, -100, 100]
# dataframe["CDLHARAMI"] = ta.CDLHARAMI(dataframe) # values [0, -100, 100]
# # Three Outside Up/Down: values [0, -100, 100]
# dataframe["CDL3OUTSIDE"] = ta.CDL3OUTSIDE(dataframe) # values [0, -100, 100]
# # Three Inside Up/Down: values [0, -100, 100]
# dataframe["CDL3INSIDE"] = ta.CDL3INSIDE(dataframe) # values [0, -100, 100]
# # Chart type
# # ------------------------------------
# # Heikin Ashi Strategy
# heikinashi = qtpylib.heikinashi(dataframe)
# dataframe["ha_open"] = heikinashi["open"]
# dataframe["ha_close"] = heikinashi["close"]
# dataframe["ha_high"] = heikinashi["high"]
# dataframe["ha_low"] = heikinashi["low"]
# EMA - Parameter Range
for val in self.ema_timeperiod.range:
dataframe[f"ema{val}"] = ta.EMA(dataframe, timeperiod=val)
dataframe[f"ror_ema{val}"] = dataframe[f"ema{val}"].pct_change()
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(
dataframe[f"ror_ema{self.ema_timeperiod.value}"]
> self.enter_long_ror.value
)
& (dataframe[f"ror_ema{self.ema_timeperiod.value}"].shift(1) > 0)
& (qtpylib.crossed_above(dataframe["aroonup"], dataframe["aroondown"]))
# & (dataframe["aroonup"] > self.enter_aroon_up.value)
& (dataframe["volume"] > 0)
),
"enter_long",
] = 1
dataframe.loc[
(
(
dataframe[f"ror_ema{self.ema_timeperiod.value}"]
< self.enter_short_ror.value
)
& (dataframe[f"ror_ema{self.ema_timeperiod.value}"].shift(1) < 0)
& (qtpylib.crossed_below(dataframe["aroondown"], dataframe["aroonup"]))
# & (dataframe["aroondown"] > self.enter_aroon_down.value)
& (dataframe["volume"] > 0)
),
"enter_short",
] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(
dataframe[f"ror_ema{self.ema_timeperiod.value}"]
< self.exit_long_ror.value
)
# | (dataframe["aroonup"] < self.exit_aroon_up.value)
& (dataframe["volume"] > 0)
),
"exit_long",
] = 1
dataframe.loc[
(
(
dataframe[f"ror_ema{self.ema_timeperiod.value}"]
> self.exit_short_ror.value
)
# | (dataframe["aroondown"] < self.exit_aroon_down.value)
& (dataframe["volume"] > 0)
),
"exit_short",
] = 1
return dataframe