diff --git a/README.md b/README.md index 7376041..e5a9725 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ Aetherius watches a list of companies. It reads new headlines and filings, decides conservatively whether each one really mentions a watched company, scores it with fixed, explainable weights, and puts only evidence-backed, adverse items in front of a human reviewer. -**Headline result.** Replayed on 161 real archived headlines from three crises (SVB 2023, Wirecard 2020, FTX 2022), it flagged **9 of 9** affected names before their formal resolution and raised **0 flags on 3 unrelated control names**. +**Headline result.** Replayed on 161 real archived headlines from three crises (SVB 2023, Wirecard 2020, FTX 2022), it flagged **9 of 9** affected names before their formal resolution. The backtest says nothing about false alarms: its control names never appear in the data ([§4.6](docs/working_paper/detection_timing_backtest_2026-07.md#46-the-control-test-was-not-exercised)). **The honest qualifier.** In **0 of 9** cases did the first flag come *before* the first headline reporting the stock already falling. The system is fast, auditable **triage** of a market reaction, not a predictor ([working paper §4.5](docs/working_paper/detection_timing_backtest_2026-07.md#45-timing-relative-to-the-market-reaction)). @@ -38,12 +38,12 @@ Aetherius watches a list of companies. It reads new headlines and filings, decid ## Results -| Event | Mechanism | Affected names flagged before resolution | Median lead to resolution | Controls flagged | First flag before market reaction | -|---|---|---|---|---|---| -| SVB-2023 | Regional-bank contagion | 5 / 5 | 2.34 days | 0 / 1 | 0 / 5 | -| Wirecard-2020 | Accounting fraud | 1 / 1 | 6.60 days | 0 / 1 | 0 / 1 | -| FTX-2022 | Crypto counterparty contagion | 3 / 3 | 7.12 days | 0 / 1 | 0 / 3 | -| **All** | | **9 / 9** (95% CI 66–100%) | 2.48 days | **0 / 3** (FP rate 95% CI 0–71%) | **0 / 9** | +| Event | Mechanism | Affected names flagged before resolution | Median lead to resolution | First flag before market reaction | +|---|---|---|---|---| +| SVB-2023 | Regional-bank contagion | 5 / 5 | 2.34 days | 0 / 5 | +| Wirecard-2020 | Accounting fraud | 1 / 1 | 6.60 days | 0 / 1 | +| FTX-2022 | Crypto counterparty contagion | 3 / 3 | 7.12 days | 0 / 3 | +| **All** | | **9 / 9** (95% CI 66–100%) | 2.48 days | **0 / 9** | "Resolution" means the formal event: receivership, insolvency filing or Chapter 11. The "market reaction" is the first headline in the corpus reporting the stock already falling ([`market_reaction_check.py`](simulations/backtest/market_reaction_check.py)). @@ -51,6 +51,7 @@ Aetherius watches a list of companies. It reads new headlines and filings, decid - **Small sample, chosen with hindsight.** There are three famous failures and nine affected names, and both the events and the adverse-term list were chosen knowing the outcomes. The confidence intervals above are wide. - **Triage, not anticipation.** Flags arrive together with the press reporting a sell-off. +- **False alarms are untested.** Each event has a control company, but none appears in its headlines, so "no control was flagged" proves nothing. The live forward test measures false alarms instead. - **Known false positives.** Tickers that are English words match ordinary text ("coin prices fall" matches `COIN`). Adverse terms match as substrings ("fall" fires inside "shortfall"). - **EDGAR adds provenance, not signal.** Filings are scored on metadata (form and date), never on the filing text. - **Whitelisted sources only.** Coverage is a fixed list of financial-news domains, which is thin for non-U.S. events. diff --git a/aetherius/app/services/reporting/target_stress_test.py b/aetherius/app/services/reporting/target_stress_test.py index dc7c492..a76f7d9 100644 --- a/aetherius/app/services/reporting/target_stress_test.py +++ b/aetherius/app/services/reporting/target_stress_test.py @@ -371,8 +371,9 @@ def _executive_summary( bullets.append( "Detection track record on structurally comparable historical events: " "9 of 9 affected names detected across SVB-2023, Wirecard-2020, and FTX-2022; " - "0 false positives on 3 unrelated controls. Flags arrived with the market's " - "reaction, not before it: lead time is measured to formal resolution, not to the price move." + "Flags arrived with the market's reaction, not before it: lead time is measured to " + "formal resolution, not to the price move. False alarms were not tested: the control " + "names never appear in the backtest corpora." ) return bullets diff --git a/aetherius/app/templates/pdf/target_stress_test.html b/aetherius/app/templates/pdf/target_stress_test.html index ea2cc62..be0a3f7 100644 --- a/aetherius/app/templates/pdf/target_stress_test.html +++ b/aetherius/app/templates/pdf/target_stress_test.html @@ -236,7 +236,7 @@

Target Stress-Test Deck

Detection track record on 3 frozen historical crises — {{ track_record.aggregate.detected_total }} of {{ track_record.aggregate.affected_total }} affected names detected - at elevated / high severity, {{ track_record.aggregate.false_positives_total }} false positives on controls. + at elevated / high severity. False alarms were not tested (control names never appear in the corpora). Flags coincided with, and did not precede, the first press report of each stock falling. Full methodology in the working paper referenced on the final page. Aetherius is an information and risk-monitoring service, not investment advice. @@ -409,7 +409,6 @@

Historical evidence on structurally comparable events

Affected Detected Median lead to resolution - FP on control @@ -419,7 +418,6 @@

Historical evidence on structurally comparable events

{{ ev.affected }} {{ ev.detected }} {{ "%.2f"|format(ev.median_lead_days) }} days - {{ ev.false_positives_on_control }} {% endfor %} @@ -427,7 +425,6 @@

Historical evidence on structurally comparable events

{{ track_record.aggregate.affected_total }} {{ track_record.aggregate.detected_total }} — - {{ track_record.aggregate.false_positives_total }} diff --git a/aetherius/tests/test_market_reaction_check.py b/aetherius/tests/test_market_reaction_check.py index 185e5b9..99b4648 100644 --- a/aetherius/tests/test_market_reaction_check.py +++ b/aetherius/tests/test_market_reaction_check.py @@ -33,3 +33,13 @@ def test_no_first_flag_precedes_the_market_reaction() -> None: assert len(rows) == 9 assert sum(1 for r in rows if r["first_flag_reports_price_move"]) == 8 assert sum(1 for r in rows if (r["flag_lead_over_reaction_hours"] or 0) > 0) == 0 + + +def test_controls_never_appear_in_the_frozen_corpora() -> None: + """Pins the paper's statement that the control test was not exercised. + + If a fixture is rebuilt so a control name does appear, this fails: update + the paper's Section 4.6 and the README before changing this test. + """ + for event in mrc.EVENTS: + assert set(mrc.control_coverage(event).values()) == {0} diff --git a/docs/assets/demo.gif b/docs/assets/demo.gif index 411f8e7..05555a0 100644 Binary files a/docs/assets/demo.gif and b/docs/assets/demo.gif differ diff --git a/docs/working_paper/detection_timing_backtest_2026-07.html b/docs/working_paper/detection_timing_backtest_2026-07.html index ec16ebe..1163199 100644 --- a/docs/working_paper/detection_timing_backtest_2026-07.html +++ b/docs/working_paper/detection_timing_backtest_2026-07.html @@ -38,15 +38,18 @@

Detection-Timing Backtest of a Deterministic Downside-Risk Screen Across Three Modern Financial Crises

-

A working paper. Revision 2, October 2026 (first version July 2026). -Author: Zarif Latif · zarif@aetheriusresearch.tech

+

A working paper. Revision 2.1, October 2026 (first version July 2026).

+

Author: Zarif Latif, independent researcher · zarif@aetheriusresearch.tech

+

Keywords: risk screening, event study, entity resolution, textual analysis, GDELT, SEC EDGAR, bank failures, backtesting

+

JEL codes: G14, G17, G21

What changed in Revision 2. Revision 1 reported that the pipeline flagged all nine affected names "before the realized event date," with a median lead of about 2.5 days. That is true, but the realized event date was the formal resolution (receivership, insolvency filing, Chapter 11), not the market's reaction. Revision 2 adds a test of timing against the first headline reporting each stock already falling (Section 4.5). Measured that way, no first flag came before the market reaction. Revision 2 also adds confidence intervals, states the hindsight selection of events and watchlists, documents two known false-positive classes, removes commercial framing, and describes a pre-registered live forward test (Section 8). Every number in this revision is reproduced by pinned tests.

+

What changed in Revision 2.1. A pre-publication check found that no control name appears in any of the three corpora, so the "0 false positives on controls" result was never actually tested. Text in Revisions 1 and 2 describing control headlines was wrong and has been removed. Section 4.6 explains what happened. Revision 2.1 also adds related work and references, and discloses that the Section 4.5 price-reaction pattern was written after the headlines had been read.


Abstract

-

We replay a deterministic entity-mapping and severity-scoring pipeline against real news headlines from three well-studied financial crises: the March 2023 U.S. regional-bank contagion, the June 2020 Wirecard AG accounting fraud and the November 2022 FTX collapse. For each affected name we report detection timing, mapping precision and behavior on unrelated control names.

-

On 161 archived observations from GDELT DOC 2.0, the pipeline flagged all 9 affected names at "elevated" or "high" severity before each name's formal resolution date, with a median lead of 2.48 days. It raised no flags on the 3 control names. With these small samples, the 95% confidence interval for recall is 66–100%, and the control false-positive rate could be anywhere from 0% to 71%.

+

We replay a deterministic entity-mapping and severity-scoring pipeline against real news headlines from three well-studied financial crises: the March 2023 U.S. regional-bank contagion, the June 2020 Wirecard AG accounting fraud and the November 2022 FTX collapse. For each affected name we report detection timing and how it compares with the market's own reaction.

+

On 161 archived observations from GDELT DOC 2.0, the pipeline flagged all 9 affected names at "elevated" or "high" severity before each name's formal resolution date, with a median lead of 2.48 days. With only nine names, the 95% confidence interval for recall is 66–100%. The study's three control names never appear in the corpus, so it provides no evidence about false positives.

The more important finding is about timing. In all 9 detections, the first flag arrived at the same time as, not before, the first headline reporting that the stock was already falling. In 8 of 9 it was that headline. The pipeline is therefore evidence of fast, auditable triage of a market reaction already underway. It is not evidence of anticipating the market. We describe the pipeline, the corpus and the ground truth, discuss the limitations, and describe a pre-registered live forward test started on 2026-10-16. All code and data are Apache-2.0 licensed and reproducible.

This is detection-timing evidence on frozen historical windows. It is not a return forecast, a trading signal, or a causal claim.


@@ -58,7 +61,9 @@

1. Motivation

  • Deterministic severity scoring. Each observation is scored against a fixed adverse-language list, so the same input always gets the same answer and every score can be audited.
  • False-positive discipline. Adverse content on names outside the book, and benign content on names inside it, should stay quiet.
  • -

    The question here is narrow: on the headlines that actually existed at the time, when would this pipeline have flagged the affected names, both relative to their formal resolution and relative to the market's own reaction, and would it have stayed quiet on unrelated controls?

    +

    The question here is narrow: on the headlines that actually existed at the time, when would this pipeline have flagged the affected names, both relative to their formal resolution and relative to the market's own reaction? False-positive behavior is the subject of the live forward test (Section 8), because this corpus cannot measure it (Section 4.6).

    + +

    Media text carries information about stock returns and firm fundamentals: pessimistic language in a daily newspaper column predicts downward pressure on market prices (Tetlock, 2007), and the share of negative words in firm-specific news predicts earnings and returns (Tetlock, Saar-Tsechansky and Macskassy, 2008). Word lists matter in finance: Loughran and McDonald (2011) show that general-purpose negative-word dictionaries misclassify many common financial terms, and build finance-specific lists from 10-K filings. This paper's adverse-term list is smaller and hand-written. Replacing it with the Loughran–McDonald negative list is a natural robustness test (Section 8). Event timing here follows the event-study idea of measuring information arrival around a dated event (Fama, Fisher, Jensen and Roll, 1969), but uses headline timestamps, not returns. The news archive is the GDELT project (Leetaru and Schrodt, 2013).


    2. Pipeline overview

    The pipeline is the production Aetherius code, unchanged for this exercise. Paths are relative to the repository root.

    @@ -84,7 +89,7 @@

    2.3 Severity scoring

    severity_label() bins risk into low, moderate, elevated or high. Every weight is a constant, and there are no learned parameters.

    2.4 Adverse-language gate

    -

    adverse_severity(raw_text) (same module) counts matches against a fixed list of about 40 downside terms (loss, plunge, withdrawals, deposit run, receivership, collapse, funding pressure, distress, insolven…, …) and maps the count to an event-severity score. An observation is a shippable flag only when its severity label is elevated or high and at least one adverse term is present. This gate, not the matcher, keeps the MSFT control quiet: MSFT headlines match MSFT directly but contain no adverse terms. Since Revision 2, the live API, the backtest and the forward test all import this single implementation.

    +

    adverse_severity(raw_text) (same module) counts matches against a fixed list of about 40 downside terms (loss, plunge, withdrawals, deposit run, receivership, collapse, funding pressure, distress, insolven…, …) and maps the count to an event-severity score. An observation is a shippable flag only when its severity label is elevated or high and at least one adverse term is present. Unit tests show the gate holding a benign direct mention below shippable severity (for example, "Microsoft expands Copilot across product suite"). The backtest corpora contain no such case for the controls (Section 4.6). Since Revision 2, the live API, the backtest and the forward test all import this single implementation.

    2.5 Backtest harness

    simulations/backtest/run_backtest.py replays each event's observations.jsonl in chronological order against its watchlist.json and ground_truth.json, records the first shippable flag per name, and computes:

    5.2 Sample size

    -

    Three events, nine affected names and three controls make a very small sample. 9/9 recall is consistent with a true recall as low as 66%, and 0/3 control false positives is consistent with a true control false-positive rate as high as 71% (exact binomial 95% intervals). One added event that failed would deserve equal reporting.

    +

    Three events and nine affected names make a very small sample. 9/9 recall is consistent with a true recall as low as 66% (exact binomial 95% interval). There is no false-positive sample at all (Section 4.6). One added event that failed would deserve equal reporting.

    5.3 Hindsight selection

    The three events, the affected names, and the decision to include each name were all chosen after the outcomes were known, from among the best-known failures of recent years. The adverse-term list was also written by people who knew how these crises unfolded, and its vocabulary ("deposit run", "receivership", "unrealized loss", "capital raise") is close to bank-run reporting. A screen tested only on famous failures cannot tell us how often it fires on companies that turned out fine. The forward test in Section 8 is designed to address this.

    5.4 Lookahead

    -

    The harness sorts observations by GDELT seendate and only counts flags strictly before the resolution date (pinned by test_time_safety_lead_time_never_negative). Regulatory anchors are inserted at a small offset from the resolution date. Removing them leaves SVB recall (5/5) and median lead (2.34 days) unchanged.

    +

    The harness sorts observations by GDELT seendate and only counts flags strictly before the resolution date (pinned by test_time_safety_lead_time_never_negative). Regulatory anchors are inserted at a small offset from the resolution date. Removing them, and keeping news headlines only, leaves recall and median lead unchanged for all three events (5/5 and 2.34 days, 1/1 and 6.60 days, 3/3 and 7.12 days).

    5.5 Known false-positive classes

    -

    What it does show is narrower: a small, deterministic, auditable pipeline running on real headlines would have put nine affected names in front of a reviewer within the same news cycle as their market reaction, ahead of formal resolution, without firing on three unrelated controls.

    +

    What it does show is narrower: a small, deterministic, auditable pipeline running on real headlines would have put nine affected names in front of a reviewer within the same news cycle as their market reaction, ahead of formal resolution. It does not show how often the screen raises false alarms.


    8. Future work

    1. Pre-registered live forward test (running since 2026-10-16). simulations/forward_test/ fixes a 20-name, all-normal-priority watchlist chosen for coverage rather than expected distress, and commits its hash. A daily GitHub Action scores live GDELT news and SEC filings with the frozen backtest scorer and appends timestamped rows to the forward-test-log branch. The planned report covers alerts per name per week, human-labeled precision, and the stock's 5-session return before and after each flag.
    2. Rule-based event selection. Choose events by a rule fixed in advance (for example, every listed U.S. bank failure on the FDIC list in a period, or every S&P 500 constituent with a ≥50% drawdown in a year) instead of by fame.
    3. +
    4. Real controls. Rebuild each fixture with control headlines that actually name the control company, ideally many controls per event chosen by a rule (for example, every same-sector name that did not fail), and report false positives with confidence intervals.
    5. +
    6. Finance-specific word lists. Re-run with the Loughran and McDonald (2011) negative list in place of the hand-written adverse terms.
    7. Price-anchored evaluation. Measure timing against the first ≥10% close-to-close decline, using price data, not headlines.
    8. Matcher fixes. Use case-sensitive ticker matching or require a cashtag for ticker-word symbols, and add whole-word adverse terms. These would be evaluated as a new model version, with the frozen version kept for comparison.
    9. Filing text. Score 8-K item text (for example, Item 2.06 impairments or Item 4.02 non-reliance) instead of metadata.

    +

    References

    +

    Clopper, C. J., and Pearson, E. S. (1934). The use of confidence or fiducial limits illustrated in the case of the binomial. Biometrika, 26(4), 404–413.

    +

    Fama, E. F., Fisher, L., Jensen, M. C., and Roll, R. (1969). The adjustment of stock prices to new information. International Economic Review, 10(1), 1–21.

    +

    Leetaru, K., and Schrodt, P. A. (2013). GDELT: Global data on events, location, and tone, 1979–2012. Paper presented at the International Studies Association Annual Convention.

    +

    Loughran, T., and McDonald, B. (2011). When is a liability not a liability? Textual analysis, dictionaries, and 10-Ks. Journal of Finance, 66(1), 35–65.

    +

    Tetlock, P. C. (2007). Giving content to investor sentiment: The role of media in the stock market. Journal of Finance, 62(3), 1139–1168.

    +

    Tetlock, P. C., Saar-Tsechansky, M., and Macskassy, S. (2008). More than words: Quantifying language to measure firms' fundamentals. Journal of Finance, 63(3), 1437–1467.

    +

    Appendix A — Watchlists

    Full JSON lives at simulations/backtest/events/<event-id>/watchlist.json.

    +

    Controls are listed for completeness; none appears in its corpus (Section 4.6).