Hoeveel van de honderden gepubliceerde voorspellers van rendementen, in dit college
signalen, zijn echt, en waarom verzwakken ze na publicatie? De meeste doorstaan een
strengere drempel en zijn in de oorspronkelijke constructie te repliceren. Na publicatie
verliezen ze echter meer dan de helft van hun rendement, veel meer
dan publicatieselectie alleen kan verklaren. Dit college gaat in vier stappen.
We leiden de procedures voor meervoudig toetsen af, van Bonferroni en Holm tot
Benjamini-Hochberg-Yekutieli, en zien waarom de drempel met het aantal geprobeerde
signalen stijgt.
We laten zien dat selectie op t>2 de gepubliceerde rendementen opblaast, en hoeveel
daling na publicatie daaruit volgt als functie van de ware sterkte van een signaal.
We simuleren een vakgebied zonder één echte anomalie, waarin de gepubliceerde signalen
na publicatie al hun rendement verliezen.
We repliceren de verzwakking na publicatie, de strengere drempels en de alpha’s ten
opzichte van vijf factoren plus momentum op 212 signalen.
In zijn presidentiële rede voor de American Finance Association zei John Cochrane in 2011
dat de cross-sectie vroeger uit het CAPM leek te komen. Nu hebben we volgens hem een
dierentuin van nieuwe factoren Cochrane (2011). Die factor zoo (de honderden
gepubliceerde
kenmerken die rendementen voorspellen) telde bij Harvey et al. (2016) al 316
soorten. Zij eisten daarom een t-waarde boven 3. McLean & Pontiff (2016) vonden
dat rendementen na publicatie ruim de helft lager liggen, en Hou et al. (2020) dat
de meeste van 452 anomalieën verdwijnen als kleine aandelen weinig gewicht krijgen. Daarop
volgde een tegenreactie van Chen & Zimmermann (2022) en
Jensen et al. (2023), die de meeste signalen wel konden repliceren. Waarom
ze verzwakken, staat bij Santa-Clara (2026) nog op de lijst van open vragen. Zo
verschuift het werk in de cross-sectie van het toetsen van één theorie naar het tellen van
feiten die op een verklaring wachten.
Denk aan een vakgebied met driehonderd onderzoekers. Elk van hen heeft een database en een
idee, en elk idee laat zich op tien manieren
uitwerken, bijvoorbeeld met een andere definitie van winst of een andere weging. Stel
verder dat
geen enkel idee iets voorspelt. Toch haalt ongeveer een op de veertig uitwerkingen door
toeval een t-waarde boven twee. Tijdschriften publiceren die resultaten en de rest
verdwijnt in een la, zodat de literatuur vol significante signalen staat.
Na publicatie komt het toeval dat zo’n signaal in de steekproef significant maakte
niet terug, en zijn gemiddelde rendement zakt naar nul. Voor een lezer lijkt de anomalie
dan verdwenen, terwijl er nooit iets was. Dat heet de winner’s curse (de vloek van de
winnaar): wie selecteert op een hoge schatting, selecteert ook op een gunstige meetfout.
Er zijn twee andere redenen waarom een rendement na publicatie kan zakken. Is het
signaal een patroon dat beleggers over het hoofd zagen, dan lezen hedgefondsen het
artikel en handelen erop tot het niet meer loont. Is het een beloning voor risico, dan kan
de premie dalen omdat meer beleggers dat risico willen dragen. McLean en Pontiff zagen dat
de kalender deze verhalen deels scheidt. Tussen het einde van de steekproef en de
publicatie is het toeval uit de steekproef al weg, terwijl de markt het resultaat nog niet
kent. Een daling in die tussenperiode is dus statistiek, en een extra daling na publicatie
is leren.
Daarom vraagt een grote factor zoo om een hogere drempel en om shrinkage (krimpen: een
schatting naar een gemeenschappelijk gemiddelde trekken, harder naarmate ze ruisiger is).
Een gemeten rendement van 1% per maand is dan waarschijnlijk een kleinere echte premie
met een gunstige meetfout. We verwachten dus dat een toevalstreffer na publicatie al zijn
rendement verliest en een sterk signaal bijna niets. De daling in de tussenperiode zou
kleiner moeten zijn dan die na publicatie.
3Toy-voorbeeld: tien kandidaat-signalen en zes procedures¶
Een onderzoeker toetst tien signalen, A tot en met J. Van elk signaal kent hij de
t-waarde van het gemiddelde long-short-rendement. Alleen A heeft een echte premie, en
de andere negen zijn ruis, maar dat weet hij niet. Bij onafhankelijke toetsen haalt een
nulsignaal ∣t∣≥2,2 met kans 0,028 (de p-waarde van E hieronder), zodat gemiddeld
9×0,028≈0,25 van de negen zo ver komen, geen vier. Bij varianten van
één idee, die samen hoog of laag uitvallen, zijn vier treffers wel goed mogelijk.
De tweezijdige p-waarde is p=2(1−Φ(∣t∣)), met Φ de standaardnormale
verdelingsfunctie uit een normale tabel. De tabel sorteert de p-waarden van klein naar
groot, met rang j, en geeft per rang de grens van vier procedures bij 5%. Bonferroni
verdeelt de 5% over de tien toetsen en Holm maakt die grens na elke verwerping ruimer,
zodat beide tegen ook maar één onterechte ontdekking beschermen. BH en BHY bewaken het
aandeel onterechte ontdekkingen, zodat hun grens met de rang meegroeit, en BHY is strenger
om ook bij samenhangende signalen te gelden. De Theorie leidt de grenzen af.
rang j
signaal
t
p
Bonferroni
Holm
BH
BHY
1
A
4,10
0,00004
0,00500
0,00500
0,005
0,00171
2
B
2,79
0,00527
0,00500
0,00556
0,010
0,00341
3
C
2,70
0,00693
0,00500
0,00625
0,015
0,00512
4
D
2,45
0,01429
0,00500
0,00714
0,020
0,00683
5
E
2,20
0,02781
0,00500
0,00833
0,025
0,00854
6
F
1,60
0,10960
0,00500
0,01000
0,030
0,01024
7
J
−1,30
0,19360
0,00500
0,01250
0,035
0,01195
8
G
1,10
0,27133
0,00500
0,01667
0,040
0,01366
9
H
0,80
0,42371
0,00500
0,02500
0,045
0,01537
10
I
−0,50
0,61708
0,00500
0,05000
0,050
0,01707
Uit de tabel volgen zes antwoorden, die alleen in de grens verschillen.
Naïef (p≤0,05, dus ∣t∣>1,96) vindt A tot en met E, vijf ontdekkingen
waarvan vier onterecht.
t>3 vindt alleen A.
Bonferroni vergelijkt elke p met 0,05/10=0,005, wat overeenkomt met
∣t∣>2,807, en vindt alleen A, omdat B met 0,00527 net boven de grens blijft.
Holm loopt van boven naar beneden en stopt bij de eerste mislukking. A haalt
0,005 en B haalt 0,00556, maar C mist 0,00625, zodat A en B overblijven.
Benjamini-Hochberg (BH) zoekt de grootste rang met p(j)≤0,05j/10. Bij D
geldt 0,01429≤0,020, en geen hogere rang haalt zijn grens, dus BH vindt A tot
en
met D.
BHY deelt de grenzen van BH door 1+21+⋯+101=2,929.
Alleen A haalt dan zijn grens. Bij rang 2 is BHY met 0,00341 zelfs strenger dan
Bonferroni met 0,005, zodat de prijs van robuustheid bij tien signalen al zichtbaar is.
Eén functie voert de zes procedures uit op een rij t-waarden, zodat we haar later op
echte data kunnen gebruiken. Een tweede cel zet de ontdekkingen naast die van de hand.
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy import optimize, stats
import hap
from hap import data as hap_data
hap.plotting.setup()
rng = np.random.default_rng(20240101)
def multiple_testing(t, q=0.05):
"""Two-sided rejections of H0: mean = 0 for a vector of t-statistics (normal p-values).
Columns: naive (p <= q), |t| > 3, Bonferroni, Holm (step-down),
Benjamini-Hochberg and Benjamini-Hochberg-Yekutieli (step-up).
"""
# TODO: naar hap.stats (multiple testing corrections)
t = np.asarray(t, dtype=float)
M = t.size
p = 2 * stats.norm.sf(np.abs(t))
order = np.argsort(p) # indices from smallest to largest p
ranks = np.arange(1, M + 1)
p_sorted = p[order]
def step_up(thresholds):
passed = np.nonzero(p_sorted <= thresholds)[0]
k = passed.max() + 1 if passed.size else 0
reject = np.zeros(M, dtype=bool)
reject[order[:k]] = True
return reject
holm = np.zeros(M, dtype=bool)
for j, idx in enumerate(order): # step down: stop at the first failure
if p[idx] > q / (M - j):
break
holm[idx] = True
c_M = np.sum(1.0 / ranks)
return pd.DataFrame({
"naief": p <= q,
"|t| > 3": np.abs(t) > 3,
"Bonferroni": p <= q / M,
"Holm": holm,
"BH": step_up(q * ranks / M),
"BHY": step_up(q * ranks / (M * c_M)),
})
p-waarden gelijk aan de tabel (5 decimalen): True
Bonferroni-drempel |t| > 2.807 ; c(10) = 2.929
Loading...
Code en hand vinden dezelfde signalen. Benjamini-Hochberg accepteert hier drie
nulsignalen, omdat het alleen hun aandeel beperkt. Met één lijstje t-waarden vindt de
onderzoeker dus één tot vijf signalen, afhankelijk van de vergissing die hij wil
vermijden.
De theorie beantwoordt de twee helften van de vraag. Voor de vraag hoeveel signalen
echt zijn, leiden we de procedures uit het toy-voorbeeld af en daarna de Bayesiaanse
shrinkage van gemeten rendementen. Voor de verzwakking berekenen we hoeveel selectie een
gepubliceerd rendement opblaast en hoe McLean en Pontiff selectie en arbitrage scheiden.
Tot slot bekijken we de modellen die de factor
zoo met een handvol factoren willen samenvatten.
Er zijn M signalen (in de literatuur ook anomalieën of factoren), i=1,…,M,
bijvoorbeeld de 316 van Harvey, Liu en Zhu. Signaal i is een long-short-portefeuille met
maandrendement ri,t+1 en ware premie αi, het gemiddelde rendement, of de alpha
als er een factormodel bij staat. Over Ti maanden schatten we
α^i met standaardfout si, en ti=α^i/si. In grote steekproeven
is ti≈N(δi,1), waarin δi=αi/si de verwachte
t-waarde is. Een premie van 0,5% per maand met een standaardfout van 0,2% heeft
bijvoorbeeld δi=2,5. De nulhypothese Hi is αi=0, en de M0 ware
nulhypothesen vormen de verzameling I0.
Een procedure verwerpt een aantal hypothesen. Met V het aantal onterechte en R het
totale aantal verwerpingen definiëren we
De family-wise error rate (FWER) is dus de kans op minstens één onterechte ontdekking,
en de false discovery rate (FDR) het verwachte aandeel onterechte ontdekkingen. Omdat
V/max(R,1) nooit groter is dan 1{V≥1}, geldt
FDR≤FWER, zodat een procedure die de FWER onder q houdt dat ook
met de FDR doet. Het niveau q is meestal 5%.
Een onderzoeker die elk signaal op niveau q/M toetst, houdt de kans op zelfs één
onterechte ontdekking onder q, hoe de signalen ook samenhangen. De kans dat minstens één
van de ware nulhypothesen wordt verworpen, is namelijk nooit groter dan de som van de
afzonderlijke kansen. Holm merkte op dat die som alleen over de ware nulhypothesen hoeft te
lopen. Zolang na j−1 verwerpingen nog geen ware nulhypothese is verworpen, zijn er
hoogstens M−j+1 ware nulhypothesen over, zodat de grens bij elke volgende rang
ruimer mag worden.
Voor Bonferroni is het bewijs één regel, namelijk
Pr(V≥1)≤∑i∈I0Pr(pi≤q/M)≤qM0/M. Voor Holm volstaat
het naar de kleinste p-waarde onder de ware nulhypothesen te kijken.
Proof 1
Holm houdt de FWER onder q. Laat i∗ de ware nulhypothese met de kleinste
p-waarde zijn, met rang j∗ in de geordende rij. Vóór i∗ staan hoogstens
M−M0 p-waarden, dus j∗≤M−M0+1. Een onterechte verwerping betekent dat
Holm tot minstens rang j∗ komt, zodat pi∗≤q/(M−j∗+1)≤q/M0.
Daarom is
Pr(V≥1)≤Pr(mini∈I0pi≤q/M0)≤M0⋅q/M0=q. Holm verwerpt alles wat Bonferroni verwerpt. Omdat q/(M−j+1)≥q/M, haalt elke Bonferroni-verwerping ook de Holm-grens, en alle kleinere p-waarden halen dan hun lagere
Holm-grens eveneens. □
4.3Benjamini-Hochberg-Yekutieli: het aandeel vergissingen onder afhankelijkheid¶
Benjamini en Hochberg beperken het aandeel onterechte ontdekkingen tot q door de
p-waarden stapsgewijs met qj/M te vergelijken. Het bewijs in
De industrie als financier: indexfondsen, DFA, AQR (Theorem 2) gebruikte echter onafhankelijke
p-waarden.
Twintig varianten van value worden echter tegelijk significant of niet, en zo’n klont
nulsignalen kan de stapsgewijze procedure over een grens duwen. Benjamini en Yekutieli
lieten zien dat het ergste geval te beheersen is door q te delen door een logaritmische
factor.
Het bewijs neemt één ware nulhypothese i en BH op niveau q, en schrijft 1/R als de
telescopische som ∑k=RM−1(1/k−1/(k+1))+1/M. Omdat pi≤qR/M
ook pi≤qk/M geeft voor elke k≥R, is de verwachte bijdrage van i hoogstens
∑k(1/k−1/(k+1))qk/M+q/M=qc(M)/M. Die grens hangt niet meer van
R af, en daarmee ook niet van de afhankelijkheid tussen de p-waarden. Opgeteld over de
M0 ware nulhypothesen en met q′=q/c(M) geeft dat de stelling.
Die robuustheid heeft een hoge prijs. Bij M=316 is c(M)=6,33, zodat BHY bij een
niveau van 5% in feite met ongeveer 0,8% werkt. Harvey, Liu en Zhu catalogiseerden 316
factoren en berekenden voor elk jaar sinds 1967 welke drempel de
procedures zouden hebben opgelegd. In hun figuur 3 stijgt de
Bonferroni-drempel van 1,96 naar 3,78 in 2012, terwijl BHY bij 5% op 2,78 uitkomt. Hun
vuistregel van ongeveer 2,8 ronden ze in de samenvatting af tot een t-waarde boven 3
Harvey et al. (2016). Omdat ongepubliceerde toetsen in hun telling ontbreken, zijn die
drempels ondergrenzen.
4.4Publicatieselectie: hoeveel een gepubliceerde t is opgeblazen¶
Een tijdschrift ziet niet alle t-waarden maar alleen de waarden boven twee. Een
gepubliceerde t is daarom een trekking uit een afgeknotte verdeling, en het gemiddelde
van die afgeknotte verdeling ligt boven het ware gemiddelde. Het verschil is de meetfout
die de selectie heeft binnengehaald, en omdat die meetfout buiten de steekproef niet
terugkomt, daalt het rendement na publicatie.
De verwachte gepubliceerde t is dus de ware t plus een opslag λ(c−δ), en
die opslag is groot als het signaal zwak is. Voor c=2 geeft een normale tabel
φ(2)=0,0540 en 1−Φ(2)=0,0228, zodat een gepubliceerde nulfactor
gemiddeld t=2,37 heeft en buiten de steekproef 100% van zijn rendement verliest. Voor
echte signalen daalt D snel, naar 28,5% bij δ=2 en 1,4% bij δ=4. Een
toevalstreffer verliest dus alles en een sterk signaal bijna niets, zoals we bij de
intuïtie al vermoedden. Een daling van een kwart past bij δ rond twee, wat de
tweede oefening narekent.
De nulsignalen B tot en met E uit het toy-voorbeeld laten die opslag zien. Hun gemiddelde
t van (2,79+2,70+2,45+2,20)/4=2,54 ligt dicht bij λ(2)=2,37,
terwijl hun ware δ nul is en hun t na publicatie dus rond nul hoort te liggen.
Selectie werkt op de steekproef en arbitrage op de kalender. Een model met die twee
elementen voorspelt
drie niveaus van het gemiddelde rendement, en de verschillen daartussen meten de twee
oorzaken apart.
Het ware gemiddelde rendement van signaal i is αi tot publicatie en
(1−a)αi daarna, met a het deel dat door handel op het artikel verdwijnt. Met
Theorem 3 is dan
Van de steekproef naar de tussenperiode verdwijnt dus alleen de selectieopslag, en van de
tussenperiode naar na publicatie alleen het deel a. McLean en Pontiff schatten die
verschillen met één gepoolde regressie op twee dummies en
een vast effect per signaal,
waarin TUS één is in de tussenperiode en NA na publicatie. Gedeeld
door het gemiddelde rendement in de steekproef meet −β1 het aandeel statistische
bias en −(β2−β1) het aandeel arbitrage. Volgens McLean en Pontiff lag het
rendement in de tussenperiode 26% lager en na publicatie 58%, zodat 32% toe te schrijven is
aan handel op het artikel McLean & Pontiff (2016). De 26% noemen ze een bovengrens voor
datamining, omdat werkdocumenten al vóór publicatie circuleren en de tussenperiode dus
ook arbitrage bevat.
Een geschatte premie is de som van een echte premie en een meetfout. Hoe groter de
meetfout ten opzichte van de spreiding in echte premies, hoe meer van een extreme
schatting meetfout is en hoe harder we haar terugtrekken. Die spreiding volgt uit de
factor zoo zelf, want de variantie van de schattingen is die van de premies plus die van
de meetfouten.
De krimpfactor Bi ligt tussen nul en één. Hij stijgt met de spreiding τ van echte
premies, omdat een extreme schatting dan vaker een extreme premie is. Hij daalt met de
standaardfout si, omdat een ruisige schatting minder zegt. Neem een artikel dat een
rendement van α^=1% per maand rapporteert met t=2,5, dus met
standaardfout s=0,4%. Zijn de premies van alle geprobeerde signalen verdeeld met
μ=0 en τ=0,4%, dan geldt
Het verwachte rendement na publicatie is de helft van het gepubliceerde, en de kans dat de
premie positief is, is Φ(0,5/0,283)=0,961. Het signaal is dus waarschijnlijk
echt, maar half zo sterk. Met τ=0,2% wordt de krimpfactor
0,04/(0,04+0,16)=0,2, zodat er 0,2% overblijft. De code rekent beide gevallen
na.
De tabel bevestigt de handberekening, en ze laat zien dat het antwoord afhangt van wat de
rest van de factor zoo over τ zegt. In de berekening komt de publicatieselectie niet
voor, en het volgende gevolg zegt waarom dat mag.
De winner’s curse verdwijnt dus niet, maar hij zit in de krimpfactor, mits de prior de
verdeling van alle geprobeerde signalen beschrijft. Een prior die alleen uit
gepubliceerde signalen is geschat, is zelf geselecteerd en daardoor te optimistisch.
Harvey, Liu en Zhu antwoorden op de factor zoo frequentistisch, met een hogere drempel,
en Jensen, Kelly en Pedersen Bayesiaans, met een prior. Empirical Bayes
schat de prior uit de data zelf, met het laatste deel van de stelling,
τ^2=max(0,M1∑i(α^i−μ^)2−M1∑isi2).
Bij Jensen et al. (2023) delen factoren binnen elk van hun 13 thema’s een
themagemiddelde, dat zelf naar nul wordt getrokken. Meer factoren per
thema maken dat gemiddelde preciezer, zodat een grote factor zoo het bewijs voor
afzonderlijke factoren juist kan versterken.
4.7FF5 en q-factoren als keuzes voor de stochastische discontofactor¶
Als driehonderd signalen maar een handvol onafhankelijke bronnen van verwacht
rendement hebben, moet een klein aantal factoren de rest verklaren. Twee groepen zochten
ze in de boekhouding, de een via de waardering en de ander via de investeringsbeslissing,
en kwamen ongeveer bij dezelfde factoren uit. Vanaf hier
zijn Vt, Bt en Rt+1 marktwaarde, boekwaarde en bruto rendement, en niet de
tellingen V en R of de krimpfactor Bi van hierboven.
Fama & French (2015) herschreven het dividendkortingsmodel uit
Williams en het dividend discount model met clean surplus (het dividend is de winst Y min de groei
dB van het eigen vermogen) en deelden door de boekwaarde Bt. Met k de interne
discontovoet geldt
Houden we de rest vast, dan gaan een lagere Vt/Bt en een hogere verwachte winst samen
met een hogere k. Een hogere groei van het eigen vermogen gaat samen met een lagere k.
Dat zijn
value, winstgevendheid en investeringen. Zo kwamen naast
markt, SMB en HML de factoren RMW (robust minus weak, winstgevendheid) en CMA
(conservative minus aggressive, investeringen) in het model. Ze zijn gebouwd zoals SMB
en HML in (2), en Novy-Marx (2013)
had de winstgevendheidsfactor al voorbereid. Hou et al. (2015) redeneerden vanuit
de investeringsbeslissing, wat een tweeperiodemodel zichtbaar maakt.
Proof 5
De eerste-ordevoorwaarde naar It is 1+κIt/At=Et[mt+1Πt+1]. De
waarde na dividend is pt=Et[mt+1Πt+1It]=(1+κIt/At)It en de
payoff is Πt+1It, zodat Rt+1=Πt+1/(1+κIt/At). Dat
Et[mt+1Rt+1]=1 volgt dan uit de eerste-ordevoorwaarde. □
Bij gegeven risico Covt(mt+1,Rt+1) daalt het verwachte rendement dus met de
investeringsgraad en stijgt het met de verwachte winstgevendheid. Een onderneming met lage
kapitaalkosten investeert veel, en een die een hoge winst verwacht maar weinig investeert,
moet hoge kapitaalkosten hebben. Het
q-model heeft daarom vier factoren: markt, size, investeringen (I/A) en
winstgevendheid (ROE). Beide modellen zijn keuzes voor de stochastische discontofactor
m=1−b′(f−Ef), lineair in een paar factorrendementen
f zoals in Cochrane: p = E[mx]. Ze verklaren een anomalie alleen in de zin
dat de alpha ten opzichte van die m klein is. Of RMW en CMA risico meten of een
vergissing, zegt (8) niet, want de identiteit geldt voor
elke discontovoet.
Of een nieuwe factor g iets toevoegt, is een vraag over zijn gewicht bg in m gegeven
de andere factoren (Proposition 1). Zo zeggen Fama en French dat
HML in hun steekproef overbodig wordt, dus dat bHML nul is.
Met een dubbele LASSO voor de controlefactoren vinden Feng et al. (2020) de
meeste nieuwe factoren overbodig, op enkele na. Volgens
Novy-Marx & Velikov (2016) blijven na transactiekosten vooral strategieën met weinig
omzet over. Intussen verpakten fondsen value, momentum en kwaliteit als smart beta
(regelgebaseerde portefeuilles die naar factoren kantelen). Eind 2019 bezaten
indexfondsen iets meer van de Amerikaanse beurs dan actieve aandelenfondsen Investment Company Institute (2020).
Is de daling na publicatie arbitrage, dan holt elke dollar in zulke fondsen de premie
verder uit.
Hoeveel verliest een gepubliceerd signaal na publicatie als er alleen selectie werkt en
niemand arbitreert? We simuleren 300 onderzoekers die elk 20 signalen toetsen op een markt
waarin geen enkel signaal een premie heeft. Elk signaal is een long-short-portefeuille
met een volatiliteit van 3% per maand, gemeten over 20 jaar. Alleen signalen met t>2
worden gepubliceerd, en daarna volgen 5 jaar tussenperiode en 20 jaar na publicatie. De
cel simuleert maandrendementen en vat per periode de gepubliceerde signalen samen.
n_researchers, n_per_researcher = 300, 20
periods = {"in-sample": 240, "oos": 60, "post": 240}
PERIOD_NAMES = {"in-sample": "in de steekproef", "oos": "tussenperiode", "post": "na publicatie"}
sigma_ls, c_pub = 0.03, 2.0
def simulate_field(alpha, rng):
"""Mean, standard error and t of every signal in each period; alpha is the true monthly premium."""
out = {}
for name, T in periods.items():
r = alpha + sigma_ls * rng.standard_normal((T, alpha.size))
mean, se = r.mean(axis=0), r.std(axis=0, ddof=1) / np.sqrt(T)
out[name] = pd.DataFrame({"mean": mean, "se": se, "t": mean / se})
return out
null_field = simulate_field(np.zeros(n_researchers * n_per_researcher), rng)
published = null_field["in-sample"]["t"] > c_pub
mills = stats.norm.pdf(c_pub) / stats.norm.sf(c_pub)
null_summary = pd.DataFrame({
"gem. rendement (% p.m.)": [100 * null_field[k]["mean"][published].mean() for k in periods],
"SE van dat gemiddelde": [100 * null_field[k]["mean"][published].std(ddof=1) / np.sqrt(published.sum())
for k in periods],
"gem. t": [null_field[k]["t"][published].mean() for k in periods],
}, index=list(periods))
print(f"{published.sum()} van {published.size} signalen gepubliceerd "
f"(verwacht {published.size * stats.norm.sf(c_pub):.0f}); "
f"theorie E[t | t > 2] = {mills:.3f}")
null_summary.rename(index=PERIOD_NAMES).round(3)
142 van 6000 signalen gepubliceerd (verwacht 137); theorie E[t | t > 2] = 2.373
Loading...
Van de 6000 nulsignalen worden er 142 gepubliceerd, tegen 137 verwacht. Hun gemiddelde
t van 2,33 ligt dicht bij de 2,37 uit (2), en het kleine
verschil komt van de geschatte standaardfout en de beperkte steekproef van 142 signalen.
In de steekproef verdienen de gepubliceerde signalen 0,44% per maand, maar in de
tussenperiode en na publicatie liggen hun gemiddelden binnen twee standaardfouten van nul.
Ze verliezen dus hun hele rendement, zonder dat iemand iets heeft gearbitreerd, net als
de nulsignalen B tot en met E in het toy-voorbeeld.
Signalen met een echte premie verliezen minder. Omdat alleen de schatting telt, trekken we
voor elke ware sterkte δ de t-waarden in en buiten de steekproef direct uit
N(δ,1) en vergelijken we de gesimuleerde daling met
(3).
def inverse_mills(x):
return stats.norm.pdf(x) / stats.norm.sf(x)
def decline_formula(delta, c=c_pub):
return inverse_mills(c - delta) / (delta + inverse_mills(c - delta))
deltas = np.linspace(0.25, 5.0, 20)
simulated_decline = []
for delta in deltas:
t_in = delta + rng.standard_normal(200_000)
t_out = delta + rng.standard_normal(200_000) # same standard error out of sample
keep = t_in > c_pub
simulated_decline.append(1 - t_out[keep].mean() / t_in[keep].mean())
simulated_decline = np.array(simulated_decline)
delta_26 = optimize.brentq(lambda d: decline_formula(d) - 0.26, 0.5, 5.0)
print(f"grootste afwijking simulatie - formule: {np.max(np.abs(simulated_decline - decline_formula(deltas))):.4f}")
print(f"daling van 26% bij een ware verwachte t van {delta_26:.2f}")
grootste afwijking simulatie - formule: 0.0049
daling van 26% bij een ware verwachte t van 2.10
Simulatie en formule verschillen nergens meer dan een half procentpunt. Bij een ware
verwachte t van 2,10 hoort een daling van 26%. Links in de figuur is de vraag of het
histogram de afgeknotte kromme volgt, rechts waar de lijnen van 26% en 58% de formule
snijden.
Source
fig, axes = plt.subplots(1, 2, figsize=(11, 4.3))
t_pub = null_field["in-sample"]["t"][published]
axes[0].hist(t_pub, bins=np.linspace(2, 4.5, 26), density=True, alpha=0.6, label="gepubliceerde t, in de steekproef")
axes[0].hist(null_field["post"]["t"][published], bins=np.linspace(-4, 4.5, 43), density=True,
histtype="step", lw=1.6, color="black", label="dezelfde signalen, na publicatie")
grid = np.linspace(2, 4.5, 200)
axes[0].plot(grid, stats.norm.pdf(grid) / stats.norm.sf(c_pub), color=hap.plotting.COLORS[1],
label="afgeknotte normale, t > 2")
axes[0].set_title("(a) 6000 nulsignalen, alleen t > 2 gepubliceerd")
axes[0].set_xlabel("t-waarde")
axes[0].set_ylabel("Dichtheid")
axes[0].legend()
fine = np.linspace(0.05, 5, 200)
axes[1].plot(fine, 100 * decline_formula(fine), label="formule D(δ)")
axes[1].plot(deltas, 100 * simulated_decline, "o", ms=4, label="simulatie")
for level, text in ((26, "McLean-Pontiff tussenperiode: 26%"), (58, "McLean-Pontiff na publicatie: 58%")):
axes[1].axhline(level, color="black", lw=0.8, ls="--")
axes[1].text(3.0, level + 2, text, fontsize=8)
axes[1].set_title("(b) Daling die alleen uit selectie volgt")
axes[1].set_xlabel("Ware verwachte t-waarde δ")
axes[1].set_ylabel("Verwachte daling van het rendement (%)")
axes[1].legend(loc="upper right")
fig.tight_layout()
plt.show()
Figure 1:Links volgen de gepubliceerde t-waarden in een markt zonder anomalieën de afgeknotte
normale verdeling, terwijl dezelfde signalen na publicatie weer rond nul liggen. Rechts
staat de daling die puur uit de selectie t>2 volgt, als functie van de ware sterkte
van het signaal. De 26% van McLean en Pontiff past bij een ware verwachte t rond 2,1. Hun 58% zou
signalen rond één vereisen, die de drempel meestal niet eens halen.
Selectie verklaart de daling in de tussenperiode dus alleen bij zwakke signalen. Hoe
sterk de echte signalen zijn, moet de replicatie laten zien.
De eerste vraag is of de volgorde van McLean en Pontiff terugkomt. De cel koppelt elke
signaalmaand aan een periode en berekent per periode het gemiddelde rendement over de
signalen.
De volgorde komt terug. Gemiddeld over alle signalen verdient een long-short-portefeuille
in de steekproef 0,69% per maand, in de tussenperiode 40% minder en na publicatie 57%
minder, maar nog steeds duidelijk meer dan nul.
Een enkel signaal is nauwelijks te volgen, want over een tussenperiode van gemiddeld 55
maanden is zijn standaardfout 0,48% per maand, groter dan het rendement zelf. Pas het
gemiddelde over alle signalen
maakt de daling meetbaar. De volgende cel schat (5) met vaste
effecten per signaal en standaardfouten die per maand geclusterd zijn.
def within(x, groups):
"""Demean a series within groups (the fixed-effects transformation)."""
return x - x.groupby(groups).transform("mean")
def mp_regression(frame, extra=None):
"""Pooled OLS of returns (% p.m.) on OOS and POST dummies with signal fixed effects.
Standard errors are clustered by month. `extra` adds further dummy columns.
"""
# TODO: naar hap.stats (panel regression with fixed effects and clustered errors)
y = within(100 * frame["r"], frame["signal"])
X = pd.get_dummies(frame["periode"])[["oos", "post"]].astype(float)
if extra is not None:
X = X.join(extra)
X = X.apply(within, groups=frame["signal"])
coef, *_ = np.linalg.lstsq(X.to_numpy(), y.to_numpy(), rcond=None)
resid = y.to_numpy() - X.to_numpy() @ coef
bread = np.linalg.inv(X.T.to_numpy() @ X.to_numpy())
scores = pd.DataFrame(X.to_numpy() * resid[:, None]).groupby(frame["date"].to_numpy()).sum().to_numpy()
se = np.sqrt(np.diag(bread @ scores.T @ scores @ bread))
return pd.DataFrame({"coef (% p.m.)": coef, "SE (cluster maand)": se, "t": coef / se}, index=X.columns)
mp = mp_regression(long).loc[["oos", "post"]]
in_sample_mean = 100 * means["in-sample"].mean()
mp["t.o.v. gem. steekproef"] = mp["coef (% p.m.)"] / in_sample_mean
publication_effect = mp.loc["post", "coef (% p.m.)"] - mp.loc["oos", "coef (% p.m.)"]
mp.loc["publicatie-effect (verschil)"] = [publication_effect, np.nan, np.nan, publication_effect / in_sample_mean]
mp.rename(index=PERIOD_NAMES).round(3)
Loading...
Volgens de regressie ligt het rendement in de tussenperiode 36% en na publicatie 54% onder
het gemiddelde in de steekproef, beide ruim significant, zodat het publicatie-effect 18%
is. Omdat de regressie signalen naar hun aantal maanden weegt, wijkt ze iets
af van de gewone gemiddelden. De daling na publicatie is vergelijkbaar met die van McLean
en Pontiff, maar bij ons ligt meer ervan al vóór publicatie.
6.2De verdeling van t-waarden en de drempels van Harvey, Liu en Zhu¶
Hoeveel signalen halen de strengere drempels? De cel past de zes procedures uit het
toy-voorbeeld toe op onze t-waarden in de steekproef en na publicatie, en vergelijkt die
met de t-waarden in de artikelen.
t_values = (means / se_means)
tests = {period: multiple_testing(t_values[period].dropna()).sum()
for period in ["in-sample", "post"]}
threshold_table = pd.DataFrame(tests).rename(index={"naief": "naief |t| > 1.96"})
threshold_table.loc["aantal signalen"] = [t_values[p].notna().sum() for p in ["in-sample", "post"]]
M = int(t_values["in-sample"].notna().sum())
print(f"Bonferroni-drempel bij M = {M}: |t| > {stats.norm.isf(0.025 / M):.2f}; "
f"c(M) = {np.sum(1 / np.arange(1, M + 1)):.2f}")
reported = doc["T-Stat"].reindex(t_values.index)
both = reported.notna()
t_ours = t_values.loc[both, "in-sample"]
rank_corr = stats.spearmanr(reported[both], t_ours)[0]
print(f"gerapporteerde t in het artikel beschikbaar voor {both.sum()} signalen; "
f"rangcorrelatie met onze t in de steekproef: {rank_corr:.2f}; "
f"aandeel van onze t in de steekproef > 1.96 onder deze signalen: {np.mean(t_ours > 1.96):.2f}")
threshold_table.rename(columns=PERIOD_NAMES)
Bonferroni-drempel bij M = 212: |t| > 3.68; c(M) = 5.94
gerapporteerde t in het artikel beschikbaar voor 188 signalen; rangcorrelatie met onze t in de steekproef: 0.62; aandeel van onze t in de steekproef > 1.96 onder deze signalen: 0.88
Loading...
In de steekproef halen 186 van de 212 signalen ∣t∣>1,96, dus 88%. Voor de 188
signalen met een gerapporteerde t is de rangcorrelatie met onze t 0,62, zodat de
replicatie in de oorspronkelijke constructie grotendeels werkt. De 65% mislukkingen van
Hou, Xue en Zhang zijn daarmee niet in tegenspraak, omdat zij naar marktwaarde wogen met
NYSE-breekpunten. De drempels van Harvey, Liu en Zhu schrappen wel een flink deel. Bij
t>3 vallen 64 van de 186 significante signalen af, en Bonferroni, met ∣t∣>3,68 bij
M=212, houdt er 85 over. In de figuur is links te zien hoe de verdeling langs de
drempels verschuift. Rechts gaat het om de helling van de puntenwolk, die onder één ligt
als sterke signalen meer verliezen.
Source
fig, axes = plt.subplots(1, 2, figsize=(11, 4.3))
bins = np.linspace(-4, 15, 58)
axes[0].hist(t_values["in-sample"], bins=bins, alpha=0.6, label="in de steekproef")
axes[0].hist(t_values["post"], bins=bins, alpha=0.6, label="na publicatie")
for value, style, text in ((1.96, ":", "1,96"), (3.0, "--", "3,0"), (stats.norm.isf(0.025 / M), "-", "Bonferroni")):
axes[0].axvline(value, color="black", lw=0.9, ls=style, label=f"drempel {text}")
axes[0].set_title("(a) t-waarden van 212 gepubliceerde signalen")
axes[0].set_xlabel("t-waarde van het gemiddelde long-short-rendement")
axes[0].set_ylabel("Aantal signalen")
axes[0].legend()
ok = means[["in-sample", "post"]].dropna()
axes[1].scatter(100 * ok["in-sample"], 100 * ok["post"], s=12, alpha=0.7)
lims = np.array([-0.5, 3.0])
axes[1].plot(lims, lims, color="black", lw=0.8, label="45 graden: geen verzwakking")
slope, intercept = np.polyfit(100 * ok["in-sample"], 100 * ok["post"], 1)
axes[1].plot(lims, intercept + slope * lims, color=hap.plotting.COLORS[1],
label=f"OLS: helling {slope:.2f}".replace(".", ","))
axes[1].axhline(0, color="grey", lw=0.6)
axes[1].set_title("(b) Rendement per signaal, in de steekproef en na publicatie")
axes[1].set_xlabel("Gemiddelde in de steekproef (% per maand)")
axes[1].set_ylabel("Gemiddelde na publicatie (% per maand)")
axes[1].legend()
fig.tight_layout()
plt.show()
Figure 2:Links liggen de t-waarden in de steekproef ver rechts van elke drempel. Na publicatie is de verdeling naar links geschoven en haalt nog maar een klein deel de Bonferroni-drempel. Rechts blijven signalen die in de steekproef sterk waren gemiddeld
de sterkste, maar met een helling van 0,61 verliezen ze meer naarmate hun rendement in de
steekproef hoger was. De puntenwolk ligt gemiddeld ruim onder de 45-gradenlijn.
Na publicatie halen nog 66 van de 212 signalen ∣t∣>1,96 en 11 de Bonferroni-drempel.
Die daling komt deels doordat de periode na publicatie korter is dan de steekproef, zodat
dezelfde premie een kleinere t geeft.
6.3Shrinkage: hoeveel van de daling is statistiek?¶
Shrinkage voorspelt hooguit 7 tot 9% van de daling in de tussenperiode, tegen 40%
waargenomen, zoals de twee schattingen hieronder laten zien. De eerste trekt de gemiddelden
in de steekproef terug met een prior gecentreerd op nul, zoals bij Jensen, Kelly en
Pedersen. Een willekeurig signaal levert dan gemiddeld niets op, en de factor zoo bepaalt
hoe breed de premies verdeeld zijn.
def empirical_bayes(estimate, se, zero_mean=False):
"""Normal-normal empirical Bayes: posterior means and sds with the prior estimated by moments."""
# TODO: naar hap.stats (empirical Bayes shrinkage)
mu = 0.0 if zero_mean else float(np.mean(estimate))
tau2 = max(float(np.mean((estimate - mu) ** 2) - np.mean(se**2)), 0.0)
weight = tau2 / (tau2 + se**2)
return mu + weight * (estimate - mu), np.sqrt(weight) * se, mu, np.sqrt(tau2)
est, se_in = means["in-sample"].to_numpy(), se_means["in-sample"].to_numpy()
post_mean, post_sd, _, tau_hat = empirical_bayes(est, se_in, zero_mean=True)
shrink = pd.DataFrame({"ruw": est, "EB": post_mean, "SE ruw": se_in, "SD posterior": post_sd,
"na publicatie": means["post"].to_numpy()}, index=means.index)
survive = pd.Series({
"tau (% p.m.)": 100 * tau_hat,
"gem. krimpfactor": np.mean(tau_hat**2 / (tau_hat**2 + se_in**2)),
"ruw: t > 1.96": np.sum(est / se_in > 1.96),
"EB: posterior gem./SD > 1.96": np.sum(post_mean / post_sd > 1.96),
"voorspelde daling door shrinkage": 1 - post_mean.mean() / est.mean(),
"helling na publicatie op ruw": np.polyfit(shrink["ruw"], shrink["na publicatie"], 1)[0],
"helling na publicatie op EB": np.polyfit(shrink["EB"], shrink["na publicatie"], 1)[0],
})
survive.round(3)
tau (% p.m.) 0.799
gem. krimpfactor 0.935
ruw: t > 1.96 186.000
EB: posterior gem./SD > 1.96 181.000
voorspelde daling door shrinkage 0.089
helling na publicatie op ruw 0.605
helling na publicatie op EB 0.609
dtype: float64
De geschatte spreiding van premies is τ^=0,80% per maand, tegen een gemiddelde
standaardfout van 0,19%. De krimpfactor is daardoor gemiddeld 0,94, en het gemiddelde
rendement over alle signalen krimpt met 9%. Van de 186 significante signalen blijven er
181 over. Deze prior is echter op
gepubliceerde signalen geschat en daardoor te optimistisch
(Corollary 1). Een tweede schatting neemt de selectie expliciet
mee. Stel dat de ware verwachte t-waarden verdeeld zijn als
δi∼N(μδ,ω2) en dat alleen ti>1,96 werd
gepubliceerd. Omdat ti=δi+zi met onafhankelijke standaardnormale ruis zi,
is de gerapporteerde ti dan afgeknot normaal met variantie 1+ω2. Zo kunnen we
(μδ,ω) met maximale aannemelijkheid schatten, en
Theorem 4 geeft de verwachte δi.
signalen met gerapporteerde t > 1.96 183
gem. gerapporteerde t 4.685
mu_delta -7.355
omega 6.131
gem. E[delta | t] 4.373
voorspelde daling door selectie 0.067
waargenomen daling tussenperiode 0.405
waargenomen daling na publicatie 0.571
convergentie 1
dtype: object
De 183 gerapporteerde t-waarden boven 1,96 liggen gemiddeld op 4,69, en de geschatte
verdeling van ware t-waarden heeft μ^δ=−7,4 en ω^=6,1.
Een willekeurig geprobeerd signaal zou daarmee met kans Φ(7,4/6,1)≈0,89
een negatieve premie hebben. Dat is
ongeloofwaardig, want onderzoekers kiezen het teken zelf en zouden zo’n signaal omdraaien.
Deze uitkomst laat vooral zien hoe weinig een afgeknotte steekproef over de ligging van de
verdeling zegt. Voor de posterior telt het gewicht ω^2/(1+ω^2)=0,97,
zodat de
verwachte ware t gemiddeld 4,37 is en selectie een daling van 7% voorspelt. Bij gelijke
standaardfout daalt het gemiddelde rendement relatief even veel als t, zodat die 7% met
de waargenomen
dalingen te vergelijken is.
Beide benaderingen blijven dus ver onder de 40%, terwijl de intuïtie die daling juist aan
statistiek toeschreef. Volgens de simulatie vereist al de 26% van McLean en Pontiff ware
t-waarden rond 2,1, en de 40% hier nog zwakkere, maar de echte signalen zijn veel
sterker. Er blijven drie
verklaringen over.
De gerapporteerde t-waarden zijn sterker opgeblazen dan afknotting beschrijft, omdat
onderzoekers ook varianten probeerden die ze nooit publiceerden.
De tussenperiode bevat al arbitrage op werkdocumenten.
Anomalierendementen dalen in het algemeen door de tijd, wat de derde oefening onderzoekt.
Als een handvol factoren de factor zoo samenvat, moeten de alpha’s van de signalen ten
opzichte van FF5 plus momentum klein zijn, ook na publicatie. De cel regresseert elk
signaal op FF5 plus momentum,
over 1963–2024 en alleen na publicatie, en telt de significante alpha’s per procedure.
factors = hap_data.french("F-F_Research_Data_5_Factors_2x3").join(hap_data.french("F-F_Momentum_Factor"))
factor_cols = ["Mkt-RF", "SMB", "HML", "RMW", "CMA", "Mom"]
sample = osap.index.intersection(factors.dropna().index)
R_ls, F_six = osap.loc[sample], factors.loc[sample, factor_cols].to_numpy()
def alpha_tstat(y, F):
"""OLS intercept and homoskedastic t-statistic of y on F, dropping missing months of y."""
ok = ~np.isnan(y)
X = np.column_stack([np.ones(ok.sum()), F[ok]])
coef, *_ = np.linalg.lstsq(X, y[ok], rcond=None)
resid = y[ok] - X @ coef
se = np.sqrt(resid @ resid / (ok.sum() - X.shape[1]) * np.linalg.inv(X.T @ X)[0, 0])
return coef[0], coef[0] / se
pub_year = doc.loc[R_ls.columns, "Year"].to_numpy()
# True where the month (row) lies after the publication year of the signal (column)
after_pub = pd.DataFrame(sample.year.to_numpy()[:, None] > pub_year[None, :],
index=sample, columns=R_ls.columns)
alphas = {}
for name, frame in {"1963-2024": R_ls, "na publicatie": R_ls.where(after_pub)}.items():
values = np.array([alpha_tstat(frame[s].to_numpy(dtype=float), F_six) for s in frame.columns])
alphas[name] = pd.DataFrame(values, index=frame.columns, columns=["alpha", "t"])
alpha_tests = {}
for name, a in alphas.items():
rejected = multiple_testing(a["t"]).set_index(a.index)
alpha_tests[name] = rejected.sum()
alpha_tests[f"{name}, alpha > 0"] = rejected[a["alpha"] > 0].sum()
alpha_table = pd.DataFrame(alpha_tests)
alpha_table.loc["gem. alpha (% p.m.)"] = [100 * alphas[k.split(",")[0]]["alpha"].mean() for k in alpha_table.columns]
alpha_table.round(3)
Loading...
Over 1963–2024 hebben 167 van de 212 signalen een significante alpha, bijna allemaal
positief, met een gemiddelde van 0,42% per maand. Na correctie blijft bij Bonferroni minder
dan de helft over, maar bij BHY en BH houdt een meerderheid een significante alpha, anders
dan we vooraf verwachtten.
Daarvoor zijn drie redenen.
De periode 1963–2024 bevat de jaren in de steekproef waarop de signalen zijn
geselecteerd.
Veel portefeuilles zijn gelijkgewogen en leunen op kleine aandelen, die de
waardegewogen factoren slecht bereiken.
B/M, winstgevendheid en momentum zitten zelf in de factor zoo.
Na publicatie blijft bij elke correctie een minderheid over, van 10 bij Bonferroni tot 62
bij BH, tegen 90 zonder correctie. De gemiddelde alpha na publicatie is met 0,30% per
maand gelijk aan het ruwe
rendement, zodat de zes factoren niet verklaren wat er na publicatie over is.
De tabel zet de gepubliceerde getallen naast de onze. De daling na publicatie komt bijna
precies terug, maar bij ons valt meer ervan in de tussenperiode en mislukken veel minder
signalen dan bij Hou, Xue en Zhang.
grootheid
origineel
hier
daling in de tussenperiode
26%
40% (regressie 36%)
daling na publicatie
58%
57% (regressie 54%)
publicatie-effect
32%
18%
aandeel zonder ∣t∣≥1,96
65% van 452 (Hou, Xue en Zhang)
12% van 212
Bonferroni-drempel
3,78 bij 316 factoren
3,68 bij 212 signalen
De replicatie is gedeeltelijk geslaagd. De volgorde van hoog naar laag komt terug, met een
positief rendement na publicatie, maar het publicatie-effect is kleiner. Over de hele
periode houdt bij BH en BHY een meerderheid een significante alpha. Pas na publicatie
krimpt het aantal signalen met een alpha tot de verwachte minderheid.
Wat het kader verklaart. Na meervoudig toetsen, publicatieselectie en shrinkage
hangt het antwoord op de vraag of een signaal significant is af van het aantal pogingen.
Dat antwoord is streng maar niet vernietigend, want 88% van de 212
signalen haalt in de oorspronkelijke constructie ∣t∣>1,96 en BHY houdt er 137
over. De replicatiecrisis is dus grotendeels een verschil in weging en drempels, zoals
Chen en Zimmermann en Jensen, Kelly en Pedersen betoogden. Vijf of zes factoren uit de
boekhouding van de onderneming verklaren daarnaast een deel van de cross-sectie, al
houden de meeste signalen tegen die factoren een alpha.
Waar het breekt. Het kader breekt bij de verzwakking. In onze replicatie ligt het
rendement na publicatie 57% onder dat in de steekproef, en halen nog 11 van de 212
signalen de Bonferroni-drempel. Beide shrinkage-benaderingen
schrijven hoogstens 7 tot 9 van die 57 procentpunten aan publicatieselectie toe, en de zes
factoren verklaren het rendement na publicatie niet. Het kader zegt hoeveel we moeten
wantrouwen,
maar niet waarom de premies kleiner worden.
Risico of vergissing? McLean en Pontiff concludeerden zelf dat beleggers uit
wetenschappelijke publicaties over mispricing leren McLean & Pontiff (2016). Dat is de
Yale-lezing, maar even goed past de Chicago-lezing, waarin kenmerken blootstelling aan
risico meten. Zodra meer kapitaal via factorfondsen dat risico wil dragen, daalt de prijs
ervan, zodat een lagere premie betere risicodeling betekent. De derde lezing is
datamining, waarin er nooit iets was. Een daling die precies op de publicatiedatum valt,
zou de lezingen kunnen scheiden. In onze data is die echter niet te onderscheiden van een
algemene daling door de tijd, die zelf arbitrage of risicodeling kan zijn. Een belegger
die in 2015 een factorfonds kocht, betaalde dus voor risico of voor een vermeend inzicht,
en de data zeggen niet waarvoor. Santa-Clara vat het samen in het motto uit Opzet, data en conventies.
Everything I made that lasted came from bearing risk that was priced. Everything I lost
came from thinking I knew something the price did not. Santa-Clara (2026)
Wat er daarna kwam. Bevatten honderden ruisige signalen elk wat informatie, dan ligt
het voor de hand ze door een machine te laten combineren, zoals in
Machine learning in de cross-sectie.
(1) De grens wordt 0,05/20=0,0025, wat overeenkomt met ∣t∣>3,02, zodat
alleen A overblijft. (2) Holm vergelijkt B met 0,05/19=0,00263 en stopt, dus ook
Holm vindt alleen A. Benjamini-Hochberg vergelijkt rang j met 0,0025j. C haalt
0,00693≤0,0075, maar D mist 0,0100 en geen hogere rang haalt zijn grens, zodat
A, B en C overblijven. De code rekent het na.
extra_nulls = pd.Series(np.linspace(-0.9, 0.9, 10), index=[f"N{k}" for k in range(1, 11)])
t_twenty = pd.concat([t_toy, extra_nulls])
twenty_tests = multiple_testing(t_twenty).set_index(t_twenty.index)
found_twenty = {col: "".join(twenty_tests.index[twenty_tests[col]]) for col in twenty_tests}
print(f"Bonferroni-drempel bij M = 20: |t| > {stats.norm.isf(0.025 / 20):.3f}")
pd.DataFrame({"M = 10": discoveries, "M = 20": found_twenty}).rename_axis("procedure")
Bonferroni-drempel bij M = 20: |t| > 3.023
Loading...
Tien extra pogingen zonder enige inhoud kosten B de Holm-ontdekking en D de
BH-ontdekking, terwijl de naïeve toets niets merkt. Elke mislukte poging maakt de
overgebleven ontdekkingen dus minder waard, ook als niemand die poging publiceert.
daling 26%: delta = 2.097; daling 58%: delta = 1.066
daling bij delta = 4: 1.362%; lambda(x) > x op [-3, 3]: True
Een daling van 26% vereist ware verwachte t-waarden rond 2,1, en 58% waarden rond 1. Bij
δ=4 voorspelt selectie een daling van 1,4%. De 26% van McLean en Pontiff is dus
alleen statistiek als de gerapporteerde t-waarden flink zijn opgeblazen, door varianten
en specificatiekeuzes die de drempel t>2 niet vangt.
Met vaste effecten voor vijfjaarsperioden is de daling in de tussenperiode 42% van het
gemiddelde in de steekproef en na publicatie 41%, zodat het publicatie-effect van 18%
verdwijnt. De coëfficiënten worden nu alleen geïdentificeerd doordat signalen in dezelfde
vijf jaar in verschillende fasen zitten. De decompositie van McLean en Pontiff blijkt dus
gevoelig voor wat kalendertijd mag verklaren, en in onze data overschaduwt een algemene
daling van anomalierendementen de publicatiedatum.
(1) Met T jaar is μ^/(σ^/T)≈Tμ/σ. Voor
t=1,96 is T=(1,96/0,5)2=15,4 jaar, en voor t=3 is T=36 jaar.
(2) en (3) De code keert de Bonferroni-grens om.
p_378 = 2 * stats.norm.sf(3.78)
print(f"tweezijdige p bij t = 3.78: {p_378:.2e}; impliciete M = 0.05 / p = {0.05 / p_378:.0f}")
print(f"jaren voor t = 1.96, 3.00, 3.78: {[round((t / 0.5)**2, 1) for t in (1.96, 3.0, 3.78)]}")
tweezijdige p bij t = 3.78: 1.57e-04; impliciete M = 0.05 / p = 319
jaren voor t = 1.96, 3.00, 3.78: [15.4, 36.0, 57.2]
Een drempel van 3,78 komt overeen met ruim 300 toetsen, in lijn met de catalogus van 316
factoren. Een signaal met een respectabele Sharpe-ratio van 0,5 heeft dan 57 jaar data
nodig om de drempel naar verwachting te halen, bijna even lang als de Amerikaanse boekhouddata sinds 1963 bestaan. Een factor zoo en een slecht gemeten gemiddeld rendement zijn zo twee kanten van
hetzelfde probleem, want een strengere drempel beschermt tegen toeval maar maakt veel
echte premies onmeetbaar.
Cochrane, J. H. (2011). Presidential Address: Discount Rates. Journal of Finance, 66(4), 1047–1108. 10.1111/j.1540-6261.2011.01671.x
Harvey, C. R., Liu, Y., & Zhu, H. (2016). \ldots and the Cross-Section of Expected Returns. The Review of Financial Studies, 29(1), 5–68. 10.1093/rfs/hhv059
McLean, R. D., & Pontiff, J. (2016). Does Academic Research Destroy Stock Return Predictability? The Journal of Finance, 71(1), 5–32. 10.1111/jofi.12365
Hou, K., Xue, C., & Zhang, L. (2020). Replicating Anomalies. The Review of Financial Studies, 33(5), 2019–2133. 10.1093/rfs/hhy131
Chen, A. Y., & Zimmermann, T. (2022). Open Source Cross-Sectional Asset Pricing. Critical Finance Review, 11(2), 207–264. 10.1561/104.00000112
Jensen, T. I., Kelly, B., & Pedersen, L. H. (2023). Is There a Replication Crisis in Finance? The Journal of Finance, 78(5), 2465–2518. 10.1111/jofi.13249
Holm, S. (1979). A Simple Sequentially Rejective Multiple Test Procedure. Scandinavian Journal of Statistics, 6(2), 65–70. https://www.jstor.org/stable/4615733
Benjamini, Y., & Yekutieli, D. (2001). The Control of the False Discovery Rate in Multiple Testing under Dependency. The Annals of Statistics, 29(4), 1165–1188. 10.1214/aos/1013699998
Fama, E. F., & French, K. R. (2015). A Five-Factor Asset Pricing Model. Journal of Financial Economics, 116(1), 1–22. 10.1016/j.jfineco.2014.10.010
Novy-Marx, R. (2013). The Other Side of Value: The Gross Profitability Premium. Journal of Financial Economics, 108(1), 1–28. 10.1016/j.jfineco.2013.01.003
Hou, K., Xue, C., & Zhang, L. (2015). Digesting Anomalies: An Investment Approach. The Review of Financial Studies, 28(3), 650–705. 10.1093/rfs/hhu068
Feng, G., Giglio, S., & Xiu, D. (2020). Taming the Factor Zoo: A Test of New Factors. The Journal of Finance, 75(3), 1327–1370. 10.1111/jofi.12883
Novy-Marx, R., & Velikov, M. (2016). A Taxonomy of Anomalies and Their Trading Costs. The Review of Financial Studies, 29(1), 104–147. 10.1093/rfs/hhv063
Deze onafhankelijke site is niet verbonden aan of onderschreven door QuantEcon.
De vormgeving is gebaseerd op het MIT-gelicentieerde
QuantEcon MyST-thema.
Zie THIRD_PARTY_NOTICES.md voor de licentie-informatie.