TradingView Backtesting

Jarque-Bera Tests for Strategy Returns: What Rejection Means

The Jarque-Bera test combines sample skewness and kurtosis to assess departures from a normal distribution. For strategy returns, rejection challenges a normal-return assumption; it does not establish that the strategy is unprofitable or invalid. First define the return series, then calculate the statistic with a declared moment convention and check whether its reference distribution fits the sample and dependence structure.

See the decision guide

Choose the observations from your TradingView export

TradingView exports report tabs separately: List of Trades supplies trade records, while Performance Summary supplies metrics. Keep the original export, strategy version, symbol, timeframe, date range, sizing rules and cost settings. A normality test needs individual observations, not the summary Sharpe ratio or total return.

  • Reconcile entry and exit rows rather than counting both as independent returns. Document partial exits, open trades, filters and the capital denominator of each percentage.
  • Resolve missing or nonfinite observations before testing. Do not turn a blank return into zero. If records are excluded, preserve the exclusion reason, timestamps and resulting n.
  • Use one return definition and unit throughout. Decimal returns and percentage-point returns give the same JB after a common scale change; simple and log returns are different transformations and can give different results.
TargetInputInterpretation boundary
Trade outcomesOne reconciled closed-trade return per chosen trade unitIrregular durations, position sizes and overlapping exposures can make trades dependent.
Account returnsRegularly sampled equity including open positionsWith no external cash flows, r(t) = E(t) / E(t-1) - 1. Closed-trade P&L alone cannot reconstruct these valuations.
Model innovationsResiduals standardized by a specified conditional scaleThis tests the fitted model error distribution, not the unconditional account-return distribution.

Calculate classical JB from central moments

For n observations x(i), let mean = Σx(i)/n and m(j) = Σ[x(i) - mean]^j/n. With m(2) > 0, skewness S = m(3)/m(2)^(3/2), Pearson kurtosis K = m(4)/m(2)^2, and excess kurtosis g2 = K - 3. The classical statistic is JB = n × [S²/6 + (K - 3)²/24]. Both unusually high and unusually low kurtosis can contribute to rejection.

  • The benchmark values for a normal population are S = 0 and K = 3. Do not subtract 3 again if software already returns excess kurtosis.
  • Under the usual independent, identically distributed normal null and large-sample calibration, JB approaches chi-square(2). Its upper-tail probability is p_asym = exp(-JB/2). At alpha = 0.05, the asymptotic critical value is -2 ln(0.05) = 5.991465.
  • This probability is conditional on the null and calibration assumptions. It is not the probability that your strategy returns are normal, nor the probability that your trading rule works.

Reproduce ten constructed returns and compare conventions

Use the synthetic percentage-point returns [-3, -2, -1, 0, 0, 0, 1, 2, 3, 10]. Here n = 10, mean = 1 pp, m(2) = 11.8 pp², m(3) = 63.6 pp³ and m(4) = 693.4 pp⁴. These values demonstrate arithmetic; ten observations do not justify treating the asymptotic p-value as a calibrated trading decision.

  • G1 is the adjusted Fisher-Pearson skewness coefficient for n > 2. G2 is a common finite-sample correction for excess kurtosis for n > 3. These estimates differ from the unadjusted moment ratios used in classical JB; calling every version simply skewness or kurtosis hides the distinction.
  • Inserting G1 and G2 into the classical formula gives 14.074763 for this same sample. That is a different statistic, not an automatic small-sample repair of JB. A named adjusted test needs its own formula and null calibration.
  • The classical asymptotic p is just above 0.05 in this example. Reporting normal returns would be unjustified even with a well-calibrated test: nonrejection can reflect limited power, and skewness and kurtosis do not uniquely determine a distribution.
QuantityCalculation or conventionResult
S63.6 / 11.8^(3/2)1.569040
K693.4 / 11.8²4.979891
g2K - 31.979891
Classical JB10 × [S²/6 + g2²/24]5.736466
Asymptotic pexp(-5.736466/2)0.056799
Adjusted skewness G1sqrt[n(n-1)] × S / (n-2)1.860653
Adjusted excess kurtosis G2(n-1) × [(n+1)g2 + 6] / [(n-2)(n-3)]4.464450
Independent standard-library calculation. The four-observation minimum is an input policy, not a sufficient sample size for asymptotic inference. p_asym is explicitly an approximation.python
from math import exp, fsum, isfinite, sqrt


