PROTECTED SOURCE SCRIPT
PSRC | Markov Regime [1D Chart]

1. Overview & Purpose
The PSRC Markov Regime Confidence Filter is a companion module to the PSRC Daily Bias Dashboard. It answers a question the base dashboard does not: given the current market regime, is a bias signal statistically likely to persist, or is it occurring in a regime where persistence has historically been unreliable?
The base dashboard scores bias from three structural factors — Prior Day Value Area position, liquidity sweep + absorption, and VWAP/CVD momentum — and gates zone activation on a single confidence measure: overnight range as a percentage of 20-day ADR. That measure answers "was there enough information built overnight," not "is the broader regime the kind that rewards this setup." The Markov filter closes that gap.
This manual documents the module's internal logic, the institutional design principles it follows, its full input reference, and the operating practices required to run it safely in a live environment. It is written for the desk operating the tool, not as marketing collateral — limitations are stated plainly where they exist.
2. Core Logic
2.1 Why a Discrete Markov Chain, Not a Fitted HMM
The obvious "institutional" answer to regime detection is a Gaussian Hidden Markov Model (HMM), fit via Expectation-Maximization (Baum-Welch), with hidden states inferred from the joint likelihood of observed returns. That is the correct model for offline research. It is the wrong model to run bar-by-bar inside a charting platform, for a specific reason:
• EM fitting is iterative and requires the full sample (or a rolling re-fit window) each time it runs — it is not an incremental, single-pass update.
• Running it live, on every bar, either means re-fitting constantly (prohibitive compute cost in a charting environment) or fitting once and freezing parameters (which silently goes stale as the market's regime statistics drift).
• A model that must look at the whole sample to produce today's state, then gets "frozen" and quietly used going forward, is a subtle form of the same look-ahead problem this framework is otherwise strict about avoiding.
The filter instead uses a first-order discrete-state Markov chain: states are assigned by a deterministic rule (Section 2.2) rather than inferred as latent variables, and the transition matrix is estimated by simple incremental counting over a rolling window (Section 2.3). This is a lower-variance, fully causal, O(1)-per-bar estimator. It gives up the ability to infer regimes the classification rule doesn't already encode — the trade made explicitly, not hidden.
2.2 State Classification — Kaufman's Efficiency Ratio
Each completed daily bar is classified into one of three states using Kaufman's Efficiency Ratio (ER), a standard measure of trend efficiency:
ER = | Close(t) − Close(t − N) | ÷ Σ | Close(i) − Close(i−1) | for i = t−N+1 … t
N = erLen (default 10 trading days)
ER ∈ [0, 1] — 1.0 = a perfectly efficient, one-directional move
0.0 = maximum churn, net-zero displacement
ER is the ratio of net directional displacement to the total path length traveled to get there. A market that moves from 100 to 110 in a straight line has ER ≈ 1; a market that oscillates between 95 and 105 for ten days before closing at 110 has a much lower ER despite an identical net move. This distinguishes a trend day from a chop day using price action alone — no volume or external series required.
Classification rule applied to each confirmed daily close:
• ER ≥ erThresh and net direction positive → BULL
• ER ≥ erThresh and net direction negative → BEAR
• ER < erThresh (regardless of direction) → CHOP
This classification is fully deterministic and reproducible from price data alone — critical for the transition matrix in Section 2.3 to be built on a consistent, auditable sequence.
2.3 Transition Matrix Construction
The filter maintains a 3×3 matrix of transition counts — one row per current-day state, one column per next-day state — updated incrementally as each new day is confirmed:
→ Next: BEAR Next: CHOP Next: BULL
Current: BEAR n₀₀ n₀₁ n₀₂
Current: CHOP n₁₀ n₁₁ n₁₂
Current: BULL n₂₀ n₂₁ n₂₂
The matrix is maintained over a rolling window (default 90 trading days) using a sliding-window count — not a full re-scan. On each new confirmed day, the transition from the prior state to the new state increments by 1; when the window's oldest day rolls off, its corresponding transition is decremented by 1. This keeps the estimator current with recent regime behavior (a stale 2019 transition matrix is of limited use in judging a 2026 regime) while remaining O(1) per update rather than O(window length).
From the current state's row, the model reads off:
• P(persist) — probability the current regime repeats tomorrow (the diagonal entry, normalized by the row total)
• P(next = BULL) / P(next = BEAR) / P(next = CHOP) — full one-step-ahead distribution conditioned on today's state
This is a standard empirical (frequentist) Markov chain estimator — the maximum-likelihood estimate of each transition probability given the observed counts in the window.
2.4 Confidence Gate Derivation
The gate the filter exposes to downstream systems, markovConfidenceOK, requires two conditions simultaneously:
1. Sample adequacy — the current state's row must contain at least minSamples observed transitions (default 12). A persistence probability computed from four historical transitions is a coin flip dressed up as a statistic; the gate refuses to answer when the sample is too thin, rather than reporting a number that implies false precision.
2. Persistence strength — the diagonal (self-transition) probability must clear persistThr (default 55%). Below this, the current regime is no more likely to continue than a range of weaker alternatives, and treating it as a stable regime would be circular reasoning: assuming persistence in order to justify trading persistence.
Both conditions failing independently produce distinct HUD states ("LOW SAMPLE" vs. "WEAK") rather than a single opaque "NO" — the operator should know which condition is failing, since the appropriate response differs (widen the lookback window vs. wait for a genuinely more persistent regime).
2.5 Timeframe-Independence Architecture
All daily-bar data is sourced via request.security_lower_tf(symbol, "D", …) rather than reading the chart's own bars. This guarantees every completed daily bar is processed exactly once, regardless of what timeframe the chart is displaying.
A naive approach — detecting day-rollover from the chart's own bar timestamps — fails silently on weekly/monthly charts: it re-evaluates once per chart bar and skips interior days, corrupting the transition sequence without throwing any error. This is the specific defect corrected in the current build.
3. Why This Is an Institutional-Grade Approach
"Institutional-grade" is not a marketing label here — it refers to a specific set of engineering and statistical disciplines that separate a tool suitable for capital allocation from a retail indicator that merely looks correct on a backtest. The filter is built to each of the following standards:
3.1 Non-Repainting by Construction, Not by Convention
Every reference to historical data uses either a confirmed-bar offset or lookahead=barmerge.lookahead_off. The realtime hold-back guard (Section 2.5) closes the one remaining repaint vector inherent to request.security_lower_tf() on higher timeframes. This matters because a regime filter that quietly repaints will show excellent performance in a backtest and materially different, worse performance live — the single most common reason retail indicators fail to survive contact with live capital.
3.2 Sample-Size Discipline Before Confidence Is Reported
Institutional risk frameworks distinguish between "we have no signal" and "we have a signal we do not yet trust." Reporting a persistence probability computed from an inadequate sample as though it were reliable is a statistical malpractice that shows up in retail tools constantly — a percentage is displayed because the arithmetic is possible, not because the estimate is meaningful. The minSamples gate enforces this distinction explicitly rather than leaving it to the operator's judgment on a bar-by-bar basis.
3.3 Probabilistic Regime Read, Not a Binary Switch
The filter does not output "bull market / bear market" as a hard binary. It outputs a full one-step-ahead probability distribution over three states, conditioned on the current state. This is closer to how a multi-strategy allocator actually treats regime information — as a continuously graded input to position sizing and strategy selection — than a binary flag that a strategy either obeys or ignores.
3.4 Designed as a Layer in a Confluence Stack, Not a Standalone Signal
The filter produces no entries, exits, or standalone trade signals. It is explicitly built to sit inside PSRC's existing Tier 2 protection layer (Daily Bias Alignment) as an additional AND-condition on the existing confOK gate — consistent with the desk's broader philosophy that no single factor should authorize a trade, and that Bias Timeframe, Confirmation Timeframe, and Entry Timeframe each carry their own veto.
3.5 Rolling-Window Estimation, Not a Static Historical Average
The transition matrix is intentionally windowed (default 90 days) rather than accumulated over the full instrument history. Regime statistics from five years ago are treated as decreasingly relevant, not as ground truth — a discipline standard in adaptive, regime-aware allocation frameworks and one many static indicators omit entirely.
4. Best Practices
5.1 Sizing the Rolling Window to the Instrument
The default 90-day window assumes a liquid instrument with reasonably stationary regime behavior over a quarter. Adjust as follows:
• Higher-volatility or narrative-driven instruments (single-name equities around earnings, altcoins): shorten the window (45–60 days) — regime character changes faster and a 90-day matrix will lag genuine shifts.
• Slower macro instruments (major FX majors, broad indices): the default 90 days, or lengthen to 120–150, is generally more stable and less prone to noise-driven regime flips.
• Never shorten the window below roughly 3× minSamples per expected state — a window that can't accumulate an adequate sample for its own gate defeats the point of the gate.
4.2 Calibrating minSamples — Don't Set It for Convenience
It is tempting to lower minSamples when the gate frequently reports LOW SAMPLE. Resist this. A low sample count reporting LOW SAMPLE is the filter doing its job — it means the current regime state genuinely hasn't recurred often enough in the window to estimate its persistence reliably. The correct responses, in order of preference, are: (1) widen lookbackN, (2) accept that some regimes are legitimately rare and trade smaller/without this confirmation layer when they occur, (3) only as a last resort, lower minSamples with the explicit understanding that the resulting probability carries wider real uncertainty than displayed.
4.3 Calibrating persistThr Through Walk-Forward Review, Not Curve-Fitting
persistThr is the input most likely to be tuned toward a specific backtest's historical performance — precisely the input most vulnerable to curve-fitting. Two practices reduce this risk:
Set it from first principles first: 55% is chosen because it is the minimum probability at which persistence is more likely than the combined probability of the other two states, given a 3-state system. Treat this as the baseline, not a parameter to be swept for the best-looking equity curve.
If adjusting, validate walk-forward — evaluate the setting on a period after the one used to select it, not the same period. A threshold that only works in-sample is not a regime filter; it is a fitted parameter wearing one.
The PSRC Markov Regime Confidence Filter is a companion module to the PSRC Daily Bias Dashboard. It answers a question the base dashboard does not: given the current market regime, is a bias signal statistically likely to persist, or is it occurring in a regime where persistence has historically been unreliable?
The base dashboard scores bias from three structural factors — Prior Day Value Area position, liquidity sweep + absorption, and VWAP/CVD momentum — and gates zone activation on a single confidence measure: overnight range as a percentage of 20-day ADR. That measure answers "was there enough information built overnight," not "is the broader regime the kind that rewards this setup." The Markov filter closes that gap.
This manual documents the module's internal logic, the institutional design principles it follows, its full input reference, and the operating practices required to run it safely in a live environment. It is written for the desk operating the tool, not as marketing collateral — limitations are stated plainly where they exist.
2. Core Logic
2.1 Why a Discrete Markov Chain, Not a Fitted HMM
The obvious "institutional" answer to regime detection is a Gaussian Hidden Markov Model (HMM), fit via Expectation-Maximization (Baum-Welch), with hidden states inferred from the joint likelihood of observed returns. That is the correct model for offline research. It is the wrong model to run bar-by-bar inside a charting platform, for a specific reason:
• EM fitting is iterative and requires the full sample (or a rolling re-fit window) each time it runs — it is not an incremental, single-pass update.
• Running it live, on every bar, either means re-fitting constantly (prohibitive compute cost in a charting environment) or fitting once and freezing parameters (which silently goes stale as the market's regime statistics drift).
• A model that must look at the whole sample to produce today's state, then gets "frozen" and quietly used going forward, is a subtle form of the same look-ahead problem this framework is otherwise strict about avoiding.
The filter instead uses a first-order discrete-state Markov chain: states are assigned by a deterministic rule (Section 2.2) rather than inferred as latent variables, and the transition matrix is estimated by simple incremental counting over a rolling window (Section 2.3). This is a lower-variance, fully causal, O(1)-per-bar estimator. It gives up the ability to infer regimes the classification rule doesn't already encode — the trade made explicitly, not hidden.
2.2 State Classification — Kaufman's Efficiency Ratio
Each completed daily bar is classified into one of three states using Kaufman's Efficiency Ratio (ER), a standard measure of trend efficiency:
ER = | Close(t) − Close(t − N) | ÷ Σ | Close(i) − Close(i−1) | for i = t−N+1 … t
N = erLen (default 10 trading days)
ER ∈ [0, 1] — 1.0 = a perfectly efficient, one-directional move
0.0 = maximum churn, net-zero displacement
ER is the ratio of net directional displacement to the total path length traveled to get there. A market that moves from 100 to 110 in a straight line has ER ≈ 1; a market that oscillates between 95 and 105 for ten days before closing at 110 has a much lower ER despite an identical net move. This distinguishes a trend day from a chop day using price action alone — no volume or external series required.
Classification rule applied to each confirmed daily close:
• ER ≥ erThresh and net direction positive → BULL
• ER ≥ erThresh and net direction negative → BEAR
• ER < erThresh (regardless of direction) → CHOP
This classification is fully deterministic and reproducible from price data alone — critical for the transition matrix in Section 2.3 to be built on a consistent, auditable sequence.
2.3 Transition Matrix Construction
The filter maintains a 3×3 matrix of transition counts — one row per current-day state, one column per next-day state — updated incrementally as each new day is confirmed:
→ Next: BEAR Next: CHOP Next: BULL
Current: BEAR n₀₀ n₀₁ n₀₂
Current: CHOP n₁₀ n₁₁ n₁₂
Current: BULL n₂₀ n₂₁ n₂₂
The matrix is maintained over a rolling window (default 90 trading days) using a sliding-window count — not a full re-scan. On each new confirmed day, the transition from the prior state to the new state increments by 1; when the window's oldest day rolls off, its corresponding transition is decremented by 1. This keeps the estimator current with recent regime behavior (a stale 2019 transition matrix is of limited use in judging a 2026 regime) while remaining O(1) per update rather than O(window length).
From the current state's row, the model reads off:
• P(persist) — probability the current regime repeats tomorrow (the diagonal entry, normalized by the row total)
• P(next = BULL) / P(next = BEAR) / P(next = CHOP) — full one-step-ahead distribution conditioned on today's state
This is a standard empirical (frequentist) Markov chain estimator — the maximum-likelihood estimate of each transition probability given the observed counts in the window.
2.4 Confidence Gate Derivation
The gate the filter exposes to downstream systems, markovConfidenceOK, requires two conditions simultaneously:
1. Sample adequacy — the current state's row must contain at least minSamples observed transitions (default 12). A persistence probability computed from four historical transitions is a coin flip dressed up as a statistic; the gate refuses to answer when the sample is too thin, rather than reporting a number that implies false precision.
2. Persistence strength — the diagonal (self-transition) probability must clear persistThr (default 55%). Below this, the current regime is no more likely to continue than a range of weaker alternatives, and treating it as a stable regime would be circular reasoning: assuming persistence in order to justify trading persistence.
Both conditions failing independently produce distinct HUD states ("LOW SAMPLE" vs. "WEAK") rather than a single opaque "NO" — the operator should know which condition is failing, since the appropriate response differs (widen the lookback window vs. wait for a genuinely more persistent regime).
2.5 Timeframe-Independence Architecture
All daily-bar data is sourced via request.security_lower_tf(symbol, "D", …) rather than reading the chart's own bars. This guarantees every completed daily bar is processed exactly once, regardless of what timeframe the chart is displaying.
A naive approach — detecting day-rollover from the chart's own bar timestamps — fails silently on weekly/monthly charts: it re-evaluates once per chart bar and skips interior days, corrupting the transition sequence without throwing any error. This is the specific defect corrected in the current build.
3. Why This Is an Institutional-Grade Approach
"Institutional-grade" is not a marketing label here — it refers to a specific set of engineering and statistical disciplines that separate a tool suitable for capital allocation from a retail indicator that merely looks correct on a backtest. The filter is built to each of the following standards:
3.1 Non-Repainting by Construction, Not by Convention
Every reference to historical data uses either a confirmed-bar offset or lookahead=barmerge.lookahead_off. The realtime hold-back guard (Section 2.5) closes the one remaining repaint vector inherent to request.security_lower_tf() on higher timeframes. This matters because a regime filter that quietly repaints will show excellent performance in a backtest and materially different, worse performance live — the single most common reason retail indicators fail to survive contact with live capital.
3.2 Sample-Size Discipline Before Confidence Is Reported
Institutional risk frameworks distinguish between "we have no signal" and "we have a signal we do not yet trust." Reporting a persistence probability computed from an inadequate sample as though it were reliable is a statistical malpractice that shows up in retail tools constantly — a percentage is displayed because the arithmetic is possible, not because the estimate is meaningful. The minSamples gate enforces this distinction explicitly rather than leaving it to the operator's judgment on a bar-by-bar basis.
3.3 Probabilistic Regime Read, Not a Binary Switch
The filter does not output "bull market / bear market" as a hard binary. It outputs a full one-step-ahead probability distribution over three states, conditioned on the current state. This is closer to how a multi-strategy allocator actually treats regime information — as a continuously graded input to position sizing and strategy selection — than a binary flag that a strategy either obeys or ignores.
3.4 Designed as a Layer in a Confluence Stack, Not a Standalone Signal
The filter produces no entries, exits, or standalone trade signals. It is explicitly built to sit inside PSRC's existing Tier 2 protection layer (Daily Bias Alignment) as an additional AND-condition on the existing confOK gate — consistent with the desk's broader philosophy that no single factor should authorize a trade, and that Bias Timeframe, Confirmation Timeframe, and Entry Timeframe each carry their own veto.
3.5 Rolling-Window Estimation, Not a Static Historical Average
The transition matrix is intentionally windowed (default 90 days) rather than accumulated over the full instrument history. Regime statistics from five years ago are treated as decreasingly relevant, not as ground truth — a discipline standard in adaptive, regime-aware allocation frameworks and one many static indicators omit entirely.
4. Best Practices
5.1 Sizing the Rolling Window to the Instrument
The default 90-day window assumes a liquid instrument with reasonably stationary regime behavior over a quarter. Adjust as follows:
• Higher-volatility or narrative-driven instruments (single-name equities around earnings, altcoins): shorten the window (45–60 days) — regime character changes faster and a 90-day matrix will lag genuine shifts.
• Slower macro instruments (major FX majors, broad indices): the default 90 days, or lengthen to 120–150, is generally more stable and less prone to noise-driven regime flips.
• Never shorten the window below roughly 3× minSamples per expected state — a window that can't accumulate an adequate sample for its own gate defeats the point of the gate.
4.2 Calibrating minSamples — Don't Set It for Convenience
It is tempting to lower minSamples when the gate frequently reports LOW SAMPLE. Resist this. A low sample count reporting LOW SAMPLE is the filter doing its job — it means the current regime state genuinely hasn't recurred often enough in the window to estimate its persistence reliably. The correct responses, in order of preference, are: (1) widen lookbackN, (2) accept that some regimes are legitimately rare and trade smaller/without this confirmation layer when they occur, (3) only as a last resort, lower minSamples with the explicit understanding that the resulting probability carries wider real uncertainty than displayed.
4.3 Calibrating persistThr Through Walk-Forward Review, Not Curve-Fitting
persistThr is the input most likely to be tuned toward a specific backtest's historical performance — precisely the input most vulnerable to curve-fitting. Two practices reduce this risk:
Set it from first principles first: 55% is chosen because it is the minimum probability at which persistence is more likely than the combined probability of the other two states, given a 3-state system. Treat this as the baseline, not a parameter to be swept for the best-looking equity curve.
If adjusting, validate walk-forward — evaluate the setting on a period after the one used to select it, not the same period. A threshold that only works in-sample is not a regime filter; it is a fitted parameter wearing one.
Protected script
This script is published as closed-source. However, you can use it freely and without any limitations – learn more here.
AI will not replace humans. AI-Powered humans will replace everyone.
Follow: plazosullivanroche.com/
Follow: plazosullivanroche.com/
Disclaimer
The information and publications are not meant to be, and do not constitute, financial, investment, trading, or other types of advice or recommendations supplied or endorsed by TradingView. Read more in the Terms of Use.
Protected script
This script is published as closed-source. However, you can use it freely and without any limitations – learn more here.
AI will not replace humans. AI-Powered humans will replace everyone.
Follow: plazosullivanroche.com/
Follow: plazosullivanroche.com/
Disclaimer
The information and publications are not meant to be, and do not constitute, financial, investment, trading, or other types of advice or recommendations supplied or endorsed by TradingView. Read more in the Terms of Use.