Whooping 3202%+ profit with Famous UTBot Alerts from TradingView using Python on Freqtrade

5th Edition of the famous Algorithmic Trading Strategies articles’ on building PROFITABLE TRADING SYSTEM. (New Strategy)

1st Edition: “Unlock 4450% Profit with Algorithm Trading on Cryptocurrency: A Freqtrade Case Study” — Link

2nd Edition: “2509% Profit Unlocked: A Case Study on Algorithmic Trading with Freqtrade” — LINK

3rd Edition: “Unleashing the Power: Unveiling a 10,000%+ Profit Surge in 2.5 Years with Advanced Cryptocurrency Algorithmic Trading Using Freqtrade” — LINK

4th Edition: “Unraveling the Cryptocurrency Market: How Pivot Points and Price Action Led to 6204%+ Profit in Backtesting using Freqtrade ” — Link

UTBot Alerts: From Pine Script to Python

UTBot Alerts by @QuantNomad is a powerful trading strategy originally written in Pine Script for TradingView. It has been converted into a reusable Python function that can be applied to various asset classes, including cryptocurrencies, stocks, commodities, and more. In this article, we’ll break down the Python implementation of UTBot Alerts, explain each line of code, and showcase how it can be customized for different assets and combined with technical indicators like RSI and ADX.

Introduction to UTBot Alerts

The UTBot Alerts strategy aims to identify potential buy and sell signals based on price movements and trend conditions. It utilizes the Average True Range (ATR) indicator and Exponential Moving Average (EMA) to create trailing stop levels and determine trend directions. By understanding the logic behind UTBot Alerts, traders can leverage this strategy to enhance their trading decisions.

UTBot Alerts with EMA and Vol for filtering of entry and exit trades
UTBot Alerts with EMA and Vol for filtering of entry and exit trades

Python Implementation of UTBot Alerts

Let’s dive into the Python code that implements the UTBot Alerts strategy. The function is named UTBot_Alerts and takes several parameters: dataframe, key_value, atr_period, and ema_period.

import numpy as np
import pandas as pd
import talib.abstract as ta

def UTBot_Alerts(dataframe, key_value=1, atr_period=3, ema_period=200):
# Calculate ATR and xATRTrailingStop
xATR = np.array(ta.ATR(dataframe['high'], dataframe['low'], dataframe['close'], timeperiod=atr_period))
nLoss = key_value * xATR
src = dataframe['close']

# Initialize arrays
xATRTrailingStop = np.zeros(len(dataframe))
xATRTrailingStop[0] = src[0] - nLoss[0]

# Calculate xATRTrailingStop using vectorized operations
mask_1 = (src > np.roll(xATRTrailingStop, 1)) & (np.roll(src, 1) > np.roll(xATRTrailingStop, 1))
mask_2 = (src < np.roll(xATRTrailingStop, 1)) & (np.roll(src, 1) < np.roll(xATRTrailingStop, 1))
mask_3 = src > np.roll(xATRTrailingStop, 1)

# ... (Continued in the next section)

In the above snippet, we calculate the ATR and use it to compute the trailing stop levels, referred to as xATRTrailingStop. We also initialize arrays and perform vectorized operations to calculate the trailing stop values efficiently.

Determining Buy and Sell Signals

Continuing from the previous snippet, we’ll focus on determining the buy and sell signals using UTBot Alerts logic.

    # ... (Previous code)
xATRTrailingStop = np.where(mask_1, np.maximum(np.roll(xATRTrailingStop, 1), src - nLoss), xATRTrailingStop)
xATRTrailingStop = np.where(mask_2, np.minimum(np.roll(xATRTrailingStop, 1), src + nLoss), xATRTrailingStop)
xATRTrailingStop = np.where(mask_3, src - nLoss, xATRTrailingStop)

mask_buy = (np.roll(src, 1) < xATRTrailingStop) & (src > np.roll(xATRTrailingStop, 1))
mask_sell = (np.roll(src, 1) > xATRTrailingStop) & (src < np.roll(xATRTrailingStop, 1))

pos = np.zeros(len(dataframe))
pos = np.where(mask_buy, 1, pos)
pos = np.where(mask_sell, -1, pos)
pos[~((pos == 1) | (pos == -1))] = 0

ema = np.array(ta.EMA(dataframe['close'], timeperiod=ema_period))

buy_condition_utbot = (xATRTrailingStop > ema) & (pos > 0) & (src > ema)
sell_condition_utbot = (xATRTrailingStop < ema) & (pos < 0) & (src < ema)

