Timeframe
5m
Direction
Long Only
Stoploss
-90.0%
Trailing Stop
No
ROI
0m: 3.0%, 120m: 2.0%, 480m: 0.2%
Interface Version
N/A
Startup Candles
N/A
Indicators
2
freqtrade/freqtrade-strategies
Strategy 003 author@: Gerald Lonlas github@: https://github.com/freqtrade/freqtrade-strategies
# --- Do not remove these libs ---
from typing import Optional
from freqtrade.strategy import IStrategy
from typing import Dict, List
from functools import reduce
from pandas import DataFrame
import numpy as np
from datetime import datetime, timedelta, timezone
from freqtrade.persistence import Trade
# --------------------------------
import talib.abstract as ta
import freqtrade.vendor.qtpylib.indicators as qtpylib
from technical.util import (resample_to_interval, resampled_merge)
class QFL_3C_PROD01(IStrategy):
"""
Strategy 3C QFL
"""
# Minimal ROI designed for the strategy.
# This attribute will be overridden if the config file contains "minimal_roi"
minimal_roi = {
# "480": 0.002,
# "120": 0.008,
"120": 0.02,
"0": 0.03
}
# Optimal timeframe for the strategy
# timeframe = '5m'
# trailing stoploss
trailing_stop = False
trailing_stop_positive = 0.02
trailing_stop_positive_offset = 0.03
stoploss = -0.9
# run "populate_indicators" only for new candle
process_only_new_candles = False
# Experimental settings (configuration will overide these if set)
# use_sell_signal = True
sell_profit_only = True
ignore_roi_if_buy_signal = False
# Optional order type mapping
order_types = {
'entry': 'limit',
'exit': 'limit',
'stoploss': 'market',
'stoploss_on_exchange': False
}
position_adjustment_enable = True
max_entry_position_adjustment = 8
current_loss_percent = -0.01 # profit or loss used as mark for new orders 1 = 100%, 0.1 = 10%, 0.01 = 1%
rsi_max_level = 30
max_dca_multiplier = np.sum([pow(2, n) for n in range(1, max_entry_position_adjustment + 1)])
low_perc_mean = 0
def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, proposed_stake: float, min_stake: float, max_stake: float, entry_tag: Optional[str], **kwargs) -> float:
return proposed_stake / self.max_dca_multiplier
def adjust_trade_position(self, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, min_stake: float, max_stake: float, **kwargs):
"""
Custom trade adjustment logic, returning the stake amount that a trade should be increased.
This means extra buy orders with additional fees.
:param trade: trade object.
:param current_time: datetime object, containing the current datetime
:param current_rate: Current buy rate.
:param current_profit: Current profit (as ratio), calculated based on current_rate.
:param min_stake: Minimal stake size allowed by exchange.
:param max_stake: Balance available for trading.
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
:return float: Stake amount to adjust your trade
"""
filled_entries = trade.select_filled_orders(trade.entry_side)
count_of_entries = trade.nr_of_successful_entries
if current_profit > abs(self.current_loss_percent) and trade.nr_of_successful_exits == 0:
# Take half of the profit at +5%
return -(trade.stake_amount / 2)
if current_profit > self.current_loss_percent * (1 + count_of_entries):
return None
# Obtain pair dataframe (just to show how to access it)
dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe)
# # Only buy when not actively falling price.
# only buy if it is actively falling!
# TODO: do some math to find better falling scheme (eg: add candle difference percent)
last_candle = dataframe.iloc[1].squeeze()
previous_candle = dataframe.iloc[2].squeeze()
if last_candle['close'] > previous_candle['close']:
return None
# # Allow up to 3 additional increasingly larger buys (4 in total)
# # Initial buy is 1x
# # If that falls to -5% profit, we buy 1.25x more, average profit should increase to roughly -2.2%
# # If that falls down to -5% again, we buy 1.5x more
# # If that falls once again down to -5%, we buy 1.75x more
# # Total stake for this trade would be 1 + 1.25 + 1.5 + 1.75 = 5.5x of the initial allowed stake.
# # That is why max_dca_multiplier is 5.5
# # Hope you have a deep wallet!
try:
# This returns first order stake size
stake_amount = filled_entries[0].cost
# This then calculates current safety order size
# stake_amount = stake_amount * (1 + (count_of_buys * 0.25))
stake_amount = stake_amount * pow(2, count_of_entries)
return stake_amount
except Exception as exception:
return None
return None
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:
"""
Adds several different TA indicators to the given DataFrame
Performance Note: For the best performance be frugal on the number of indicators
you are using. Let uncomment only the indicator you are using in your strategies
or your hyperopt configuration, otherwise you will waste your memory and CPU usage.
"""
dataframe["vam"] = ta.SMA(dataframe["volume"], 6)
dataframe["base"] = dataframe.shift(3).loc[(dataframe["low"].shift(3) < dataframe["low"].shift(4))
& (dataframe["low"].shift(4) < dataframe["low"].shift(5))
& (dataframe["low"].shift(2) > dataframe["low"].shift(3))
& (dataframe["low"].shift(1) > dataframe["low"].shift(2))
& (dataframe["volume"].shift(3) > dataframe["vam"].shift(3)), ["low"]]
dataframe["base"].ffill(inplace=True)
dataframe['low_perc'] = np.nan
diff_perc = (dataframe['base'] - dataframe['base'].shift(1)) / dataframe['base'].shift(1) * 100
dataframe.loc[diff_perc > 1, 'low_perc'] = diff_perc
dataframe['low_perc'] = dataframe['low_perc'].abs()
# Calcolo della media di "low_perc"
self.low_perc_mean = dataframe['low_perc'].mean()
resampled = resample_to_interval(dataframe, 60)
resampled['rsi'] = ta.RSI(resampled, timeperiod=14)
dataframe = resampled_merge(dataframe, resampled)
return dataframe
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Based on TA indicators, populates the buy signal for the given dataframe
:param dataframe: DataFrame
:return: DataFrame with buy column
"""
# buy if under 1% lower than base break
# dataframe.loc[((dataframe['low'] < (dataframe['base'] - ((dataframe['base'] - dataframe['base'] * self.low_perc_mean / 100)))) & (dataframe['resample_60_rsi'] < self.rsi_max_level)), 'enter_long'] = 1
dataframe.loc[(dataframe['low'] < (dataframe['base'] - dataframe['base'] * self.low_perc_mean / 100)), 'enter_long'] = 1
return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Based on TA indicators, populates the sell signal for the given dataframe
:param dataframe: DataFrame
:return: DataFrame with buy column
"""
dataframe.loc[(), 'exit_long'] = 1
return dataframe