1Copy the scriptPress Copy script above, or the copy button on the code below.
2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
3Paste over the templateCreate a new strategy, select all of the template text and paste. Press Save and give it a name.
4Add it to the chartPress Add to chart. The trades and results appear in the Strategy Tester tab; adjust the settings with the gear icon.
Source Code
186 lines of Pine Script v6 from pine/demo_rsi2_pullback.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.
demo_rsi2_pullback.pine
//@version=6
// Demo: a classic RSI(2) pullback on SPY daily, with the TokIO check pasted underneath.
// Alone it looks like an edge: plain t-test p=0.0004, dependence-corrected p=0.006.
// Set "Variants tried" to 20 (the RSI lengths, thresholds and exits you might have
// tried) and it is NOT SIGNIFICANT: p=0.11, Deflated Sharpe 0.82, and its minimum
// track record is 351 trades against the 106 it has (0.05% commission, 1 tick slippage).
strategy("RSI(2) pullback + TokIO check", overlay = true, initial_capital = 10000, default_qty_type = strategy.percent_of_equity, default_qty_value = 100, commission_type = strategy.commission.percent, commission_value = 0.05, slippage = 1)
rsiLen = input.int(2, "RSI length")
buyBelow = input.int(5, "Buy when RSI below")
sellAbove = input.int(60, "Sell when RSI above")
trendLen = input.int(200, "Trend filter SMA")
r = ta.rsi(close, rsiLen)
trend = ta.sma(close, trendLen)
plot(trend, color = color.orange)
if r < buyBelow and close > trend
strategy.entry("Long", strategy.long)
if r > sellAbove
strategy.close("Long")
// ─────────────────────────────────────────────────────────────────────────────
// TokIO backtest check for TradingView — paste below your strategy's code.
// https://github.com/Kuzi-DEV/Tokio-ai (MIT licence)
//
// Is this strategy's profit distinguishable from luck? Reads the strategy's
// closed trades and draws a table on the chart with:
// • a one-sided test of the mean trade return that allows for serial
// dependence (Bartlett HAC, Andrews bandwidth, Kiefer-Vogelsang fixed-b),
// the same test as TokIO's Python check_backtest on a trade list
// • Sidak's correction for the number of variants you tried ("Trials")
// • the Probabilistic / Deflated Sharpe Ratio (Bailey & Lopez de Prado),
// as published and with the dependence correction
// • the minimum track record length, and a symmetric-trim check
//
// A trade's return is its P&L as a % of the position's value
// (strategy.closedtrades.profit_percent), so position sizing doesn't move
// the verdict. The Python package does more — several variants corrected
// for each other, probability of backtest overfitting, costs/breakeven, the
// lookahead (one-bar delay) check — on the Strategy Tester's trade export:
// pip install tokio-ai
// tokio-ai-backtest "List of trades.csv" --trials 30
//
// Requires: //@version=6 and a strategy() script. Rename nothing below.
// ─────────────────────────────────────────────────────────────────────────────
tokio_trials = input.int(1, "Variants tried (incl. this one)", minval = 1, group = "TokIO check",
tooltip = "Every parameter set, indicator or rule you tried before keeping this one. Be honest: the correction is only as good as this number.")
tokio_alpha = input.float(0.05, "Significance level", minval = 0.001, maxval = 0.5, group = "TokIO check")
tokio_pos = input.string("bottom_right", "Table position", options = ["top_left", "top_center", "top_right", "middle_left", "middle_center", "middle_right", "bottom_left", "bottom_center", "bottom_right"], group = "TokIO check")
// Standard normal CDF (Abramowitz & Stegun 7.1.26 erf, |error| < 1.5e-7)
tokio_cdf(float tk_z) =>
tk_x = math.abs(tk_z) / math.sqrt(2.0)
tk_t = 1.0 / (1.0 + 0.3275911 * tk_x)
tk_y = 1.0 - (((((1.061405429 * tk_t - 1.453152027) * tk_t) + 1.421413741) * tk_t - 0.284496736) * tk_t + 0.254829592) * tk_t * math.exp(-tk_x * tk_x)
tk_z >= 0 ? 0.5 * (1.0 + tk_y) : 0.5 * (1.0 - tk_y)
// Inverse standard normal CDF (Acklam, relative error < 1.2e-9)
tokio_inv(float tk_p) =>
tk_a1 = -3.969683028665376e+01
tk_a2 = 2.209460984245205e+02
tk_a3 = -2.759285104469687e+02
tk_a4 = 1.383577518672690e+02
tk_a5 = -3.066479806614716e+01
tk_a6 = 2.506628277459239e+00
tk_b1 = -5.447609879822406e+01
tk_b2 = 1.615858368580409e+02
tk_b3 = -1.556989798598866e+02
tk_b4 = 6.680131188771972e+01
tk_b5 = -1.328068155288572e+01
tk_c1 = -7.784894002430293e-03
tk_c2 = -3.223964580411365e-01
tk_c3 = -2.400758277161838e+00
tk_c4 = -2.549732539343734e+00
tk_c5 = 4.374664141464968e+00
tk_c6 = 2.938163982698783e+00
tk_d1 = 7.784695709041462e-03
tk_d2 = 3.224671290700398e-01
tk_d3 = 2.445134137142996e+00
tk_d4 = 3.754408661907416e+00
float tk_r = na
if tk_p < 0.02425
tk_q = math.sqrt(-2.0 * math.log(tk_p))
tk_r := (((((tk_c1 * tk_q + tk_c2) * tk_q + tk_c3) * tk_q + tk_c4) * tk_q + tk_c5) * tk_q + tk_c6) / ((((tk_d1 * tk_q + tk_d2) * tk_q + tk_d3) * tk_q + tk_d4) * tk_q + 1.0)
else if tk_p <= 1.0 - 0.02425
tk_q = tk_p - 0.5
tk_s = tk_q * tk_q
tk_r := (((((tk_a1 * tk_s + tk_a2) * tk_s + tk_a3) * tk_s + tk_a4) * tk_s + tk_a5) * tk_s + tk_a6) * tk_q / (((((tk_b1 * tk_s + tk_b2) * tk_s + tk_b3) * tk_s + tk_b4) * tk_s + tk_b5) * tk_s + 1.0)
else
tk_q = math.sqrt(-2.0 * math.log(1.0 - tk_p))
tk_r := -(((((tk_c1 * tk_q + tk_c2) * tk_q + tk_c3) * tk_q + tk_c4) * tk_q + tk_c5) * tk_q + tk_c6) / ((((tk_d1 * tk_q + tk_d2) * tk_q + tk_d3) * tk_q + tk_d4) * tk_q + 1.0)
tk_r
tokio_fmt(float tk_v, int dp) =>
na(tk_v) ? "–" : str.tostring(tk_v, dp == 2 ? "#,##0.00" : dp == 3 ? "0.000" : "0.0000")
if barstate.islastconfirmedhistory or (barstate.islast and barstate.isrealtime)
int tk_n = strategy.closedtrades
var table tk_tbl = na
if not na(tk_tbl)
table.delete(tk_tbl)
tk_pos = switch tokio_pos
"top_left" => position.top_left
"top_center" => position.top_center
"top_right" => position.top_right
"middle_left" => position.middle_left
"middle_center" => position.middle_center
"middle_right" => position.middle_right
"bottom_left" => position.bottom_left
"bottom_center" => position.bottom_center
=> position.bottom_right
tk_tbl := table.new(tk_pos, 2, 12, bgcolor = color.new(color.black, 0), border_color = color.gray, border_width = 1, frame_color = color.gray, frame_width = 1)
tk_txt = color.white
table.cell(tk_tbl, 0, 0, "TokIO check", text_color = tk_txt, text_size = size.small)
if tk_n < 60
table.cell(tk_tbl, 1, 0, "NOT REPORTABLE", text_color = color.orange, text_size = size.small)
table.cell(tk_tbl, 0, 1, "Closed trades", text_color = tk_txt, text_size = size.small)
table.cell(tk_tbl, 1, 1, str.tostring(tk_n) + " (need 60+)", text_color = tk_txt, text_size = size.small)
else
tk_rets = array.new_float(0)
for tk_i = 0 to tk_n - 1
array.push(tk_rets, strategy.closedtrades.profit_percent(tk_i) / 100.0)
float tk_m = array.avg(tk_rets)
// central moments (population), Bartlett long-run variance
float tk_s2 = 0.0
float tk_s3 = 0.0
float tk_s4 = 0.0
float tk_g1 = 0.0
for tk_i = 0 to tk_n - 1
tk_d = array.get(tk_rets, tk_i) - tk_m
tk_s2 += tk_d * tk_d
tk_s3 += tk_d * tk_d * tk_d
tk_s4 += tk_d * tk_d * tk_d * tk_d
if tk_i > 0
tk_g1 += tk_d * (array.get(tk_rets, tk_i - 1) - tk_m)
tk_v = tk_s2 / tk_n
tk_sd = math.sqrt(tk_s2 / (tk_n - 1))
tk_skew = (tk_s3 / tk_n) / math.pow(tk_v, 1.5)
tk_kurt = (tk_s4 / tk_n) / (tk_v * tk_v)
// Andrews (1991) AR(1) plug-in and the Newey-West rule; the larger wins
tk_rho = math.max(-0.97, math.min(0.97, tk_g1 / tk_s2))
tk_a1 = 4.0 * tk_rho * tk_rho / (math.pow(1.0 - tk_rho, 2) * math.pow(1.0 + tk_rho, 2))
int tk_L = math.min(tk_n - 1, math.max(int(math.floor(4.0 * math.pow(tk_n / 100.0, 2.0 / 9.0))), int(1.1447 * math.pow(tk_a1 * tk_n, 1.0 / 3.0))))
float tk_lrv = tk_s2
if tk_L > 0
for tk_l = 1 to tk_L
float tk_gl = 0.0
for tk_t = tk_l to tk_n - 1
tk_gl += (array.get(tk_rets, tk_t) - tk_m) * (array.get(tk_rets, tk_t - tk_l) - tk_m)
tk_lrv += 2.0 * (1.0 - tk_l / (tk_L + 1.0)) * tk_gl
tk_lrv := math.max(tk_lrv / tk_n, 1e-18)
tk_b = (tk_L + 1.0) / tk_n
tk_fb = 1.6449 / (1.6449 + 2.1859 * tk_b + 0.3142 * tk_b * tk_b - 0.3427 * tk_b * tk_b * tk_b)
tk_z = tk_m / math.sqrt(tk_lrv / tk_n) * tk_fb
tk_p_alone = 1.0 - tokio_cdf(tk_z)
tk_p_adj = 1.0 - math.pow(1.0 - tk_p_alone, tokio_trials)
tk_z_naive = tk_m / (tk_sd / math.sqrt(tk_n))
tk_p_naive = 1.0 - tokio_cdf(tk_z_naive)
// Sharpe per trade; annualized by trades per year
tk_sr = tk_m / tk_sd
tk_span_years = (strategy.closedtrades.exit_time(tk_n - 1) - strategy.closedtrades.entry_time(0)) / (365.25 * 86400000.0)
tk_tpy = tk_span_years > 0 ? tk_n / tk_span_years : na
tk_sr_ann = na(tk_tpy) ? na : tk_sr * math.sqrt(tk_tpy)
// PSR / DSR (Bailey & Lopez de Prado); vr scales Var(SR) for dependence
tk_vr = (tk_lrv / tk_v) / (tk_fb * tk_fb)
tk_core = math.max(1.0 - tk_skew * tk_sr + (tk_kurt - 1.0) / 4.0 * tk_sr * tk_sr, 1e-12)
tk_gam = 0.5772156649015329
tk_bench = tokio_trials > 1 ? math.sqrt(1.0 / (tk_n - 1)) * ((1.0 - tk_gam) * tokio_inv(1.0 - 1.0 / tokio_trials) + tk_gam * tokio_inv(1.0 - 1.0 / (tokio_trials * math.e))) : 0.0
tk_psr_pub = tokio_cdf((tk_sr - tk_bench) * math.sqrt(tk_n - 1) / math.sqrt(tk_core))
tk_psr_dep = tokio_cdf((tk_sr - tk_bench) * math.sqrt(tk_n - 1) / math.sqrt(tk_core * tk_vr))
tk_mintrl = tk_sr > tk_bench ? 1.0 + tk_core * tk_vr * math.pow(tokio_inv(0.95) / (tk_sr - tk_bench), 2) : na
// symmetric trim: drop the 5 best and 5 worst trades
tk_sorted = array.copy(tk_rets)
array.sort(tk_sorted, order.ascending)
tk_k = math.min(5, int(tk_n / 20))
tk_tr = array.slice(tk_sorted, tk_k, tk_n - tk_k)
tk_sr_trim = array.stdev(tk_tr, false) > 0 ? array.avg(tk_tr) / array.stdev(tk_tr, false) * (na(tk_tpy) ? 1.0 : math.sqrt(tk_tpy)) : na
tk_sig = tk_p_adj <= tokio_alpha
tk_verdict = tk_sig ? "SIGNIFICANT" : "NOT SIGNIFICANT"
table.cell(tk_tbl, 1, 0, tk_verdict + (tokio_trials > 1 ? " (" + str.tostring(tokio_trials) + " trials)" : ""), text_color = tk_sig ? color.lime : color.red, text_size = size.small)
tk_rows = array.from("p-value, corrected", "p-value, this alone", "p-value, plain t-test", "Sharpe (annualized)", (tokio_trials > 1 ? "Deflated" : "Probabilistic") + " Sharpe Ratio", " as published (indep. trades)", "Min. track record (trades)", "Sharpe w/o 5 best & 5 worst", "Closed trades", "Trades per year")
tk_vals = array.from(tokio_fmt(tk_p_adj, 4), tokio_fmt(tk_p_alone, 4), tokio_fmt(tk_p_naive, 4), tokio_fmt(tk_sr_ann, 2), tokio_fmt(tk_psr_dep, 3) + " (0.95 passes)", tokio_fmt(tk_psr_pub, 3), na(tk_mintrl) ? "never" : str.tostring(math.ceil(tk_mintrl)), tokio_fmt(tk_sr_trim, 2), str.tostring(tk_n), tokio_fmt(tk_tpy, 2))
for tk_i = 0 to array.size(tk_rows) - 1
table.cell(tk_tbl, 0, tk_i + 1, array.get(tk_rows, tk_i), text_color = tk_txt, text_size = size.small, text_halign = text.align_left)
table.cell(tk_tbl, 1, tk_i + 1, array.get(tk_vals, tk_i), text_color = tk_txt, text_size = size.small, text_halign = text.align_right)
table.cell(tk_tbl, 0, 11, "Mean trade return " + tokio_fmt(tk_m * 100.0, 3) + "%; HAC lag window " + str.tostring(tk_L), text_color = color.gray, text_size = size.tiny, text_halign = text.align_left)
table.merge_cells(tk_tbl, 0, 11, 1, 11)
Overview
RSI(2) pullback + TokIO check closes the long when RSI rises above a second threshold and does not set a stop loss. Position size defaults to full equity. It plots the trend average on the price chart and draws a TokIO table that tests closed-trade returns for serial dependence, trial-count correction, and Sharpe-style significance. Trial count, significance level, and table position are configurable.
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
RSI length
int
2
rsiLen
Buy when RSI below
int
5
buyBelow
Sell when RSI above
int
60
sellAbove
Trend filter SMA
int
200
trendLen
Variants tried (incl. this one)
int
1
tokio_trials
Significance level
float
0.05
tokio_alpha
Table position
string
bottom_right
tokio_pos
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.
This overlay strategy combines a machine-learning distance model with a MACD oscillator to open trades on the price chart. It compares recent history using cosine similarity or Euclidean and Lorentzian distance, then filters direction with selectable moving-av
This long-only trend-following strategy combines Ichimoku Kinko Hyo components with higher timeframe moving average filters. It triggers long entries when price trades above a higher timeframe EMA and a bullish Tenkan-Sen cross above Kijun-Sen occurs under fav
This strategy calculates trend direction across three user-defined higher timeframes using dual Simple Moving Averages, filtered by On-Balance Volume and Commodity Channel Index conditions alongside fractal pivot swings. Entries trigger when multi-timeframe tr
This strategy plots on the gold price chart and combines stochastic, RSI, and three EMAs with ATR. Confirm buys and sells can require an M15 overbought or oversold rejection wick, a Fibonacci or EMA zone, and a no-chase distance from the fast EMA. Optional LSB
This strategy automatically adapts its moving average lengths and types based on the chart's timeframe, covering scalping, intraday, and swing styles. It generates entry signals when a fast moving average crosses a slow moving average, provided price is on the
This strategy draws on the price chart and trades a fast and slow Commodity Channel Index against an exponential moving average regime. It enters long when the fast CCI crosses above the lower extreme, the slow CCI is already above that level, and price is abo