trend = np.where(buy_condition_utbot, 1, np.where(sell_condition_utbot, -1, 0))

# ... (Continued in the next section)

In this section, we calculate the buy and sell conditions based on UTBot Alerts logic and additional indicators such as the Exponential Moving Average (ema). The resulting trend array holds values of 1 (buy), -1 (sell), or 0 (neutral).

Applying UTBot Alerts and Customization

Now that we have the buy and sell signals, we’ll finalize the UTBot Alerts function and discuss how to customize it for different assets and combine it with other indicators.

    # ... (Previous code)
trend = np.array(trend)

dataframe['trend'] = trend
return dataframe

The function calculates trend values and assigns it to the 'trend' column in the input dataframe. By returning the modified dataframe, the function can be integrated seamlessly into trading platforms like Freqtrade.

Customization and Combination with Indicators

To customize UTBot Alerts for different assets or combine it with other indicators, you can adjust the input parameters and conditions. For example, you can modify the key_value, atr_period, and ema_period to better suit the volatility and trends of specific assets. Additionally, you can integrate indicators like Relative Strength Index (RSI) or Average Directional Index (ADX) to enhance the strategy's accuracy.

# Example of combining UTBot Alerts with RSI and ADX
def custom_strategy(dataframe):
dataframe = UTBot_Alerts(dataframe, key_value=2, atr_period=7, ema_period=100)

# Calculate RSI and ADX
rsi = ta.RSI(dataframe['close'])
adx = ta.ADX(dataframe['high'], dataframe['low'], dataframe['close'])

# Define conditions based on UTBot Alerts and additional indicators
# ... (your custom conditions here)

return dataframe

Freqtrade Introduction and Setup Explanation:

We have covered lot of introductory topics in the 1st edition which covers all key basic concepts which I mentioned below, if you are new to “trading”, “algorithm trading”, “freqtrade” platform or “futures trading” concepts, I suggest you to open my previous articles and go through the same.

I’m here to talk about my new strategy which I was working for past few months

Introductory Topics already covered in 1st edition: (Link)

Introduction to algorithmic trading and its benefits

What algorithmic trading is and how it can be used in the context of crypto futures trading

Some of the benefits of using algorithmic trading for crypto futures include:

Introduction to the freqtrade platform

Here are some key features of the freqtrade platform:

What is Short Trading and Long Trading in Futures Market

How Leverage works and Factors to consider while using Leverage during Trades

There are a few factors that traders should consider when deciding whether and how to use leverage:

  1. Risk appetite: Traders with a higher risk appetite may be more comfortable using larger amounts of leverage, while those who are more risk-averse may prefer to use less leverage or none at all.
  2. Trading strategy: Different trading strategies may be more or less suitable for leveraging, depending on the level of risk involved and the trader’s goals.
  3. Market conditions: The level of leverage that is appropriate for a trade may also depend on the current market conditions, such as the level of volatility or the overall trend of the market.
  4. Trading capital: Traders should also consider their available capital when deciding how much leverage to use, as they will need to have sufficient margin to cover any potential losses.

In general, it’s important for traders to carefully evaluate the potential risks and rewards of using leverage and to use it responsibly, as it can significantly impact the outcome of a trade.

Setting up freqtrade for crypto futures trading

  1. There are lot of tutorials about how to connect Freqtrade using docker in a containerized environment. You can refer to any of the many Youtube tutorials on the same.
  2. Here, Our main agenda is to show case the backtest and forward test results of the algorithm trading on freqtrade, so, I will focus on that more.
  3. If there is a lot of demand and requests in comments for a tutorial on how to setup freqtrade and run your own strategies if requested, I will add that in forth coming article. Thank you

Resources:

https://youtu.be/ASq2aeUHen8

or

https://youtu.be/PrPGKHCx5qY

or

https://youtu.be/H2OkrvSojOI

I’m giving reference only.

UTBot_Alerts Initialization:


def optimize_trend_alert(dataframe, key_value=1, atr_period=3, ema_period=200):

# Calculate ATR and xATRTrailingStop
xATR = np.array(ta.ATR(dataframe['high'], dataframe['low'], dataframe['close'], timeperiod=atr_period))
nLoss = key_value * xATR
src = dataframe['close']

# Initialize arrays
xATRTrailingStop = np.zeros(len(dataframe))
xATRTrailingStop[0] = src[0] - nLoss[0]

