Package: tradingview-defi-strategy
TradingView and Coinbase to DeFi and Trader Joe algorithmic trading strategy portingThis is an example Python project on how to convert TradingView-based PineScript algorithmic
trading strategies toTradingStrategy.aiPython format.Watch the recorded workshop session on YouTubeThis example repository was made forAvalanche Summit II workshop.See the example Github repository here.Benefits of DeFi for algorithmic tradersPrerequisitesYour skillsSoftwareAbout the example strategyTechnical indicator documentationStrategy performance results and algorithm porting notesEquity curvePrice action and positionsTrading summaryPosition timelineExample codeNotable differences between Python and PineScriptAbout trading on decentralised financeDEX trading feesInstallationAPI keyRunning backtestsRunning backtest notebooks from terminalRunning backtest notebooks with Visual Studio CodeRunning backtest notebooks JupyterVariations of the backtest exampleNext stepsBenefits of DeFi for algorithmic tradersRunning your trading strategy ondecentralised exchangesinstead of centralised exchanges have several benefits:Execute your strategy in a counterparty risk free mannerBroker free, direct to exchangeHave 100% control of your strategy market data and live executionLow trading fees on efficient decentralised marketsConvert your trading algorithm to a on-chain fundBenefits of rich Python quant finance libraries likepandas_taandquantstats.PrerequisitesYour skillsTo work with this example, you need to haveBasic experience in cryptocurrenciesBasic experience in tradingExperience in TradingView's PineScriptJunior level experience in PythonSoftwarePython 3.10Poetry package manager for PythonGitAbout the example strategyThe example strategy backtest is inbollinger_band_example_defi_strategy.ipynbnotebook.The example strategy is a simpleBollinger bandstrategy.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.UseBollinger Band'sandRSIto determine position entriesLong only - suitable forDEX spot marketslike Trader Joe4 hours timeframe for candlesBacktesting period of 2024-04-01 - 2023-04-01Use a tight stop loss when entering a positionThis will result multiple positions closed for stop loss and few profitable positions during market ralliesWe target the following live trading pairsEAVAXTH/USDC pair on Trader Joe on Avalanche with 20 BPS fee tier.
See a note about this indecide_trades()Python code.Coinbase ETH/USDC with 60 BPS market taker fee(12x more expensive than DeFi)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 documentationFind documentation for technical indicators used in the exampleExponential 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 notesBoth 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 curveHow well the strategy would have historically performed on AVAX-USDC pair on Trader Joe on Avalanche (20 BPS fee).How well the strategy would have historically performed on AVAX-USD on Coinbase (no fees).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).Positions takenHere 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.Price action and indicatorsHere is a screenshot of the price action and technical indicators of the strategy.Trading summarySummary 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 timelineHere are individual positions.Example codeThe example strategy is presented asPineScript source fileBacktesting Jupyter Notebook for Trading StrategyStrategy 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#bbandsbollinger_bands=bbands(close_prices,length=MOVING_AVERAGE_LENGTH,std=STDDEV)# bbands() returns a dictionary of items with different name manglingbb_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 averageifnotposition_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.ifprice_latest>bb_upper.iloc[-1]andrsi_series[-1]>=RSI_THRESHOLD:buy_amount=cash*POSITION_SIZEtrades+=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.ifprice_latest<bb_mid.iloc[-1]:trades+=position_manager.close_all()Notable differences between Python and PineScriptSome 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'sdecide_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 termpositionto cover a trading position with entry and exit,
where as TradingView is using a termtrade. 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 timeDepending on a blockchain and DEX, the assets use wrapped token notation.
E.g.ETHbecomesWETH. This is due to the technical limitations ofEVM-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-1and the oldest value is in zero index0.
In PineScript, this is the opposite, where the latest value is noted without index or index 0.About trading on decentralised financeDEX trading feesYou have four elements of feesBlockchain transaction costs orgas feesGoing towards zero and neglible in the futureTrading fee, which consists ofLiquidity provider fee...andprotocol feeUsually 0.05% for large Uniswap v3 pools, otherwise 0.25% - 0.30% onAMMsCompares to 0.60% taker fee on Coinbase, othersPrice impactUnlike on order book exchanges, this is very easy to historically backtest on AMMs due to deterministic nature of the price
based on liquiditySlippagePrice change between signing your transction and having a block producer to include it in a blockAlso important forMEV protectionUsually orders are signed with maximum slippageAMM andCLMMbased DEXes do not have slippageInstallationMake a git clone of this repository and then runpoetryto create a Python environment for your project.poetryshell
poetryinstallAPI keyWhen 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 backtestsRunning backtest notebooks from terminalRunning the backtesting notebook in a terminal is the most robust, though not that useful methodWorks always - you see if your code worksOpens any charts separate windows in a web browserBut it's very hard to work with notebooks in a terminalUsing shell for notebooks allows e.g. you to useipdbbreakpoints in Python code.How to run:ipythonbollinger_band_example_defi_strategy.ipynbThis will open a couple of browser tabs and print out the trading summary asRunning backtest notebooks with Visual Studio CodeVisual Studio Code is the recommended tool for the backtest development.First start Poetry environment in a terminal:poetryshellWithin this shell session, start Visual Studio Code.codeOpen a notebook in Visual Studio Code.UseSelect Kernelat 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 JupyterYou can start Jupyter by:poetryshell
jupyternotebookThen choose a notebook from the file explorer and run itVariations of the backtest exampleWe have created some alternatives on the notebook to show how it affects profit and lossBaseline: 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 pairUniswap full history: Trade on ETH-USD pair based on Uniswap v2, so we get max DEX 2020-2023 backtesting historyUniswap 1h candles: Same as above, but trade very frequentlyGrid searchesGrid search - basic: Automatically search through strategy parameters for an optional combinationGrid search - multiprocessing: Optimise strategy parameters over larger dataset and parameter space using Python multiprocessingNext stepsJoin the Trading Strategy community Discord for discussion and questionsView our learning material for algorithmic tradingStudy other strategy backtesting examples and code samplesLinksTrading Strategy websiteBlogTwitterDiscordTelegram channelChangelog and version history