Skip to content

Example how to convert PineScript based algorithmic trading strategy for DeFi

Notifications You must be signed in to change notification settings

tradingstrategy-ai/tradingview-defi-strategy

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

65 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Porting PineScript-based trading strategies to DeFi

This is an example Python project on how to convert TradingView-based PineScript algorithmic trading strategies to TradingStrategy.ai Python format.

Watch the recorded workshop session for this project

Watch the recorded workshop session on YouTube

This example repository was made for Avalanche Summit II workshop. See the example Github repository here.

Benefits of DeFi for algorithmic traders

Running your trading strategy on decentralised exchanges instead of centralised exchanges have several benefits:

Prerequisites

Your skills

To work with this example, you need to have

  • Basic experience in cryptocurrencies
  • Basic experience in trading
  • Experience in TradingView's PineScript
  • Junior level experience in Python

Software

About the example strategy

The example strategy backtest is in bollinger_band_example_defi_strategy.ipynb notebook.

The example strategy is a simple Bollinger band strategy. Whether it makes profit or not is outside the scope of the example. The strategy is not optimised at all and parameters are picked more or less by a gut feeling. Please use this example as learning material and base for your own strategies.

Note: Long only strategies are challenging in a descending or sideways cryptocurrencies market like 2021-2023. Furthermore, this strategy was handpicked for an overly short backtesting period, to better illustrate the features of the backtesting framework.

Technical indicator documentation

Find documentation for technical indicators used in the example

  • Exponential Moving Average (EMA): The Exponential Moving Average is a more responsive moving average compared to the Simple Moving Average (SMA). The weights are determined by alpha which is proportional to it’s length.

  • Relative Strength Index (RSI): The Relative Strength Index is a popular momentum oscillator used to measure the velocity as well as the magnitude of directional price movements.

  • Bollinger Bands (BB): A popular volatility indicator by John Bollinger.

Strategy performance results and algorithm porting notes

Both TradingView and Trading Strategy strategies open positions in a similar fashion, so they are more or less comparable.

Note. Because of the different price feeds and other subtle differences you cannot have the same strategy backtest result on two different markets: Coinbase and Trader Joe.**. If you carefully examine the price chart, RSI and other indicators, you will see the results vary a bit. In such a small backtesting timeframe, this strategy is prone to small fluxuations and is not robust. The goal of this example, however, is not robustness, but easily demonstrable data.

If you examine, some of positions like ~March 17th are opened around the same time, so we do see that the strategy is following the same pattern.

Both strategy implementations make a low number of trades, 10-20, for the backtesting period. This makes it easier to demonstrate the example.

Equity curve

How well the strategy would have historically performed on AVAX-USDC pair on Trader Joe on Avalanche (20 BPS fee).

equity curve trading strategy

How well the strategy would have historically performed on AVAX-USD on Coinbase (no fees).

equity curve coinbase

However, if we switch on 50 BPS taker fee on Coinbase we can see it destroys the strategy performance, going to loss (vs. 20 BPS fee on Trader Joe).

equity curve coinbase with fee

Positions taken

Here is a screenshot of individual won/lost positions in Python strategy. You can see we have few profitable long duration positions, and very short duration unprofitable positions.

positions

Price action and indicators

Here is a screenshot of the price action and technical indicators of the strategy.

price action and positions

Trading summary

Summary statistics are calculated as follow:

Trading period length                     145 days
Return %                                    11.90%
Annualised return %                         29.88%
Cash at start                            $5,000.00
Value at end                             $5,594.84
Trade volume                            $47,387.00
Position win percent                        55.56%
Total positions                                  9
Won positions                                    5
Lost positions                                   4
Stop losses triggered                            4
Stop loss % of all                          44.44%
Stop loss % of lost                        100.00%
Winning stop losses                              0
Winning stop losses percent                  0.00%
Losing stop losses                               4
Losing stop losses percent                 100.00%
Take profits triggered                           0
Take profit % of all                         0.00%
Take profit % of won                         0.00%
Zero profit positions                            0
Positions open at the end                        0
Realised profit and loss                   $594.84
Portfolio unrealised value                   $0.00
Extra returns on lending pool interest       $0.00
Cash left at the end                     $5,594.84
Average winning position profit %            6.72%
Average losing position loss %              -2.57%
Biggest winning position %                  12.12%
Biggest losing position %                   -2.76%
Average duration of winning positions       3 days
Average duration of losing positions        0 days
LP fees paid                                $94.87
LP fees paid % of volume                     0.20%
Average position:                            2.59%
Median position:                             1.65%
Most consecutive wins                            2
Most consecutive losses                          3
Biggest realized risk                       -1.38%
Avg realised risk                           -1.28%
Max pullback of total capital               -4.00%
Max loss risk at opening of position         1.10%

Position timeline

Here are individual positions.

position timeline

Example code

The example strategy is presented as

Strategy core:

rsi_series = rsi(close_prices, length=RSI_LENGTH)

# Calculate Bollinger Bands with a 20-day SMA and 2 standard deviations using pandas_ta
# See documentation here https://tradingstrategy.ai/docs/programming/api/technical-analysis/volatility/help/pandas_ta.volatility.bbands.html#bbands
bollinger_bands = bbands(close_prices, length=MOVING_AVERAGE_LENGTH, std=STDDEV)