# Calculate xATRTrailingStop using vectorized operations
mask_1 = (src > np.roll(xATRTrailingStop, 1)) & (np.roll(src, 1) > np.roll(xATRTrailingStop, 1))
mask_2 = (src < np.roll(xATRTrailingStop, 1)) & (np.roll(src, 1) < np.roll(xATRTrailingStop, 1))
mask_3 = src > np.roll(xATRTrailingStop, 1)

xATRTrailingStop = np.where(mask_1, np.maximum(np.roll(xATRTrailingStop, 1), src - nLoss), xATRTrailingStop)
xATRTrailingStop = np.where(mask_2, np.minimum(np.roll(xATRTrailingStop, 1), src + nLoss), xATRTrailingStop)
xATRTrailingStop = np.where(mask_3, src - nLoss, xATRTrailingStop)

# Calculate pos using vectorized operations
mask_buy = (np.roll(src, 1) < xATRTrailingStop) & (src > np.roll(xATRTrailingStop, 1))
mask_sell = (np.roll(src, 1) > xATRTrailingStop) & (src < np.roll(xATRTrailingStop, 1))

pos = np.zeros(len(dataframe))
pos = np.where(mask_buy, 1, pos)
pos = np.where(mask_sell, -1, pos)
pos[~((pos == 1) | (pos == -1))] = 0

ema = np.array(ta.EMA(dataframe['close'], timeperiod=ema_period))

buy_condition_utbot = (xATRTrailingStop > ema) & (pos > 0) & (src > ema)
sell_condition_utbot = (xATRTrailingStop < ema) & (pos < 0) & (src < ema)

trend = np.where(buy_condition_utbot, 1, np.where(sell_condition_utbot, -1, 0))

trend = np.array(trend)

dataframe['trend'] = trend
return dataframe

we have initialized above UTBot_Alerts function and below under populate_indicators() we have intilized optimized_trend_alert() (which is UTBot_Alerts function) along with ‘adx’, ‘ema’, ‘volume’ indicators

def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
if not self.dp:
# Don't do anything if DataProvider is not available.
return dataframe


L_optimize_trend_alert = optimize_trend_alert(dataframe=dataframe, key_value= self.key_value_l.value, atr_period= self.atr_period_l.value, ema_period=self.ema_period_l.value)
dataframe['trend_l'] = L_optimize_trend_alert['trend']

S_optimize_trend_alert = optimize_trend_alert(dataframe=dataframe, key_value= self.key_value_s.value, atr_period= self.atr_period_s.value, ema_period=self.ema_period_s.value)
dataframe['trend_s'] = S_optimize_trend_alert['trend']

# ADX
dataframe['adx'] = ta.ADX(dataframe)

# RSI
# dataframe['rsi'] = ta.RSI(dataframe)

# EMA
dataframe['ema_l'] = ta.EMA(dataframe['close'], timeperiod=self.ema_period_l_exit.value)
dataframe['ema_s'] = ta.EMA(dataframe['close'], timeperiod=self.ema_period_s_exit.value)


# Volume Weighted
dataframe['volume_mean'] = dataframe['volume'].rolling(self.volume_check.value).mean().shift(1)
dataframe['volume_mean_exit'] = dataframe['volume'].rolling(self.volume_check_exit.value).mean().shift(1)

dataframe['volume_mean_s'] = dataframe['volume'].rolling(self.volume_check_s.value).mean().shift(1)
dataframe['volume_mean_exit_s'] = dataframe['volume'].rolling(self.volume_check_exit_s.value).mean().shift(1)




return dataframe

Taking long and Short Positions Entry and Exit:

def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:

dataframe.loc[
(
(dataframe['adx'] > self.adx_long_min.value) & # trend strength confirmation
(dataframe['adx'] < self.adx_long_max.value) & # trend strength confirmation
(dataframe['trend_l'] > 0) &
(dataframe['volume'] > dataframe['volume_mean']) &
(dataframe['volume'] > 0)

),
'enter_long'] = 1

dataframe.loc[
(
(dataframe['adx'] > self.adx_short_min.value) & # trend strength confirmation
(dataframe['adx'] < self.adx_short_max.value) & # trend strength confirmation
(dataframe['trend_s'] < 0) &
(dataframe['volume'] > dataframe['volume_mean_s']) # volume weighted indicator
),
'enter_short'] = 1

return dataframe

