This strategy is based on market structure, identifying pivot points (higher highs and lower lows) and trading based on demand zones created from these structures.
Timeframe
5m
Direction
Long Only
Stoploss
-10.0%
Trailing Stop
Yes
ROI
0m: 15.0%, 30m: 10.0%, 60m: 5.0%
Interface Version
2
Startup Candles
N/A
Indicators
1
freqtrade/freqtrade-strategies
author@: lenik
# --- Do not remove these libs ---
from freqtrade.strategy import IStrategy, IntParameter
from pandas import DataFrame
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
import numpy as np
from scipy.signal import argrelextrema
class MarketStructureStrategy(IStrategy):
"""
This strategy is based on market structure, identifying pivot points (higher highs and lower lows)
and trading based on demand zones created from these structures.
"""
# Strategy interface version - attribute needed by Freqtrade
INTERFACE_VERSION = 2
# Minimal ROI designed for the strategy.
minimal_roi = {
"0": 0.15,
"30": 0.10,
"60": 0.05
}
# Stoploss:
stoploss = -0.10
# Trailing stop:
trailing_stop = True
trailing_stop_positive = 0.01
trailing_stop_positive_offset = 0.02
trailing_only_offset_is_reached = True
# Optimal timeframe for the strategy
timeframe = '5m'
# Parameters for pivot points
pivot_window = IntParameter(5, 20, default=8, space="buy")
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Adds several different TA indicators to the given DataFrame
"""
# Pivot Points
n = self.pivot_window.value
dataframe['pivot_high'] = (dataframe['high'].rolling(window=2*n+1, center=True).max() == dataframe['high']).astype(int)
dataframe['pivot_low'] = (dataframe['low'].rolling(window=2*n+1, center=True).min() == dataframe['low']).astype(int)
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Based on TA indicators, populates the entry signal for the given dataframe
"""
dataframe['enter_long'] = 0
pivots_high = dataframe[dataframe['pivot_high'] == 1]
pivots_low = dataframe[dataframe['pivot_low'] == 1]
if len(pivots_low) < 2 or len(pivots_high) < 2:
return dataframe
last_pivot_low = pivots_low.index[-1]
second_last_pivot_low = pivots_low.index[-2]
last_pivot_high = pivots_high.index[-1]
second_last_pivot_high = pivots_high.index[-2]
# Identify Higher High and Higher Low
if (pivots_high.loc[last_pivot_high, 'high'] > pivots_high.loc[second_last_pivot_high, 'high'] and
pivots_low.loc[last_pivot_low, 'low'] > pivots_low.loc[second_last_pivot_low, 'low']):
# Find the demand zone (last bearish candle before the up-move)
up_move_start_index = second_last_pivot_low
demand_zone_candle = dataframe.loc[up_move_start_index - 1] # Previous candle
if demand_zone_candle['close'] < demand_zone_candle['open']: # It's a bearish candle
demand_zone_top = demand_zone_candle['open']
demand_zone_bottom = demand_zone_candle['close']
# Potential entry when price touches the demand zone
for i in range(last_pivot_low, len(dataframe)):
if dataframe.loc[i, 'low'] <= demand_zone_top:
entry_price = demand_zone_top
stop_loss_price = demand_zone_bottom
take_profit_price = pivots_high.loc[last_pivot_high, 'high']
# Risk/Reward Ratio Check
if (entry_price - stop_loss_price) > 0:
rr_ratio = (take_profit_price - entry_price) / (entry_price - stop_loss_price)
if rr_ratio >= 2.5:
dataframe.loc[i, 'enter_long'] = 1
break # Exit loop after finding an entry
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Based on TA indicators, populates the exit signal for the given dataframe
"""
dataframe['exit_long'] = 0
return dataframe