Timeframe
3m
Direction
Long & Short
Stoploss
-1.0%
Trailing Stop
No
ROI
N/A
Interface Version
3
Startup Candles
N/A
Indicators
0
davidzr/freqtrade-strategies
BB_RPB_TSL @author jilv220 Simple bollinger brand strategy inspired by this blog ( https://hacks-for-life.blogspot.com/2020/12/freqtrade-notes.html ) RPB, which stands for Real Pull Back, taken from ( https://github.com/GeorgeMurAlkh/freqtrade-stuff/blob/main/user_data/strategies/TheRealPullbackV2.py ) The trailing custom stoploss taken from BigZ04_TSL from Perkmeister ( modded by ilya ) I modified it to better suit my taste and added Hyperopt for this strategy.
TheoBrigitte/freqtrade
This strategy is based on research work by Sergey Malchevskiy and uses Renko bricks to identify trends. The brick size is optimized using ATR to find out boundaries from an informative period. For more information on the brick size optimization, see the following article: https://towardsdatascience.com/renko-brick-size-optimization-34d64400f60e
keithorange/HUGE_FreqTrade_Strategy_Collection
BB_RPB_TSL @author jilv220 Simple bollinger brand strategy inspired by this blog ( https://hacks-for-life.blogspot.com/2020/12/freqtrade-notes.html ) RPB, which stands for Real Pull Back, taken from ( https://github.com/GeorgeMurAlkh/freqtrade-stuff/blob/main/user_data/strategies/TheRealPullbackV2.py ) The trailing custom stoploss taken from BigZ04_TSL from Perkmeister ( modded by ilya ) I modified it to better suit my taste and added Hyperopt for this strategy.
# 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 Optional, Union
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,
)
class IlliquidityStrategy(IStrategy):
INTERFACE_VERSION = 3
timeframe = "3m"
# 0.5%
stoploss = -0.010
max_volume_ratio = 0.25 # 25% of volume
can_short = True
use_custom_stoploss: bool = False
trailing_stop: bool = True
trailing_stop_positive: float | None = 0.03
trailing_stop_positive_offset: float = 0.0
trailing_only_offset_is_reached = False
def custom_stoploss(
self,
pair: str,
trade: Trade,
current_time: datetime,
current_rate: float,
current_profit: float,
after_fill: bool,
**kwargs,
) -> float | None:
"""
Custom stoploss logic, returning the new distance relative to current_rate (as ratio).
e.g. returning -0.05 would create a stoploss 5% below current_rate.
The custom stoploss can never be below self.stoploss, which serves as a hard maximum loss.
For full documentation please go to https://www.freqtrade.io/en/latest/strategy-advanced/
When not implemented by a strategy, returns the initial stoploss value.
Only called when use_custom_stoploss is set to True.
:param pair: Pair that's currently analyzed
:param trade: trade object.
:param current_time: datetime object, containing the current datetime
:param current_rate: Rate, calculated based on pricing settings in exit_pricing.
:param current_profit: Current profit (as ratio), calculated based on current_rate.
:param after_fill: True if the stoploss is called after the order was filled.
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
:return float: New stoploss value, relative to the current_rate
"""
return self.stoploss
def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float,
proposed_stake: float, min_stake: Optional[float], max_stake: float,
entry_tag: Optional[str], side: str, **kwargs) -> float:
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
current_candle = dataframe.iloc[-1]
# Calculate volume in USDT
volume_usdt = current_candle['volume'] * current_candle['close']
# Max stake is 25% of volume
max_stake_volume = volume_usdt * self.max_volume_ratio
# Return minimum between proposed stake and volume-based stake
return min(proposed_stake, max_stake_volume)
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:
"""
Customize leverage for each new trade. This method is only called in futures mode.
:param pair: Pair that's currently analyzed
:param current_time: datetime object, containing the current datetime
:param current_rate: Rate, calculated based on pricing settings in exit_pricing.
:param proposed_leverage: A leverage proposed by the bot.
:param max_leverage: Max leverage allowed on this pair
:param entry_tag: Optional entry_tag (buy_tag) if provided with the buy signal.
:param side: "long" or "short" - indicating the direction of the proposed trade
:return: A leverage amount, which is between 1.0 and max_leverage.
"""
return 1.0
# Volume multiplier parameter
volume_multiplier = IntParameter(
low=20, high=100, default=50,
space='buy', optimize=True
)
# Window size for volume average
volume_window = IntParameter(
low=50, high=200, default=100,
space='buy', optimize=True
)
amihud_threshold = DecimalParameter(low=0.05, high=0.05, default=0.05,
space='buy', optimize=True)
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""Add volume and illiquidity indicators"""
# Calculate rolling volume average
dataframe['volume_mean'] = dataframe['volume'].rolling(
window=self.volume_window.value
).mean()
# Calculate volume ratio
dataframe['volume_ratio'] = dataframe['volume'] / dataframe['volume_mean']
dataframe['volume_shares'] = dataframe['volume'] * dataframe['close']
# Price change percentage
dataframe['price_pct'] = dataframe['close'].pct_change() * 100
# Calculate Amihud illiquidity ratio (absolute return / volume)
dataframe['amihud_ratio'] = (dataframe['price_pct'].abs() / dataframe['volume'])
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""Entry signals based on Amihud illiquidity ratio and volume pump"""
dataframe.loc[
(
# Volume is X times higher than average
(dataframe['volume_ratio'] > self.volume_multiplier.value) &
# Amihud illiquidity ratio is higher, indicating higher volatility
(dataframe['amihud_ratio'] > self.amihud_threshold.value) &
# Ensure there is enough trading volume
(dataframe['volume_shares'] > 10_0000) &
# Price has increased
(dataframe['price_pct'] > 0)
),
'enter_long'
] = 1
dataframe.loc[
(
# Volume is X times higher than average
(dataframe['volume_ratio'] > self.volume_multiplier.value) &
# Amihud illiquidity ratio is higher, indicating higher volatility
(dataframe['amihud_ratio'] > self.amihud_threshold.value) &
# Ensure there is enough trading volume
(dataframe['volume_shares'] > 10_0000) &
# Price has decreased
(dataframe['price_pct'] < 0)
),
'enter_short'
] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""Exit signals when Amihud illiquidity ratio normalizes"""
# Exit long positions when Amihud ratio decreases (liquidity improves)
dataframe.loc[
(
# Amihud ratio decreases, liquidity improves
(dataframe['amihud_ratio'] < self.amihud_threshold.value/2)
),
'exit_long'
] = 1
# Exit short positions when Amihud ratio decreases (liquidity improves)
dataframe.loc[
(
# Amihud ratio decreases, liquidity improves
(dataframe['amihud_ratio'] < self.amihud_threshold.value/2)
),
'exit_short'
] = 1
return dataframe