The Plumbline Trading Suite is organized as four software Stages (I–IV) that map to Steps 1, 4, 5, and 6 of the six-Step pipeline documented on the How-To page. Stage I (Build) is a specification tool and is not covered here. This page documents the statistical and simulation methods behind the three validation Stages: Stage II (Backtest Verification), Stage III (Portfolio Fit), and Stage IV (Prop Firm Verification). For each test, you get the null hypothesis or governing question, the exact procedure, the assumptions, the failure modes, and a worked numeric example.
Plumbline Trading Suite is an educational and research tool. Nothing on this page or produced by this software constitutes financial, investment, trading, tax, or legal advice, or a recommendation to buy, sell, or hold any security, contract, or other financial instrument.
The statistical tests, simulations, and reports described here describe properties of a historical trade log. They do not predict future results. Past performance — simulated or actual — is not indicative of future performance. Trading futures, options, and other leveraged products involves substantial risk of loss and is not suitable for every investor. You can lose more than your initial deposit.
You are solely responsible for your trading decisions and for verifying the correctness, applicability, and legality of any output from this tool in your jurisdiction. Consult a licensed financial professional before making investment decisions. Use of this software is at your own risk and is governed by the project's Terms of Use.
Each Stage answers a different question and can independently fail a strategy that another Stage passes. A production-ready strategy must clear all applicable gates. Stage I (Build) is a specification tool, not a validation tool, and is therefore not covered on this page.
Plumbline is a validation toolkit, not an optimization toolkit. It ingests trade logs produced by fixed-rule strategies and measures their statistical and portfolio properties. It does not re-fit parameters, search parameter spaces, or produce optimized versions of your strategy. Users who want parameter optimization can get it directly from NinjaTrader's Strategy Analyzer.
| Step | Name | Software | Plumbline Stage |
|---|---|---|---|
| 1 | Build (Prompt Builder) | Plumbline Trading Suite | Stage I |
| 2 | Compile strategy code | NinjaTrader 8 (NinjaScript Editor) | — |
| 3 | Backtest strategy | NinjaTrader 8 (Strategy Analyzer) | — |
| 4 | Backtest Verification | Plumbline Trading Suite | Stage II |
| 5 | Portfolio Fit | Plumbline Trading Suite | Stage III |
| 6 | Prop Firm Verification | Plumbline Trading Suite | Stage IV |
Vocabulary: Steps (1–6) describe the workflow you follow. Stages (I–IV) describe the four Plumbline software modules that run inside four of those Steps. This page documents Stages II, III, and IV. Workflow-level guidance and the user-checkpoint between Steps 4 and 5 live on the How-To page.
Given any finite trade log, it is trivial to construct a set of entry and exit rules that produce a great equity curve on that specific data. The rules do not need to have any predictive power. They only need to memorize the sequence of profitable trades that already happened. This is called overfitting, and it is the default outcome of most retail backtesting workflows.
Even a strategy that clears the overfitting hurdle can still fail in a live portfolio for reasons a single-strategy test can't see:
The three Plumbline Stages exist to close each of these gaps in turn.
Stage II asks: Does this strategy have a real edge, or did it just get lucky on this sample?
Stage III asks: Given the other strategies I already run, does this one make my portfolio better or worse?
Stage IV asks: Would this strategy actually survive under the specific rulebook of the funded account I'm trading?
Five independent tests applied to a single strategy's trade log. Each attacks a different failure mode — positive expectancy, sample-lucky sign structure, distributional significance, sequence risk, and out-of-sample persistence. A strategy must clear all five gates to receive an overall pass. The engine uses a numpy-compatible PCG64 PRNG with fixed seed 42, so results are bit-identical across the Python reference implementation and the browser JavaScript port.
Before any statistics, the strategy must clear the most basic hurdle: does its expected value per trade come out positive under the Curtis Faith formulation? A strategy that fails this test has no edge to validate.
The engine also reports expectancy per dollar risked as E / avg_loss, which normalizes across position sizes and lets you compare strategies with different average loss magnitudes.
Pass when E > 0. This is a hard gate. A strategy with non-positive expectancy will not be advanced to the remaining four tests in any meaningful sense — those tests still run, but the overall verdict is already a fail.
If the win/loss pattern were random — every trade a fair coin flip with the observed magnitudes — how often would a random assignment produce a net P&L at least as high as what actually occurred?
Test statistic: net P&L — the sum of realized trade P&L. Iteration count: 10,000 permutations. Random number source: numpy-compatible PCG64 with seed 42, ensuring reproducibility across runs and across the Python and JavaScript implementations.
Pass when p < 0.05. This is a strict binary gate in the engine (the significant_sign_flip_005 flag). There is no warn tier — the engine reports the raw p-value alongside a boolean pass/fail.
x = [+120, -80, +45, +200, -60, +90, -110, +75, +150, -50] T_obs = 380 |x| = [120, 80, 45, 200, 60, 90, 110, 75, 150, 50]
Enumerating all 210 = 1024 sign assignments exactly: 139 produce a signed sum ≥ 380. Exact p-value = 139 / 1024 ≈ 0.136. With p above the 0.05 threshold, this trade log fails the sign-flip test at n = 10. The engine would run 10,000 sampled permutations instead of enumerating exhaustively, but at n = 10 the sampled p-value converges to the exact one within ~0.005.
Sign-flip is a non-parametric test on the sign structure. The one-sample t-test is a parametric test on the mean. Both interrogate "does this strategy have a real edge?" but they attack the question from different angles and can disagree in informative ways. Requiring both to pass tightens the gate.
The JavaScript implementation computes Ft,df via the regularized incomplete beta function (Lanczos log-Gamma for stability, Lentz continued fraction for the beta CDF), which matches scipy.stats.ttest_1samp to double-precision.
Pass when pone < 0.05.
A strategy with one huge outlier winner and many small losers can have very positive mean P&L (t-test says pass) but very few actual winning trades (sign-flip says fail, because random sign assignment easily produces the same sum from the outlier alone). Conversely, a strategy with a strong win rate but tiny average edge can pass sign-flip and fail the t-test. Requiring both catches both pathologies.
The observed backtest is one specific ordering of one specific sample. If the same trades had occurred in a different sequence — or with slight variations in composition — what would the distribution of terminal equities, max drawdowns, and Sharpe ratios look like? And how deep is the drawdown that materializes in unlucky-but-not-unrealistic paths?
Iteration count: 10,000. Resampling scheme: i.i.d. bootstrap with replacement — not block bootstrap. Random source: PCG64, seed 42.
This is the most important design choice in Test 4 and the one most likely to be misunderstood.
If the user does not supply a ruin threshold, the engine sets R to the 95th percentile of simulated max drawdowns. This makes P(ruin) a self-referential measure: it asks "how often does a resampled path suffer a drawdown at or above the 95th percentile of resampled drawdowns?" The answer is mechanically close to 5% for well-behaved distributions, but diverges meaningfully when the drawdown distribution is skewed or bimodal — and that divergence is the signal.
If the user supplies a threshold (e.g., "−$5,000, the max drawdown my prop firm allows"), R is fixed to that value and P(ruin) becomes an absolute measure. The engine reports the ruin_source field as either "auto_95pct" or "user" so the interpretation is unambiguous downstream.
Pass when prob_of_ruin < 0.05. Under the auto ruin threshold, this is a test of drawdown-distribution shape: a strategy passes if the tail of the drawdown distribution is short (few paths hit the 95th-percentile ceiling repeatedly). Under a user-supplied threshold, this is a test of absolute risk exposure against your operational limit.
Split the trade history into a sequence of in-sample and out-of-sample windows. Compare per-trade expectancy between the two. Does the strategy's edge persist as the sample rolls forward? Do enough out-of-sample windows come out profitable to trust the pattern?
Plumbline uses anchored walk-forward. The in-sample window starts at trade 1 and expands with each fold; the out-of-sample window is the next non-overlapping slice. Sliding walk-forward, by contrast, moves both windows together with a fixed IS length and is the version originally documented by Pardo (1992, 2008).
Sliding is more statistically rigorous — folds are approximately independent, per-fold IS statistical power is constant, and the classical academic treatments assume it. Anchored trades some of that rigor for two things: small-sample tolerance (fold 0 gets a usable IS estimate even at modest trade counts), and alignment with deployment reality (live IS is always "everything so far," not a fixed-length recent window).
The sharper critique of anchored — that old data dominates and hides regime shifts — assumes parameters are being re-fit on each IS window. Plumbline does not optimize. It ingests a trade log produced by fixed rules and measures whether the edge persists. In that context, anchored is a defensible design choice rather than a compromise. Users who want the Pardo-canonical sliding version can get it directly from NinjaTrader's Strategy Analyzer, which implements it natively.
| Metric | Pass gate | What a fail means |
|---|---|---|
| median_efficiency | ≥ 0.50 | Typical OOS window delivers less than 50% of the IS expectancy. Edge decays materially out of sample. |
| pct_oos_profitable | ≥ 0.60 | Fewer than 60% of OOS windows came out profitable. Wins are concentrated in specific windows rather than persistent across the sample. |
Overall pass_wfa = true requires both gates. Median efficiency alone can be gamed by one very strong OOS window; the profitability gate exists to require breadth as well as depth.
A strategy with 300 trades, 5 windows, fold_size = floor(300 / 6) = 50:
Window 0: IS trades 0-49 (E_IS = $18.20) OOS trades 50-99 (E_OOS = $9.10) eff = 0.50 Window 1: IS trades 0-99 (E_IS = $15.40) OOS trades 100-149 (E_OOS = $8.50) eff = 0.55 Window 2: IS trades 0-149 (E_IS = $13.10) OOS trades 150-199 (E_OOS = $6.80) eff = 0.52 Window 3: IS trades 0-199 (E_IS = $11.90) OOS trades 200-249 (E_OOS = -$2.10) eff = -0.18 Window 4: IS trades 0-249 (E_IS = $10.20) OOS trades 250-299 (E_OOS = $7.60) eff = 0.75 median_efficiency = median([0.50, 0.55, 0.52, -0.18, 0.75]) = 0.52 → passes 0.50 gate pct_oos_profitable = 4 / 5 = 0.80 → passes 0.60 gate pass_wfa = TRUE
Note: window 3 lost money OOS but did not fail the overall test because the other four windows carried the median and the profitability gate. This is the intended behavior — a single unlucky window should not veto an otherwise robust strategy, but a pattern of unlucky windows will.
Three portfolio-context tests applied on top of strategies that have already cleared Stage II. Test 6 measures how strategies co-move with each other. Tests 7 and 8 measure how the aggregate portfolio behaves against a market backdrop — monthly SPY regimes for edge stability, and passive buy-and-hold SPY for headline performance. Stage III does not re-validate individual strategies; it assumes each has already passed Stage II.
Do these strategies' returns move together? Two strategies with correlated returns provide less diversification than uncorrelated ones, regardless of how individually strong each is.
The engine does not emit a Pass/Warn/Fail verdict for correlation. It renders a heat-shaded matrix using the bands below, plus a per-strategy diversification-benefit bar. These are visual guides, not summary tests.
| ρ range | Shade | Interpretation |
|---|---|---|
| |ρ| < 0.10 | Neutral | Effectively uncorrelated over the sample window. |
| 0.10 ≤ |ρ| < 0.33 | Light brass / light red | Weak co-movement. Meaningful diversification remains. |
| 0.33 ≤ |ρ| < 0.66 | Mid brass / mid red | Moderate co-movement. Diversification benefit reduced. |
| |ρ| ≥ 0.66 | Deep brass / deep red | Strong co-movement. Adding this strategy mostly adds size, not diversification. |
| ρ = 1.00 (diagonal) | Neutral card | Self-correlation, ignored in interpretation. |
Positive and negative correlations receive symmetric bands (brass for positive, red for negative). The diversification-benefit bar is a rough summary computed as max(0, (1 − max(0, mean off-diagonal ρ)) · 100%), not a formal test.
Is the strategy's edge conditional on a specific market regime, or does it persist across regimes? A strategy with strong overall statistics can still be concentrated in one type of market — only bullish, only volatile, only trending — and that concentration is a portfolio-fit signal Stage II cannot see.
Plumbline classifies every month in the historical SPY window on three independent axes. The classifier is a fixed rules-based system, not a model fit. Classifier version 1.0.0 ships with the bundle; percentile-based cuts are re-computed at build time from the SPY sample and pinned into the shipped data.
| Axis | Bucket | Rule |
|---|---|---|
| Direction | Bull | monthly return > +2.0% |
| Bear | monthly return < −2.0% | |
| Neutral | otherwise | |
| Volatility | Low | 21d realized vol < 33rd percentile of vol pool |
| Normal | 33rd ≤ vol ≤ 66th percentile | |
| High | 21d realized vol > 66th percentile of vol pool | |
| Trendiness | Trending | efficiency ratio > 66th percentile of eff pool |
| Choppy | otherwise |
Realized volatility is annualized as stdev(daily_returns) · √252 over a trailing 21-trading-day window ending on the month's last trading day. Efficiency ratio (Kaufman) is |monthly_return| / Σ|daily_returns| — a value near 1.0 indicates a straight-line month, values near 0 indicate directionless chop.
Window: 2015-01-02 through 2026-06-23 (2,884 SPY trading days).
vol_lo = 0.1050 (10.5% annualized) · vol_hi = 0.1540 (15.4% annualized) · eff_hi = 0.3250
Every trade is tagged to a regime by its exit date, sliced to a UTC year-month key. This choice is deliberate and matches Stage II's convention: P&L is realized at exit, so the regime in which the exit occurred is the regime that produced the P&L — even if the trade opened in a different regime.
For each (strategy, axis, bucket) triple with at least one trade, the engine reports:
Regime Alpha is reported per strategy per bucket and is the primary signal for identifying regime dependence. A strategy with a large positive Reg-α in one bucket and a large negative Reg-α in the complementary bucket has a regime-conditional edge. A strategy with Reg-α near zero across all buckets has a regime-agnostic edge.
The engine does not emit a binary Pass/Fail on regime data. It renders a verdict panel and a heat-shaded per-strategy breakdown. Practical reading:
| Pattern | Verdict | Meaning |
|---|---|---|
| Profitable in ≥ 66% of active buckets | Strong edge | Edge is robust across market conditions. |
| Profitable in 50–66% of active buckets | Mixed edge | Some regime dependence. Identify the losing buckets and decide whether they are avoidable in live trading. |
| Profitable in < 50% of active buckets | Conditional edge | Returns are driven by a minority of regimes. Overall Stage II pass may be an artifact of a favorable sample window. |
Would you have been better off just buying and holding SPY? A validated multi-strategy portfolio should outperform passive buy-and-hold on absolute return, on risk-adjusted return, or both. If it does neither, the portfolio's active work is not being compensated.
Alpha and Beta are estimated by ordinary least squares regression of portfolio daily returns on SPY daily returns over the aligned window:
The engine reports each metric for the portfolio, for SPY buy-and-hold, and the delta:
| # | Metric | Definition |
|---|---|---|
| 1 | Total Return | Cumulative return over the aligned window. |
| 2 | Alpha (annualized) | OLS intercept · 252. Portfolio-only. |
| 3 | Beta | OLS slope vs SPY. Portfolio-only; SPY beta is 1.000 by construction. |
| 4 | Up Capture | Portfolio return / SPY return on SPY-up days. |
| 5 | Down Capture | Portfolio return / SPY return on SPY-down days. |
| 6 | Sharpe Ratio | Annualized mean daily return / annualized daily-return stdev. Reported for both. |
| 7 | Time in Market | Fraction of SPY trading days with at least one portfolio trade exit. |
| 8–9 | Supplementary panel | R², portfolio and SPY CAGRs, both max drawdowns, sample-window length in years and trading days, SPY up/down day counts. |
| β | Reading |
|---|---|
| |β| < 0.3 | Market-neutral profile. |
| 0.3 ≤ |β| ≤ 1.3 | Market-like exposure. |
| |β| > 1.3 | Leveraged or heavily directional exposure. |
The engine collapses the panel to one of five plain-English verdicts based on annualized alpha and the Sharpe delta against SPY:
Rule-based simulation of prop firm evaluation and funded-account rulesets against a strategy's historical trade log. Under active development. This section documents the intended methodology so the design can be reviewed and challenged before it ships.
The math and structure below describe the intended Stage IV implementation. It is not shipped yet. Details may change during development.
Prop firms do not evaluate a strategy on its long-run expected return. They evaluate it on a specific rulebook — usually some combination of daily loss limits, trailing drawdown, maximum static drawdown, minimum profit target, and consistency requirements. A strategy with a perfect Stage II report can fail evaluation on a single unlucky Wednesday.
Initial coverage targets Topstep, Apex, and Lucid. Additional firms will be added based on user request. Rulesets will live as JSON templates so users can define custom rulebooks without code changes.
The Stages are gated. A strategy that fails Stage II should not be tested at Stage III. A strategy that fails Stage III at your intended weights should not be tested at Stage IV. Each gate exists to filter out strategies that would waste your time at the next Stage.
| Stage | Applies to | Pass gate | What a fail means |
|---|---|---|---|
| Stage II | Single strategy | All 5 tests pass (AND gate) | Strategy may lack edge, be sample-lucky, be fragile to trade reordering, or fail to persist out-of-sample. |
| Stage III | Strategy in context of existing portfolio and market backdrop | Correlation matrix inspection, favorable/consistent regime alpha, and non-negative benchmark alpha vs SPY | Strategy is valid on its own but adds redundant exposure, concentrates its edge in a single market regime, or fails to outperform passive SPY on a risk-adjusted basis. |
| Stage IV | Strategy under specific prop firm rules | P(pass) > threshold on Monte Carlo | Strategy is portfolio-valid but incompatible with the account rulebook. |
Passing all three Stages does not guarantee live profitability. It means the strategy is not obviously an artifact of overfitting (Stage II), not obviously redundant with your existing portfolio (Stage III), and not obviously incompatible with your funded account (Stage IV). Live performance depends on execution, market impact, regime persistence, and factors these tests do not measure.