Populate_entry_trend() helps in taking long and short positions accordingly with certain said rules as displayed above.


def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:

conditions_long = []
conditions_short = []
dataframe.loc[:, 'exit_tag'] = ''

exit_long = (
# (dataframe['close'] < dataframe['low'].shift(self.sell_shift.value)) &
(dataframe['close'] < dataframe['ema_l']) &
(dataframe['volume'] > dataframe['volume_mean_exit'])
)

exit_short = (
# (dataframe['close'] > dataframe['high'].shift(self.sell_shift_short.value)) &
(dataframe['close'] > dataframe['ema_s']) &
(dataframe['volume'] > dataframe['volume_mean_exit_s'])
)


conditions_short.append(exit_short)
dataframe.loc[exit_short, 'exit_tag'] += 'exit_short'


conditions_long.append(exit_long)
dataframe.loc[exit_long, 'exit_tag'] += 'exit_long'


if conditions_long:
dataframe.loc[
reduce(lambda x, y: x | y, conditions_long),
'exit_long'] = 1

if conditions_short:
dataframe.loc[
reduce(lambda x, y: x | y, conditions_short),
'exit_short'] = 1

return dataframe

populate_exit_trend() helps in taking stoploss or take profit for both long and short positions, can mention when to exit, apart from this we also setup stoploss, trailing_stoploss and roi too in freqtrade which helps in exiting the trade as per rules set by us.

You can find the whole code here https://patreon.com/pppicasso

Backtesting a trading strategy with freqtrade

Backtesting is the process of simulating trades using historical market data to evaluate the performance of a trading strategy. Freqtrade includes a backtesting feature that allows users to backtest their trading strategies by specifying a range of dates and a set of market data to use in the simulation.

To backtest a trading strategy with freqtrade, you will need to follow these steps:

  1. Create a configuration file: Freqtrade requires a configuration file to specify the details of your crypto futures exchange account and your desired trading parameters. To create a configuration file, copy the sample configuration file provided in the freqtrade repository to a new file called “config.json”. Then, edit the file to specify your exchange credentials and desired trading parameters.
  2. Prepare your market data: Freqtrade requires a set of market data to use in the backtest. This data should be in the form of a CSV file with columns for the date, open price, high price, low price, close price, and volume of the asset being traded. You can obtain this data from a variety of sources, such as a cryptocurrency exchange or a market data provider.
  3. Run the backtest: Once you have your configuration file and market data ready, you can run the backtest by executing the following command:
freqtrade backtesting --config config.json --strategy MyStrategy --datadir data/

Replace “MyStrategy” with the name of your strategy function and “data/” with the directory where your market data is stored. This will run the backtest using the settings specified in your configuration file and the market data provided.

  1. Review the results: Once the backtest is complete, freqtrade will generate a report with information on the performance of your strategy. This report will include metrics such as the profit/loss, the number of trades executed, and the win/loss ratio of the strategy. You can use this information to evaluate the performance of your strategy and make any necessary adjustments.
Monthly Results of UTBot Alerts Strategy done using Python on Freqtrade Platform
Monthly Results of UTBot Alerts Strategy done using Python on Freqtrade Platform

freqtrade backtesting profit for UTBot Alerts Crypto Algorithmic Strategy 2023

freqtrade backtesting profit for UTBot Alerts Crypto Algorithmic Strategy 2023
freqtrade backtesting profit for UTBot Alerts Crypto Algorithmic Strategy 2023

freqtrade backtesting summary profit for UTBot Alerts Crypto Algorithmic Strategy 2023

freqtrade backtesting summary profit for UTBot Alerts Crypto Algorithmic Strategy 2023
freqtrade backtesting summary profit for UTBot Alerts Crypto Algorithmic Strategy 2023

You can find the whole code here https://patreon.com/pppicasso

By investing 1000 USDT, (1 USD approximately equal to 1 USDT with 1–2% variance)

for a period of 955 days (from 2021–01–01 07:30:00 up to 2023–08–15 00:00:00)

with maximum open trades at any given point of time being 4

maximum stake in each trade entry being around 200 USDT,

has given a Profit of 3202% Profit return on investment (ROI).

The Absolute Draw-down mentioned from results is at — 14.29%

Daily Win to Lose Ratio is at 634 days of WIN, 323 Days loss and 0 Days of Draw (Open trades which haven’t closed yet)

Average Daily profit is at3.35% per day

Daily Average Trades is 19.55 approximate

