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
184 lines of Pine Script v6 from pine/demo_sma_cross.pine, published under MIT. Keep the author's credit and licence lines when you reuse it.
demo_sma_cross.pine
//@version=6
// Demo: a long-only SMA crossover with the TokIO check pasted underneath.
// On SPY daily it looks significant alone; set "Variants tried" to the 20
// parameter sets you might have tried and it isn't.
// To use with your own strategy, paste pine/tokio_check.pine below your code.
strategy("SMA cross + 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)
fastLen = input.int(10, "Fast SMA")
slowLen = input.int(30, "Slow SMA")
f = ta.sma(close, fastLen)
s = ta.sma(close, slowLen)
plot(f, color = color.teal)
plot(s, color = color.orange)
if ta.crossover(f, s)
strategy.entry("Long", strategy.long)
if ta.crossunder(f, s)
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
SMA cross + TokIO check enters when the fast average crosses above the slow average and closes the position when the fast average crosses back below. There is no stop loss or take profit. A table in a chosen corner reports a dependence-aware test of mean trade return, a Sidak correction for the number of variants tried, probabilistic and deflated Sharpe ratios, a minimum track record length, and a symmetric-trim check. Fast and slow lengths, significance level, trial count, and table position are inputs.
The inputs you can change from the gear icon on the chart. Defaults are the author's.
Setting
Type
Default
Variable
Fast SMA
int
10
fastLen
Slow SMA
int
30
slowLen
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 strategy plots an Optimized Trend Tracker and a selectable moving-average support line on the price chart. It builds the average as SMA, EMA, WMA, TMA, VAR, WWMA, ZLEMA, or TSF, then offsets long and short stops by a percent of that average. Optional mark
Calculates a custom moving average (MaMA) by modifying the source price with price momentum, acceleration, and psychological win-rate probability before applying an EMA or SMA. Plots the adjusted moving average directly on the price chart alongside optional re
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 executes trades based on dual exponential moving average trend alignment, customizable Bollinger Bands, and normalized ATR volatility thresholds. It enters positions in the direction of the moving average trend and manages risk using a dynamic st
EMA Trend Surfer is a dual-timeframe trend-following strategy designed for index futures such as MES and MNQ. It determines overall trend direction using fast and slow exponential moving averages on a higher timeframe while seeking entry signals on a lower tim