max-trades : 3
Timeframe
1h
Direction
Long Only
Stoploss
-28.9%
Trailing Stop
Yes
ROI
0m: 28.3%, 132m: 16.0%, 548m: 7.1%, 961m: 0.0%
Interface Version
3
Startup Candles
N/A
Indicators
3
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 libs ---
import numpy as np
import pandas as pd
from pandas import DataFrame
from datetime import datetime
from typing import Optional, Union
from freqtrade.strategy import (BooleanParameter, CategoricalParameter, DecimalParameter,
IntParameter, IStrategy, merge_informative_pair)
# --------------------------------
# Add your lib to import here
import talib.abstract as ta
import pandas_ta as pta
from technical import qtpylib
class picasso_slope_is_dope_adx_1h_2Lev_dec15_np_Jan20(IStrategy):
'''
max-trades : 3
freqtrade backtesting --strategy picasso_slope_is_dope_adx_1h_2Lev_dec15_np_Jan20 -i 1h --export trades --breakdown month --timerange 20211101-20221208
freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --spaces all --strategy picasso_slope_is_dope_adx_1h_2Lev_dec15_np_Jan20 -e 155 --ignore-missing-spaces -i 1h --timerange 20220101-20221208 --random-state 10102
=========================================================== ENTER TAG STATS ===========================================================
| TAG | Entries | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% |
|-------+-----------+----------------+----------------+-------------------+----------------+----------------+-------------------------|
| TOTAL | 3814 | 0.85 | 3238.63 | 4845.917 | 484.59 | 2:35:00 | 2752 0 1062 72.2 |
======================================================= EXIT REASON STATS ========================================================
| Exit Reason | Exits | Win Draws Loss Win% | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % |
|--------------------+---------+--------------------------+----------------+----------------+-------------------+----------------|
| trailing_stop_loss | 2828 | 2686 0 142 95.0 | 2.75 | 7785.19 | 11631.5 | 2595.06 |
| exit_signal | 904 | 10 0 894 1.1 | -6.05 | -5472.23 | -8174.27 | -1824.08 |
| roi | 69 | 55 0 14 79.7 | 17.63 | 1216.64 | 1821.33 | 405.55 |
| stop_loss | 10 | 0 0 10 0 | -28.95 | -289.5 | -430.463 | -96.5 |
| force_exit | 3 | 1 0 2 33.3 | -0.49 | -1.48 | -2.212 | -0.49 |
======================================================== LEFT OPEN TRADES REPORT =========================================================
| Pair | Entries | Avg Profit % | Cum Profit % | Tot Profit USDT | Tot Profit % | Avg Duration | Win Draw Loss Win% |
|----------+-----------+----------------+----------------+-------------------+----------------+----------------+-------------------------|
| ZEN/USDT | 1 | 0.42 | 0.42 | 0.628 | 0.06 | 7:00:00 | 1 0 0 100 |
| ZEC/USDT | 1 | -0.22 | -0.22 | -0.326 | -0.03 | 6:00:00 | 0 0 1 0 |
| AR/USDT | 1 | -1.68 | -1.68 | -2.513 | -0.25 | 1:00:00 | 0 0 1 0 |
| TOTAL | 3 | -0.49 | -1.48 | -2.212 | -0.22 | 4:40:00 | 1 0 2 33.3 |
======================= MONTH BREAKDOWN ========================
| Month | Tot Profit USDT | Wins | Draws | Losses |
|------------+-------------------+--------+---------+----------|
| 31/01/2022 | 518.64 | 280 | 0 | 87 |
| 28/02/2022 | 253.151 | 216 | 0 | 90 |
| 31/03/2022 | 781.56 | 352 | 0 | 107 |
| 30/04/2022 | 354.388 | 238 | 0 | 77 |
| 31/05/2022 | 1166.55 | 292 | 0 | 67 |
| 30/06/2022 | 209.446 | 189 | 0 | 58 |
| 31/07/2022 | 417.505 | 325 | 0 | 119 |
| 31/08/2022 | 321.697 | 220 | 0 | 101 |
| 30/09/2022 | -30.796 | 157 | 0 | 89 |
| 31/10/2022 | 163.703 | 214 | 0 | 132 |
| 30/11/2022 | 567.286 | 212 | 0 | 84 |
| 31/12/2022 | 122.791 | 57 | 0 | 51 |
================== SUMMARY METRICS ==================
| Metric | Value |
|-----------------------------+---------------------|
| Backtesting from | 2022-01-01 00:00:00 |
| Backtesting to | 2022-12-08 00:00:00 |
| Max open trades | 3 |
| | |
| Total/Daily Avg Trades | 3814 / 11.18 |
| Starting balance | 1000 USDT |
| Final balance | 5845.917 USDT |
| Absolute profit | 4845.917 USDT |
| Total profit % | 484.59% |
| CAGR % | 561.95% |
| Profit factor | 1.53 |
| Trades per day | 11.18 |
| Avg. daily profit % | 1.42% |
| Avg. stake amount | 149.366 USDT |
| Total trade volume | 569682.426 USDT |
| | |
| Long / Short | 2397 / 1417 |
| Total profit Long % | 348.13% |
| Total profit Short % | 136.47% |
| Absolute profit Long | 3481.267 USDT |
| Absolute profit Short | 1364.65 USDT |
| | |
| Best Pair | GMT/USDT 226.73% |
| Worst Pair | BAL/USDT -45.58% |
| Best trade | CELO/USDT 29.82% |
| Worst trade | AAVE/USDT -29.03% |
| Best day | 231.141 USDT |
| Worst day | -71.979 USDT |
| Days win/draw/lose | 187 / 54 / 95 |
| Avg. Duration Winners | 1:31:00 |
| Avg. Duration Loser | 5:21:00 |
| Rejected Entry signals | 361560 |
| Entry/Exit Timeouts | 0 / 508 |
| | |
| Min balance | 953.364 USDT |
| Max balance | 5862.83 USDT |
| Max % of account underwater | 6.01% |
| Absolute Drawdown (Account) | 3.51% |
| Absolute Drawdown | 180.58 USDT |
| Drawdown high | 4143.184 USDT |
| Drawdown low | 3962.604 USDT |
| Drawdown Start | 2022-09-10 08:00:00 |
| Drawdown End | 2022-10-02 00:00:00 |
| Market change | -76.77% |
=====================================================
2022-12-14 06:18:09,580 - NostalgiaForInfinityX_dec13_15m - INFO - pandas_ta successfully imported
2022-12-14 06:18:09,686 - freqtrade.optimize.hyperopt_tools - INFO - Dumping parameters to /freqtrade/user_data/strategies/slope_is_dope_adx_1h_2Lev_dec14.json
Epoch details:
139/155: 3814 trades. 2752/0/1062 Wins/Draws/Losses. Avg profit 0.85%. Median profit 2.26%. Total profit 4845.91739859 USDT ( 484.59%). Avg duration 2:35:00 min. Objective: -30.40069
# Buy hyperspace params:
buy_params = {
"adx_long": 39,
"adx_short": 20,
"close_market_shift_long": 6,
"close_market_shift_short": 9,
"entryMA_tp": 8,
"fastMA_tp": 16,
"marketMA_tp": 97,
"rsi_tp": 10,
"slowMA_tp": 57,
"leverage_num": 2, # value loaded from strategy
}
# Sell hyperspace params:
sell_params = {
"last_lowest_rolling_long": 9,
"last_lowest_rolling_short": 9,
}
# Protection hyperspace params:
protection_params = {
"max_allowed_drawdown": 0.45,
"max_drawdown_lookback": 102,
"max_drawdown_stop_duration": 53,
"max_drawdown_trade_limit": 14,
"stoploss_guard_lookback": 157,
"stoploss_guard_stop_duration": 191,
"stoploss_guard_trade_limit": 18,
}
# ROI table:
minimal_roi = {
"0": 0.283,
"132": 0.16,
"548": 0.071,
"961": 0
}
# Stoploss:
stoploss = -0.289
# Trailing stop:
trailing_stop = True
trailing_stop_positive = 0.01
trailing_stop_positive_offset = 0.021
trailing_only_offset_is_reached = True
'''
INTERFACE_VERSION = 3
# Optimal timeframe for the strategy.
timeframe = '1h'
# Can this strategy go short?
can_short: bool = True
minimal_roi = {
"0": 0.283,
"132": 0.16,
"548": 0.071,
"961": 0
}
stoploss = -0.289
# Trailing stop:
trailing_stop = True
trailing_stop_positive = 0.01
trailing_stop_positive_offset = 0.021
trailing_only_offset_is_reached = True
'''
'''
#leverage here
leverage_optimize = False
leverage_num = IntParameter(low=1, high=5, default=2, space='buy', optimize=leverage_optimize)
# 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
# Strategy parameters
# buy_rsi = IntParameter(10, 40, default=30, space="buy")
# sell_rsi = IntParameter(60, 90, default=70, space="sell")
close_market_shift_long = IntParameter(5,15,default=6,space="buy")
close_market_shift_short = IntParameter(5,15,default=9,space="buy")
entryMA_tp = IntParameter(1,10, default=8, space="buy")
fastMA_tp = IntParameter(10,30, default=16, space="buy")
marketMA_tp = IntParameter(95,220, default=97, space="buy")
rsi_tp = IntParameter(5,20, default=10, space="buy")
slowMA_tp = IntParameter(30,60, default=57, space="buy")
adx_long = IntParameter(15,50, default=39, space="buy")
adx_short = IntParameter(15,50, default=20, space="buy")
# rsi_value_long = IntParameter(30,80, default=55, space="buy")
# rsi_value_short = IntParameter(30,80, default=55, space="buy")
last_lowest_rolling_long = IntParameter(5,20,default=9, space="sell")
last_lowest_rolling_short = IntParameter(5,20,default=9, space="sell")
# # protection
# protect_optimize = True
# # cooldown_lookback = IntParameter(1, 240, default=6, space="protection", optimize=protect_optimize)
# max_drawdown_lookback = IntParameter(1, 288, default=8, space="protection", optimize=protect_optimize)
# max_drawdown_trade_limit = IntParameter(1, 20, default=1, space="protection", optimize=protect_optimize)
# max_drawdown_stop_duration = IntParameter(1, 288, default=8, space="protection", optimize=protect_optimize)
# max_allowed_drawdown = DecimalParameter(0.10, 0.50, default=0.12, decimals=2, space="protection",
# optimize=protect_optimize)
# stoploss_guard_lookback = IntParameter(1, 288, default=10, space="protection", optimize=protect_optimize)
# stoploss_guard_trade_limit = IntParameter(1, 20, default=1, space="protection", optimize=protect_optimize)
# stoploss_guard_stop_duration = IntParameter(1, 288, default=8, space="protection", optimize=protect_optimize)
# @property
# def protections(self):
# return [
# # {
# # "method": "CooldownPeriod",
# # "stop_duration_candles": self.cooldown_lookback.value
# # },
# {
# "method": "MaxDrawdown",
# "lookback_period_candles": self.max_drawdown_lookback.value,
# "trade_limit": self.max_drawdown_trade_limit.value,
# "stop_duration_candles": self.max_drawdown_stop_duration.value,
# "max_allowed_drawdown": self.max_allowed_drawdown.value
# },
# {
# "method": "StoplossGuard",
# "lookback_period_candles": self.stoploss_guard_lookback.value,
# "trade_limit": self.stoploss_guard_trade_limit.value,
# "stop_duration_candles": self.stoploss_guard_stop_duration.value,
# "only_per_pair": False
# }
# ]
# Optional order type mapping.
order_types = {
'entry': 'limit',
'exit': 'limit',
'stoploss': 'market',
'stoploss_on_exchange': False
}
# Optional order time in force.
order_time_in_force = {
'entry': 'GTC',
'exit': 'GTC'
}
@property
def plot_config(self):
return {
# Main plot indicators (Moving averages, ...)
"main_plot": {
# Configuration for main plot indicators.
"fastMA": {"color": "red"},
"slowMA": {"color": "blue"},
},
"subplots": {
# Additional subplots
"rsi": {"rsi": {"color": "blue"}},
"fast_slope": {"fast_slope": {"color": "red"}, "slow_slope": {"color": "blue"}},
},
}
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.
:param dataframe: Dataframe with data from the exchange
:param metadata: Additional information, like the currently traded pair
:return: a Dataframe with all mandatory indicators for the strategies
"""
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=self.rsi_tp.value)
dataframe['marketMA'] = ta.SMA(dataframe, timeperiod=self.marketMA_tp.value)
dataframe['fastMA'] = ta.SMA(dataframe, timeperiod=self.fastMA_tp.value)
dataframe['slowMA'] = ta.SMA(dataframe, timeperiod=self.slowMA_tp.value)
dataframe['entryMA'] = ta.SMA(dataframe, timeperiod=self.slowMA_tp.value)
dataframe['adx'] = ta.ADX(dataframe)
# Calculate slope of slowMA
# See: https://www.wikihow.com/Find-the-Slope-of-a-Line
dataframe['sy1'] = dataframe['slowMA'].shift(+11)
dataframe['sy2'] = dataframe['slowMA'].shift(+1)
sx1 = 1
sx2 = 11
dataframe['sy'] = dataframe['sy2'] - dataframe['sy1']
dataframe['sx'] = sx2 - sx1
dataframe['slow_slope'] = dataframe['sy']/dataframe['sx']
dataframe['fy1'] = dataframe['fastMA'].shift(+11)
dataframe['fy2'] = dataframe['fastMA'].shift(+1)
fx1 = 1
fx2 = 11
dataframe['fy'] = dataframe['fy2'] - dataframe['fy1']
dataframe['fx'] = fx2 - fx1
dataframe['fast_slope'] = dataframe['fy']/dataframe['fx']
# print(dataframe[['date','close', 'slow_slope','fast_slope']].tail(50))
# ==== Trailing custom stoploss indicator ====
dataframe['last_lowest_long'] = dataframe['low'].rolling(self.last_lowest_rolling_long.value).min().shift(1)
dataframe['last_lowest_short'] = dataframe['low'].rolling(self.last_lowest_rolling_short.value).min().shift(1)
return dataframe
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Based on TA indicators, populates the entry signal for the given dataframe
:param dataframe: DataFrame
:param metadata: Additional information, like the currently traded pair
:return: DataFrame with entry columns populated
"""
dataframe.loc[
(
(
(dataframe['adx'] > self.adx_long.value) &
(dataframe['close'] > dataframe['marketMA']) &
# Only trade when the fast slope is above 0
(dataframe['fast_slope'] > 0) &
# Only trade when the slow slope is above 0
(dataframe['slow_slope'] > 0) &
# Only buy when the close price is higher than the 3day average of ten periods ago
# (dataframe['close'] > dataframe['entryMA'].shift(+11)) &
# Or only buy when the close price is higher than the close price of 3 days ago (this is a choice)
(dataframe['close'] > dataframe['close'].shift(self.close_market_shift_long.value)) &
# Only enter trades when the RSI is higher than 55
(dataframe['rsi'] > 55) &
# Only trade when the fast MA is above the slow MA
(dataframe['fastMA'] > dataframe['slowMA'])
# Or trade when the fase MA crosses above the slow MA (This is a choice...)
# (qtpylib.crossed_above(dataframe['fastMA'], dataframe['slowMA']))
)
),
'enter_long'] = 1
# Uncomment to use shorts (Only used in futures/margin mode. Check the documentation for more info)
dataframe.loc[
(
(
(dataframe['adx'] > self.adx_short.value) &
(dataframe['close'] < dataframe['marketMA']) &
# Only trade when the fast slope is above 0
(dataframe['fast_slope'] < 0) &
# Only trade when the slow slope is above 0
(dataframe['slow_slope'] < 0) &
# Only buy when the close price is higher than the 3day average of ten periods ago
# (dataframe['close'] > dataframe['entryMA'].shift(+11)) &
# Or only buy when the close price is higher than the close price of 3 days ago (this is a choice)
(dataframe['close'] < dataframe['close'].shift(self.close_market_shift_short.value)) &
# Only enter trades when the RSI is higher than 55
(dataframe['rsi'] < 55) &
# Only trade when the fast MA is above the slow MA
(dataframe['fastMA'] < dataframe['slowMA'])
# Or trade when the fase MA crosses above the slow MA (This is a choice...)
# (qtpylib.crossed_above(dataframe['fastMA'], dataframe['slowMA']))
)
),
'enter_short'] = 1
return dataframe
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Based on TA indicators, populates the exit signal for the given dataframe
:param dataframe: DataFrame
:param metadata: Additional information, like the currently traded pair
:return: DataFrame with exit columns populated
"""
dataframe.loc[
(
# Close or do not trade when fastMA is below slowMA
(dataframe['fastMA'] < dataframe['slowMA'])
# Or close position when the close price gets below the last lowest candle price configured
# (AKA candle based (Trailing) stoploss)
| (dataframe['close'] < dataframe['last_lowest_long'])
# | (dataframe['close'] < dataframe['fastMA'])
),
'exit_long'] = 1
# Uncomment to use shorts (Only used in futures/margin mode. Check the documentation for more info)
dataframe.loc[
(
# Close or do not trade when fastMA is below slowMA
(dataframe['fastMA'] > dataframe['slowMA'])
# Or close position when the close price gets below the last lowest candle price configured
# (AKA candle based (Trailing) stoploss)
| (dataframe['close'] > dataframe['last_lowest_short'])
# | (dataframe['close'] < dataframe['fastMA'])
),
'exit_short'] = 1
return dataframe
def leverage(self, pair: str, current_time: datetime, current_rate: float,
proposed_leverage: float, max_leverage: float, side: str,
**kwargs) -> float:
return self.leverage_num.value