author@: @Arthie github@: https://github.com/droidoz/freqtrade/ Other strategies for Freqtrade https://github.com/freqtrade/freqtrade
Timeframe
5m
Direction
Long Only
Stoploss
-13.0%
Trailing Stop
No
ROI
0m: 4.0%, 20m: 3.0%, 30m: 1.0%, 120m: 0.0%
Interface Version
3
Startup Candles
600
Indicators
5
freqtrade/freqtrade-strategies
Strategy 003 author@: Gerald Lonlas github@: https://github.com/freqtrade/freqtrade-strategies
# --- Do not remove these libs ---
from freqtrade.strategy import IStrategy, informative
from pandas import DataFrame
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
import numpy # noqa
# --------------------------------
# --- For conditions
from functools import reduce
# --- For hyperopt
from freqtrade.strategy import CategoricalParameter, DecimalParameter, IntParameter, BooleanParameter
from freqtrade.optimize.space import Categorical, Dimension, Integer, SKDecimal
# --- Other
from typing import Dict, List, Union, Optional
class SMACross_V1(IStrategy):
"""
author@: @Arthie
github@: https://github.com/droidoz/freqtrade/
Other strategies for Freqtrade https://github.com/freqtrade/freqtrade
This is a simple SMA crossover strategy framework to experiment with;
Feel free to try other SMA timeperiod combo in Hyperoptable parameters.
Note: always dry testing the strategy before going live ! Use at your own risk.
"""
def version(self) -> str:
return "v3"
INTERFACE_VERSION = 3
plot_config = {
'main_plot': {
"bb_lowerband": {
"color": "#e66100",
"type": "line",
"fill_to": "bb_upperband"
},
"bb_upperband": {
"color": "#F0E68C",
"type": "line"
},
'buy_MA1': {'color': '#8A2BE2', 'fill_to': 'buy_MA2'},
'buy_MA2': {'color': '#5F9EA0', 'fill_to': 'buy_MA3'},
},
'subplots': {
"MACD": {
'macd': {'color': '#00FF00', 'fill_to': 'macdhist'},
'macdhist': {'type': 'bar', 'color': '#FF00FF'},
'macdsignal': {'color': '#00FFFF'},
},
'ADX': {
'adx': {'color': '#FFF5EE'},
'minus_di': {'color': '#E9967A', 'fill_to': 'plus_di'},
'plus_di' :{'color': '#FF4500'},
},
"RSI": {
'rsi': {'type': 'bar', 'color': '#C71585'}
},
}
}
# Optional
@property
def protections(self):
return [
{
"method": "CooldownPeriod",
"stop_duration_candles": 5
},
{
"method": "MaxDrawdown",
"lookback_period_candles": 48,
"trade_limit": 20,
"stop_duration_candles": 4,
"max_allowed_drawdown": 0.2
},
{
"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": 2,
"required_profit": 0.02
},
{
"method": "LowProfitPairs",
"lookback_period_candles": 24,
"trade_limit": 4,
"stop_duration_candles": 2,
"required_profit": 0.01
}
]
class HyperOpt:
def generate_estimator(dimensions: List['Dimension'], **kwargs):
from skopt.learning import ExtraTreesRegressor
# Corresponds to "ET" - but allows additional parameters.
return ExtraTreesRegressor(n_estimators=500) # Default = 100
# Define a custom stoploss space.
def stoploss_space():
return [SKDecimal(-0.30, -0.10, decimals=2, name='stoploss')]
# Define custom ROI space
def roi_space() -> List[Dimension]:
return [
Integer(10, 120, name='roi_t1'),
Integer(10, 60, name='roi_t2'),
Integer(10, 40, name='roi_t3'),
SKDecimal(0.01, 0.04, decimals=2, name='roi_p1'),
SKDecimal(0.01, 0.07, decimals=2, name='roi_p2'),
SKDecimal(0.01, 0.10, decimals=2, name='roi_p3'),
]
def generate_roi_table(params: Dict) -> Dict[int, float]:
roi_table = {}
roi_table[0] = params['roi_p1'] + params['roi_p2'] + params['roi_p3']
roi_table[params['roi_t3']] = params['roi_p1'] + params['roi_p2']
roi_table[params['roi_t3'] + params['roi_t2']] = params['roi_p1']
roi_table[params['roi_t3'] + params['roi_t2'] + params['roi_t1']] = 0
return roi_table
def trailing_space() -> List[Dimension]:
# All parameters here are mandatory, you can only modify their type or the range.
return [
# Fixed to true, if optimizing trailing_stop we assume to use trailing stop at all times.
Categorical([True], name='trailing_stop'),
SKDecimal(0.01, 0.35, decimals=3, name='trailing_stop_positive'),
SKDecimal(0.001, 0.1, decimals=3, name='trailing_stop_positive_offset_p1'),
Categorical([True, False], name='trailing_only_offset_is_reached'),
]
# Define protections parameters spaces
cooldown_lookback = IntParameter(2, 48, default=5, space="protection", optimize=True)
stop_duration = IntParameter(12, 200, default=5, space="protection", optimize=True)
use_stop_protection = BooleanParameter(default=True, space="protection", optimize=True)
# Optional
# Protection hyperspace params:
protection_params = {
"cooldown_lookback": 5,
"stop_duration": 12,
"use_stop_protection": True,
}
# Hyperoptable parameters
buy_adx = DecimalParameter(25, 50, decimals=1, default=30.1, space="buy", optimize=True)
buy_rsi = IntParameter(20, 40, default=30, space="buy", optimize=True)
buy_adx_enabled = BooleanParameter(default=True, space="buy", optimize=True)
buy_rsi_enabled = CategoricalParameter([True, False], default=False, space="buy", optimize=True)
buy_trigger = CategoricalParameter(["bb_lower", "macd_cross_signal"], default="bb_lower", space="buy", optimize=True)
buy_MA1 = IntParameter(low=3, high=7, default=5, space='buy', optimize=True)
buy_MA2 = IntParameter(low=8, high=25, default=8, space='buy', optimize=True)
sell_trigger = CategoricalParameter(["bb_upper", "macd_cross_signal"], default="bb_upper", space="sell", optimize=True)
# Buy hyperspace params:
buy_params = {
"buy_MA1": 7,
"buy_MA2": 13,
"buy_adx": 40.0,
"buy_adx_enabled": False,
"buy_rsi": 22,
"buy_rsi_enabled": False,
"buy_trigger": "bb_lower",
}
# Sell hyperspace params:
sell_params = {
"sell_trigger": "bb_upper",
}
# ROI table:
minimal_roi = {
"0": 0.04,
"20": 0.03,
"30": 0.01,
"120": 0
}
# Stoploss:
stoploss = -0.13
use_custom_stoploss = False
# Optimal timeframe for the strategy
timeframe = '5m'
# Trailing stop:
trailing_stop = False
trailing_stop_positive = 0.01
trailing_stop_positive_offset = 0.02
trailing_only_offset_is_reached = False
# run "populate_indicators" only for new candle
process_only_new_candles = True
startup_candle_count = 600
# Experimental settings (configuration will overide these if set)
use_exit_signal = True
exit_profit_only = True
ignore_roi_if_entry_signal = False
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# ADX
dataframe['adx'] = ta.ADX(dataframe)
# BBANDS
bollinger = ta.BBANDS(dataframe, timeperiod=20, nbdevup=2.0, nbdevdn=2.0)
dataframe['bb_lowerband'] = bollinger['lowerband']
dataframe['bb_middleband'] = bollinger['middleband']
dataframe['bb_upperband'] = bollinger['upperband']
# SMA
dataframe['buy_MA1'] = ta.SMA(dataframe, timeperiod=self.buy_MA1.value)
dataframe['buy_MA2'] = ta.SMA(dataframe, timeperiod=self.buy_MA2.value)
# MACD
macd = ta.MACD(dataframe)
dataframe['macd'] = macd['macd']
dataframe['macdsignal'] = macd['macdsignal']
dataframe['macdhist'] = macd['macdhist']
# Minus & Plus Directional Indicator / Movement
dataframe['minus_di'] = ta.MINUS_DI(dataframe)
dataframe['plus_di'] = ta.PLUS_DI(dataframe)
# RSI
dataframe['rsi'] = ta.RSI(dataframe)
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
conditions = []
# Trend up
conditions.append(dataframe['plus_di'] > dataframe['minus_di'])
conditions.append(dataframe['buy_MA1'] > dataframe['buy_MA2'])
# GUARDS AND TRENDS
if self.buy_adx_enabled.value:
conditions.append(dataframe['adx'] > self.buy_adx.value)
if self.buy_rsi_enabled.value:
conditions.append(dataframe['rsi'] < self.buy_rsi.value)
# TRIGGERS
if self.buy_trigger.value == 'bb_lower':
conditions.append(dataframe['close'] < dataframe['bb_lowerband'])
if self.buy_trigger.value == 'macd_cross_signal':
conditions.append(qtpylib.crossed_above(
dataframe['macd'], dataframe['macdsignal']
))
# Volume is above 0
conditions.append(dataframe['volume'] > 0)
if conditions:
dataframe.loc[
reduce(lambda x, y: x & y, conditions),
['enter_long', 'enter_tag']] = (1, 'buy_signal')
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
conditions = []
# TRIGGERS
if self.sell_trigger.value == 'bb_upper':
conditions.append(dataframe['close'] > dataframe['bb_upperband'])
if self.sell_trigger.value == 'macd_cross_signal':
conditions.append(qtpylib.crossed_below(
dataframe['macd'], dataframe['macdsignal']
))
# Volume above 0
conditions.append(dataframe['volume'] > 0)
if conditions:
dataframe.loc[
reduce(lambda x, y: x & y, conditions),
['exit_long', 'exit_tag']] = (1, 'sell_signal')
return dataframe