Professional Documents
Culture Documents
Replica of TradingView Backtesting Engine
Replica of TradingView Backtesting Engine
Here is a perfectly replicated TradingView backtesting engine condensed into a single library function
calculated with arrays. It includes TradingView's calculations for Net profit, Total Trades, Percent of
Trades Profitable, Profit Factor, Max Drawdown (absolute and percent), and Average Trade (absolute and
percent). Here's how TradingView defines each aspect of its backtesting system:
Net Profit: The overall profit or loss achieved.
Total Trades: The total number of closed trades, winning and losing.
Percent Profitable: The percentage of winning trades, the number of winning trades divided by the total
number of closed trades.
Profit Factor: The amount of money the strategy made for every unit of money it lost, gross profits
divided by gross losses.
Max Drawdown: The greatest loss drawdown, i.e., the greatest possible loss the strategy had compared
to its highest profits.
Average Trade: The sum of money gained or lost by the average trade, Net Profit divided by the overall
number of closed trades.
bool _enter: When the strategy should enter a trade (entry condition)
bool _exit: When the strategy should exit a trade (exit condition)
float _startQty: The starting capital in the account (for BTCUSD, it is the amount of USD the
account starts with)
float _tradeQty: The amount of capital traded (if set to 1000 on BTCUSD, it will trade 1000 USD
on each trade)
Currently, this library only works with long strategies, and I've included a commented out section under
DEMO STRATEGY where you can replicate my results with TradingView's backtesting engine. There's tons
I could do with this beyond what is shown, but this was a project I worked on back in June of 2022
before getting burned out. Feel free to comment with any suggestions or bugs, and I'll try to add or fix
them all soon. Here's my list of thing to add to the library currently (may not all be added):
Separate all variables, so they become accessible outside of calculations (such as gross profit,
gross loss, number of winning trades, number of losing trades, etc.).
//@version=5
library("OzzyBacktestEngine")
// quality of life user function that help when working with array data usage
array.pop(_array)
// _backtest() function
export _backtest(bool _enter, bool _exit, float _startQty, float _tradeQty) =>
var tradeAmt =0
var tradeProfitable = 0
var grossProfit = 0.0
var tradeOpen =0
if barstate.isconfirmed
if barstate.isfirst
array.unshift(profit_array, 0)
tradeOpen := 1
array.unshift(entryPrice_array, open)
array.unshift(entryQty_array, _tradeQty/entryPrice)
netProfit := netProfit
_clearArray(entryPrice_array, 3)
_clearArray(entryQty_array, 3)
if _exit[1] and (tradeOpen == 1)
tradeOpen := 0
tradeAmt += 1
array.unshift(exitPrice_array, open)
_clearArray(exitPrice_array, 3)
netProfit += tradeReturn
array.unshift(tradeReturn_array, tradeReturn)
array.unshift(profit_array, netProfit)
array.unshift(percentProfit_array, netPercentProfit)
tradeProfitable += 1
grossProfit += math.abs(tradeReturn)
grossLoss += math.abs(tradeReturn)
// Max Drawdown
array.unshift(drawdown_array, drawdown)
// "THE PERCENTAGE AND ABBSOLUTE VALUES OF A DRAWDOWN ARE TWO DIFFERENT METRICS.
THEY ARE TRICKED INDEPENDENTLY."
// This takes the percent of the current Max Drawdown, not the max percent drawdown
// Average Trade
avgTrade := array.avg(tradeReturn_array)
////////////////////////////////////////////
////////////////////////////////////////////
// //@version=5
// strategy("DEMO STRATEGY", overlay=true, default_qty_type = strategy.cash, default_qty_value =
1000, initial_capital = 10000)
// sma_fast = ta.sma(close, 9)
// if enterLong
// strategy.entry("Long", strategy.long)
// if exitLong
// strategy.close("Long")
sma_fast = ta.sma(close, 9)
plot(sma_fast, color=color.lime)
_addCell(_table) =>
_addCell(backtest_table)