# bbands() returns a dictionary of items with different name mangling
bb_upper = bollinger_bands[f"BBU_{MOVING_AVERAGE_LENGTH}_{STDDEV}"]
bb_lower = bollinger_bands[f"BBL_{MOVING_AVERAGE_LENGTH}_{STDDEV}"]
bb_mid = bollinger_bands[f"BBM_{MOVING_AVERAGE_LENGTH}_{STDDEV}"]  # Moving average

if not position_manager.is_any_open():
    # No open positions, decide if BUY in this cycle.
    # We buy if the price on the daily chart closes above the upper Bollinger Band.
    if price_latest > bb_upper.iloc[-1] and rsi_series[-1] >= RSI_THRESHOLD:
        buy_amount = cash * POSITION_SIZE
        trades += position_manager.open_1x_long(
            pair, 
            buy_amount, 
            stop_loss_pct=STOP_LOSS_PCT)

else:
    # We have an open position, decide if SELL in this cycle.
    # We close the position when the price closes below the 20-day moving average.        
    if price_latest < bb_mid.iloc[-1]:
        trades += position_manager.close_all()

Notable differences between Python and PineScript

Some major differences between Python and PineScript:

  • Python is a general-purpose programming language, making a vast number of tutorials, books and courses available for it.
  • Python is open source - making a vast number of software libraries like technical indicators and statistics available for it.
  • TradingView's PineScript is optimised to be used with their service only. It is streamlined, easier to work with, but inflexible.
  • PineScript is fast: backtests complete fast as it is simplified what PineScript can do.
  • Python data is presented as Pandas DataFrame's - the de facto core unit of any data science, whereas TradingView uses its own data format.
  • Trading Strategy's decide_trades() function is designed to suit all kind of strategies, including portfolio construction, lending strategies, liquidity provider positions and such. Thus, it will return a list of trades to be executed on a blockchain to enter a new position and you have more finer-grained control than PineScript's entry/exit that has been designed for traditional stock markets.

Some differences traders should note:

  • Trading Strategy use a term position to cover a trading position with entry and exit, where as TradingView is using a term trade. This might be confusing because a single position consists of multiple trades.
  • Because the price feed is not 1:1 same (different exchanges), different trades will be taken at a different time
  • Depending on a blockchain and DEX, the assets use wrapped token notation. E.g. ETH becomes WETH. This is due to the technical limitations of EVM-compatible blockchains.

Some differences programmer's should note:

  • Python use the zero indexed arrays unlike PineScript that uses reverse arrays. In Python, like in most programming languages, the latest value of time series is in the last index of an array, noted by -1 and the oldest value is in zero index 0. In PineScript, this is the opposite, where the latest value is noted without index or index 0.

About trading on decentralised finance

DEX trading fees

You have four elements of fees

  • Blockchain transaction costs or gas fees
    • Going towards zero and neglible in the future
  • Trading fee, which consists of
  • Price impact
    • Unlike on order book exchanges, this is very easy to historically backtest on AMMs due to deterministic nature of the price based on liquidity
  • Slippage
    • Price change between signing your transction and having a block producer to include it in a block
    • Also important for MEV protection
    • Usually orders are signed with maximum slippage
  • AMM and CLMM based DEXes do not have slippage

Installation

Make a git clone of this repository and then run poetry to create a Python environment for your project.

poetry shell
poetry install

API key

When you run the notebook for the first time, you will be prompted to register to give an API key to download Trading Strategy datasets.

Running backtests

Running backtest notebooks from terminal

Running the backtesting notebook in a terminal is the most robust, though not that useful method

  • Works always - you see if your code works
  • Opens any charts separate windows in a web browser
  • But it's very hard to work with notebooks in a terminal
  • Using shell for notebooks allows e.g. you to use ipdb breakpoints in Python code.

How to run:

ipython bollinger_band_example_defi_strategy.ipynb 

This will open a couple of browser tabs and print out the trading summary as

Running backtest notebooks with Visual Studio Code

Visual Studio Code is the recommended tool for the backtest development.

First start Poetry environment in a terminal:

poetry shell

Within this shell session, start Visual Studio Code.

code 

Open a notebook in Visual Studio Code.

Use Select Kernel at the top right of the screen. Visual Studio Code should recommend you the same Python virtual environment that is installed with Poetry.

Run the notebook.

Running backtest notebooks Jupyter

You can start Jupyter by:

poetry shell
jupyter notebook

Then choose a notebook from the file explorer and run it

Variations of the backtest example

We have created some alternatives on the notebook to show how it affects profit and loss

Baseline: Annual return 14%, max drawdown 7%.

  • Trailing stop loss - Annual return 18%, max drawdown 7%
  • All in: Use 90% of cash instead of 50% of cash when entering a position. Realised profit $300 -> $600.
  • Multipair: Trade more than single pair
  • Uniswap full history: Trade on ETH-USD pair based on Uniswap v2, so we get max DEX 2020-2023 backtesting history
  • Uniswap 1h candles: Same as above, but trade very frequently

Grid searches

Next steps

Links

Releases

No releases published

Packages

No packages published