def jarque_bera_moments(values):
    x = [float(value) for value in values]
    n = len(x)
    if n < 4 or not all(isfinite(value) for value in x):
        raise ValueError("Need at least four finite observations")
    scale = max(abs(value) for value in x)
    if scale == 0:
        raise ValueError("Constant data: normality statistic is undefined")
    # Common scaling avoids overflow in third and fourth powers.
    y = [value / scale for value in x]
    mean = fsum(y) / n
    d = [value - mean for value in y]
    m2 = fsum(value**2 for value in d) / n
    if m2 <= 0:
        raise ValueError("Zero or numerically lost variance")
    z = [value / sqrt(m2) for value in d]
    skew = fsum(value**3 for value in z) / n
    kurtosis = fsum(value**4 for value in z) / n
    jb = n * (skew**2 / 6 + (kurtosis - 3)**2 / 24)
    return {"n": n, "skew": skew, "pearson_kurtosis": kurtosis,
            "JB": jb, "p_asym": exp(-jb / 2)}


print(jarque_bera_moments([-3, -2, -1, 0, 0, 0, 1, 2, 3, 10]))
# JB = 5.736465775565..., p_asym = 0.056799208524...

Check the calibration before comparing p with alpha

The large-sample reference is the main constraint. SciPy explicitly cautions that its asymptotic JB test needs a large sample and cites more than 2,000 observations. That is guidance for the approximation, not a guarantee at observation 2,001. Small samples can have poor calibration or low power; a long series can still contain dependence or regime changes.

  • Shuffling the same observations leaves JB unchanged because the moments ignore order. It does not provide a null distribution for normality or cure dependence.
  • A block bootstrap of observed nonnormal returns does not automatically impose a normal null. Resampling and any refitting must reproduce the hypothesis being tested; replacing n with a mean effective sample size is not a general correction for third- and fourth-moment uncertainty.
  • Choose the sample, alpha and test version before searching across instruments, windows or parameter sets. Repeatedly testing until a preferred conclusion appears changes the error rate.
ConditionWhy it mattersDefensible next step
Small independent sampleThe finite-sample null distribution differs from chi-square(2).If an iid normal null is justified, simulate samples of the same n under that null and recompute the same statistic. Report simulation count, seed and Monte Carlo uncertainty.
Overlapping trades or returnsReused price changes undermine iid calibration.Audit timing and exposure. Use a justified non-overlapping design or a dependence-aware test with a documented null model.
Volatility clustering or changing regimesA normal conditional innovation model can coexist with nonnormal pooled returns.Separate the unconditional question from model-residual diagnostics. Check serial structure in returns and squared returns.
Constant or nearly constant seriesZero variance makes standardized third and fourth moments undefined; rounding can erase tiny variation.Report undefined or numerical failure. Never convert that state to p = 1.

Use rejection to review assumptions, not grade the strategy

A small calibrated p-value is evidence against the specified normal-return null. Examine which component contributes: skewness can reflect asymmetric exits or exposure, while kurtosis may reflect rare large moves or a mixture of volatility states. Those are hypotheses to investigate against the trade record, not causes established by JB.

  • Review a histogram, a normal Q-Q plot and the actual tail observations. Check data errors and costs before changing the model. Do not remove legitimate losses merely to obtain a larger p-value.
  • Rejection may make a normal-tail VaR calculation or normal-error confidence interval unsuitable. It does not directly test expected net profit, execution realism, drawdown tolerance or out-of-sample persistence; evaluate those questions separately.
  • Nonrejection leaves uncertainty. Some nonnormal distributions match the normal third and fourth moments, and a short sample may miss rare losses. A normality label cannot replace tail stress scenarios or chronological validation.
  • Record n, the observation clock, return definition, S, Pearson K or excess g2, JB, calibration method, alpha, missing-data policy and software version with the conclusion. Keep the descriptive moments even when inferential assumptions are not defensible.

Reconcile report fields, then calculate JB independently

Pineify Backtest Deep Report parses TradingView trade timestamps, prices, quantity, net P&L and P&L percentage. Its current advanced metrics calculate skewness and excess kurtosis from trade P&L percentages using central moments divided by n. These are useful checks against the trade sample; the report does not currently expose a Jarque-Bera statistic or p-value.

  • Use the same included trades and full-precision returns when reconciling the moments. Do not infer an accurate JB from rounded displayed statistics, or treat trade percentages as daily account returns.
  • The current report calculation falls back to zero for skewness and excess kurtosis when variance is zero. For a JB analysis, treat that input as undefined instead of interpreting the fallback as evidence of normality.
  • Pine Script AI Coding Agent can help draft a custom return-series output from explicit timing and valuation rules. Review the generated code and reconcile exported values independently. The Python calculation on this page is separate from both products.
Where Pineify fits

Backtest Deep Report

Inspect TradingView trade records and supported distribution metrics before calculating and interpreting JB separately.

Also useful: Pine Script AI Coding Agent. Draft custom series output with explicit return definitions and observation timing, then verify the values independently.

Review Backtest Deep Report

Frequently asked questions

Educational information, not investment advice. The numerical sample is constructed, not observed strategy performance. Distribution diagnostics and historical backtests do not guarantee future results.

Sources and verification

Published by Pineify. Pineify is an independent product and is not affiliated with TradingView. Sources support the technical explanations; examples do not establish trading performance.