5D Library › Credit Cycles, Self-Organised Criticality and the Statistical Physics of Market Phase Transitions · 中文
Chapter 6 The Early-Warning Controversy: Critical Slowing Down and Log-Periodic Power Laws
The first five chapters dealt with mechanisms: how debt builds up, how avalanches spread, how fire sales amplify each other, how volatility comes in clusters. A natural question follows: since these systems have a describable structure before they change abruptly, can the change be recognised before it happens? This chapter discusses two often-mentioned methods and tests on simulated data what they can and cannot do.
Critical slowing down
Many dynamical systems share one feature as they approach a “critical transition” such as a bifurcation point: they recover more and more slowly from small disturbances. This is known as critical slowing down, and Scheffer and colleagues described systematically how it can serve as an early-warning signal: if recovery slows, the lag-1 autocorrelation and the variance of a time series rise (Scheffer et al. 2009). Dakos and colleagues found in palaeoclimate records that autocorrelation did tend to rise before several abrupt climate shifts (Dakos et al. 2008).
Calculation
A test on the simplest first-order autoregressive series. In the “approaching” group the autoregressive coefficient rises gradually from 0.3 to 0.95 over 1,000 steps, simulating a system slowly losing stability; in the “control” group it stays at 0.3 and nothing changes. Compute the lag-1 autocorrelation in a moving window of 250 steps, measure its upward trend with Kendall’s , and count as “issuing a warning”. 200 series per group.
# Critical slowing down (Scheffer et al. 2009): as a system nears a tipping point it recovers more
# slowly from small shocks, so lag-1 autocorrelation and variance rise. Test it on AR(1) series:
# x[t+1] = phi[t] x[t] + noise
# "approaching": phi rises from 0.3 to 0.95 over 1,000 steps (a system drifting towards instability)
# "control": phi stays at 0.3 (nothing is changing)
# Indicator: lag-1 autocorrelation in a moving window of 250 steps; its trend is measured by
# Kendall's tau. A "warning" is declared when tau > 0.5. 200 series of each kind.
import random, statistics as st
def series(n, ramp, rnd):
x, out = 0.0, []
for t in range(n):
phi = 0.3 + (0.65 * t / n if ramp else 0.0)
x = phi * x + rnd.gauss(0, 1); out.append(x)
return out
def ac1(w):
m = st.fmean(w)
return sum((w[i] - m) * (w[i + 1] - m) for i in range(len(w) - 1)) / sum((u - m) ** 2 for u in w)
def kendall(y):
c = d = 0
for i in range(len(y)):
for j in range(i + 1, len(y)):
if y[j] > y[i]: c += 1
elif y[j] < y[i]: d += 1
return (c - d) / (c + d)
def tau_of(x, win=250, step=10):
return kendall([ac1(x[i - win:i]) for i in range(win, len(x) + 1, step)])
rnd = random.Random(8)
for ramp, lab in ((True, "approaching"), (False, "control")):
taus = [tau_of(series(1000, ramp, rnd)) for _ in range(200)]
print(f"{lab:11s}: median tau {st.median(taus):+.2f}; 'warning' (tau > 0.5) in {sum(t > 0.5 for t in taus) / 2:.0f} % of series")
# With a shorter record the same rule loses power and gains false alarms
for ramp, lab in ((True, "approaching"), (False, "control")):
taus = [tau_of(series(300, ramp, rnd), win=100, step=5) for _ in range(200)]
print(f"{lab:11s}, only 300 steps: 'warning' in {sum(t > 0.5 for t in taus) / 2:.0f} % of series")
# approaching: median tau +0.91; 'warning' (tau > 0.5) in 100 % of series
# control : median tau -0.04; 'warning' (tau > 0.5) in 7 % of series
# approaching, only 300 steps: 'warning' in 91 % of series
# control , only 300 steps: 'warning' in 14 % of seriesIn this idealised example the method does quite well: every series in the “approaching” group issues a warning. But about 7 % of the control group issue a warning too, although nothing in the control group changes. With the data shortened to 300 steps the detection rate drops to about 91 % and the false-alarm rate rises to about 14 %.
Two conditions here are easily overlooked. First, the system in the example really is slowly approaching a critical point; its autoregressive coefficient rises step by step. If an abrupt change happens because a large enough random shock pushes the system from one stable state to another while its parameters do not change, there is no slowing down and so no warning. Second, in real studies the abrupt change is usually seen first, and only then do people look back for signals; examining only series in which a change occurred, and not the many in which none did, greatly overstates the reliability of a method.
Evidence
Limits of early-warning signals. Boettiger and Hastings showed with models that at realistic data lengths there is an unavoidable trade-off between the detection power of critical-slowing-down indicators and their false-alarm rate (Boettiger and Hastings 2012b). In another paper they showed that, tested on simulated systems that make transitions purely by chance, common warning statistics give too many false positives, and that testing only systems selected after the fact because a transition occurred overstates a method’s reliability, the “prosecutor’s fallacy” (Boettiger and Hastings 2012a). Boettiger, Ross and Hastings also stress that not every system that undergoes a regime shift shows critical slowing down (Boettiger et al. 2013). Diks, Hommes and Wang tested critical-slowing-down indicators in stock-market data before four financial crises, in 1987, 1997, 2000 and 2008: there was evidence of critical slowing down before Black Monday in 1987, while the results for the other three were mixed or not significant (Diks et al. 2019).
Log-periodic power laws
Sornette and colleagues proposed a more specific model of bubbles (Johansen et al. 2000; Sornette 2003). In their view prices in a bubble grow faster than exponentially, towards a “critical time” , with superimposed oscillations that become faster and faster. The logarithm of the price takes the form
This is called the log-periodic power law (LPPL). Writing the oscillation as a sum of cosine and sine terms, so that only three parameters, , and , enter non-linearly, follows a later reformulation of the model (Filimonov and Sornette 2013). In their framework is the most probable time for the bubble to end, not a time at which a crash must happen; a bubble may also end gently.
The model has seven parameters, of which , and enter non-linearly. With so many parameters and so flexible a form, a natural worry is: can it fit any rising series?
Calculation
Eight simulated series containing no bubble at all: random walks with a positive drift (30 % a year, volatility 19 % a year), 250 trading days each. For each series, search the commonly used parameter ranges ( 5 to 117 days after the last day in steps of 8 days, from 0.1 to 0.9, from 6 to 13) for the best fit, and compare with a straight-line fit; then look at the largest 20-day fall in the following 120 days of the same random walk.
# Over-fitting a log-periodic power law (LPPL; Johansen, Ledoit & Sornette 2000) to series that
# contain NO bubble: random walks with an upward drift (a steady boom, 250 trading days).
# ln p(t) = A + B (tc - t)^m + (tc - t)^m [C1 cos(w ln(tc - t)) + C2 sin(w ln(tc - t))]
# For each (tc, m, w) on a grid, A, B, C1, C2 are fitted by least squares; the best grid point wins.
# Grid: tc 5-117 days after the last observation (steps of 8), m 0.1-0.9, w 6-13 (common filter ranges).
import math, random
def solve(M, v):
n = len(v); M = [row[:] + [v[i]] for i, row in enumerate(M)]
for c in range(n):
piv = max(range(c, n), key=lambda i: abs(M[i][c])); M[c], M[piv] = M[piv], M[c]
if abs(M[c][c]) < 1e-14: return None
for i in range(n):
if i != c:
f = M[i][c] / M[c][c]
M[i] = [a - f * b for a, b in zip(M[i], M[c])]
return [M[i][n] / M[i][i] for i in range(n)]
def lstsq(cols, y):
k = len(cols)
G = [[sum(a * b for a, b in zip(cols[i], cols[j])) for j in range(k)] for i in range(k)]
beta = solve(G, [sum(a * b for a, b in zip(cols[i], y)) for i in range(k)])
if beta is None: return None, float("inf")
fit = [sum(beta[i] * cols[i][t] for i in range(k)) for t in range(len(y))]
return beta, sum((a - b) ** 2 for a, b in zip(y, fit))
def fit_lppl(y):
T = len(y); ts = range(0, T, 2); yy = [y[t] for t in ts]
best = (float("inf"), None)
for tc in range(T + 4, T + 120, 8):
for m in (0.1, 0.3, 0.5, 0.7, 0.9):
for w in (6, 7.5, 9, 10.5, 12, 13):
d = [(tc - t) ** m for t in ts]; L = [math.log(tc - t) for t in ts]
cols = [[1.0] * len(ts), d, [a * math.cos(w * l) for a, l in zip(d, L)], [a * math.sin(w * l) for a, l in zip(d, L)]]
_, sse = lstsq(cols, yy)
if sse < best[0]: best = (sse, (tc - (T - 1), m, w))
tot = sum((u - sum(yy) / len(yy)) ** 2 for u in yy)
_, lin = lstsq([[1.0] * len(ts), [float(t) for t in ts]], yy)
return best[1], 1 - best[0] / tot, 1 - lin / tot
rnd = random.Random(21)
print("series LPPL R^2 straight-line R^2 'critical time' tc largest 20-day fall in the next 120 days")
for k in range(8):
x, y = 0.0, []
for _ in range(370):
x += 0.0012 + 0.012 * rnd.gauss(0, 1); y.append(x) # 30 % a year drift, 19 % a year vol
(tc, m, w), r2, r2lin = fit_lppl(y[:250])
fut = y[249:]
fall = max(1 - math.exp(fut[j] - max(fut[max(0, j - 20):j + 1])) for j in range(len(fut)))
print(f" {k + 1} {r2:.3f} {r2lin:.3f} {tc:4d} days later {fall:5.1%}")
print("No series contains a bubble or a crash mechanism, yet every one yields a fitted 'critical time'.")
# series LPPL R^2 straight-line R^2 'critical time' tc largest 20-day fall in the next 120 days
# 1 0.819 0.766 77 days later 7.6%
# 2 0.812 0.269 109 days later 6.3%
# 3 0.441 0.076 45 days later 15.5%
# 4 0.951 0.925 117 days later 8.9%
# 5 0.739 0.041 37 days later 7.2%
# 6 0.960 0.542 117 days later 10.3%
# 7 0.964 0.958 37 days later 9.4%
# 8 0.971 0.867 5 days later 7.3%
# No series contains a bubble or a crash mechanism, yet every one yields a fitted 'critical time'.Every series yields a “critical time”, from 5 to 117 days, several of them at the edge of the search range; the LPPL is always higher than for a straight line, mostly above 0.8. The largest 20-day fall over the following 120 days lies between 6 % and 16 % and bears no relation to the fitted “critical time”: these series contain no bubble and no crash mechanism in the first place.
Evidence
Tests and criticisms of the LPPL. Feigenbaum carried out a statistical analysis of log-periodic precursors and questioned their significance (Feigenbaum 2001). Brée and Joseph tested 11 crashes of the Hang Seng index between 1970 and 2008: for only 7 did the fitted parameters fall within the ranges Johansen and Sornette had given after the fact; the fitted curves often implied falling prices during bubbles, contradicting the mechanism the model rests on; the LPPL could have predicted the large fall of the Hang Seng in 2008; overall the data supported the model only partially, and the fitting error was highly sensitive to the frequency parameter (Brée and Joseph 2013). Brée, Challet and Peirano showed that LPPL fits are “sloppy”: the critical time is among the least well-determined parameters, adding or removing a single data point can shift it a great deal, and published prediction windows probably understate the uncertainty (Brée et al. 2010).
Note
Fitting after the event is easy; timing in advance is very unreliable. That a flexible model fits a rise that has already happened does not show that it has captured the mechanism behind the rise; a better fit comes largely from more parameters. Testing an early-warning method requires at least: writing the prediction down, including its time window, before the event; running the method in the same way over the many periods in which nothing happened, and counting false alarms; and comparing it with a simple benchmark such as “predict nothing”. This book uses no such method to give any market time or level.
Hypothesis · not established
Out-of-sample test hypothesis for warning methods (not yet established). If a bubble or crash warning method really works, then in an out-of-sample test registered publicly in advance, the share of its warnings followed by a large drawdown within a set period should be clearly higher than the share for the same number of “warnings” issued on randomly chosen dates. If the two do not differ in a pre-registered test, the method’s warning value is refuted.
Summary
Critical slowing down is an early-warning indicator with a solid theoretical basis: as a system slowly approaches a critical point, autocorrelation and variance rise. Simulation shows that under ideal conditions it detects well but still gives false alarms, more of them the shorter the data; abrupt changes triggered by random shocks, with no change in the system’s parameters, leave no such signal. In empirical studies of financial crises, there was evidence of critical slowing down only before the 1987 crash, with mixed results for the others. Log-periodic power laws fit random walks containing no bubble at all very well and produce arbitrary “critical times”. Fitting after the event is easy; timing in advance is statistically very unreliable. The next chapter reads these modern discussions beside ancient writing on rise and decline.
References
Fan, Y. (2026). Credit Cycles, Self-Organised Criticality and the Statistical Physics of Market Phase Transitions: From Minsky's Financial Instability Hypothesis and Sandpile Power-Law Avalanches to Implied-Volatility Skew, Read Beside Classical Chinese Thought on Rise and Decline [信贷周期、自组织临界性与市场相变的统计物理] (Version 1.0.0). 5D Library. https://doi.org/10.5281/zenodo.23754711 · Licensed under Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0).