Market Returns Have been (if you buy and hold Bitcoin (BTCUSDT) for the above mentioned period the returns are mentioned here, instead of trading) — 38.39%

Time Frame used is 15m

Key Findings from Results:

  1. Profit and ROI: The trading strategy yielded a significant profit of 3202%+ return on investment (ROI) over a span of 955 days.
  2. Drawdown: The absolute drawdown reached a maximum of -14.29%, indicating relatively low risk exposure.
  3. Win-Lose Ratio: The daily win-lose ratio showed 634 days of winning trades, 323 days of losing trades, and 0days with open (draw) trades.
  4. Average Daily Profit: The average daily profit was calculated at 3.35%, suggesting consistent positive returns on most trading days.
  5. Market Returns Comparison: The trading strategy outperformed the market, which had a return of -38.39% over the same period.
  6. Time Frame: The strategy operated on a 15-minute time frame.

Tips for Improving Strategy Performance For Algorithmic Trading:

  1. Optimize Indicators: Fine-tune the parameters of indicators like ATR, EMA, and ADX to find optimal settings for the specific asset and market conditions.
  2. Portfolio Diversification: Consider diversifying the portfolio by incorporating additional assets or using different strategies for various assets to reduce risk.
  3. Risk Management: Adjust position sizing and risk parameters to control exposure and manage drawdowns effectively.
  4. Backtesting: Thoroughly backtest the strategy over different market conditions and time periods to ensure robustness and adaptability.
  5. Hyper-parameter Optimization: Use techniques like grid search or random search to optimize hyper-parameters for better performance.
  6. Market Research: Stay updated with market trends, news, and events that could impact the performance of the trading strategy.
  7. Continuous Learning: Stay informed about new features, updates, and best practices in FreqTrade to make the most of the trading bot.
  8. Regular Evaluation: Periodically review and analyze the strategy’s performance to identify areas for improvement and necessary adjustments.
  9. Risk-Reward Ratio: Adjust the risk-reward ratio for trade entries and exits to optimize potential profits while minimizing losses.
  10. Adaptability: Modify and adapt the strategy as market conditions change to ensure its relevance and effectiveness.

Remember that trading involves inherent risks, and there’s no guaranteed way to avoid losses. Implementing these tips can enhance the strategy’s potential, but careful risk management and continuous monitoring are essential for long-term success.

Please ensure to thoroughly test any modifications to the code on historical data and conduct proper risk assessment before deploying the strategy in a live trading environment.

Conclusion

UTBot Alerts, originally developed in Pine Script for TradingView by @QuantNomad, has been successfully adapted into a Python function. By understanding the logic behind the code, traders can apply this strategy to various asset classes and combine it with other indicators for more accurate trading signals. Remember to thoroughly backtest and validate any trading strategy before implementing it in a live trading environment.

Feel free to enhance and customize the article according to your needs. This article provides an overview of the Python implementation of UTBot Alerts, explains each line of code, and demonstrates its application with different indicators. It also emphasizes the importance of backtesting and customization for successful trading.

It’s important to note that past performance does not guarantee future results, and continuous monitoring and optimization of the algorithm are essential to adapt to changing market conditions. Additionally, it is crucial to exercise proper risk management and conduct thorough testing before deploying the algorithm with real funds.

Thank you, Readers.

I hope you have found this article on Algorithmic strategy to be informative and helpful. As a creator, I am dedicated to providing valuable insights and analysis on cryptocurrency, stock market and other assets management.

If you have enjoyed this article and would like to support my ongoing efforts, I would be honored to have you as a member of my Patreon community. As a member, you will have access to exclusive content, early access to new analysis, and the opportunity to be a part of shaping the direction of my research.

Membership starts at just $10, and you can choose to contribute on a bi-monthly basis. Your support will help me to continue to produce high-quality content and bring you the latest insights on financial analytics.

Patreon https://patreon.com/pppicasso

Regards,

Puranam Pradeep Picasso

Linkedinhttps://www.linkedin.com/in/puranampradeeppicasso/

Patreon https://patreon.com/pppicasso

Facebook https://www.facebook.com/puranam.p.picasso/

Twitterhttps://twitter.com/picasso_999

--

--

Puranam Pradeep Picasso - ImbueDesk Profile

Algorithmic Trader, AI/ML & Crypto Enthusiast, Certified Blockchain Architect, Certified Lean Six SIgma Green Belt, Certified SCRUM Master and Entrepreneur