Tradability Analysis: Entry, Hold, Exit

Market Synthesis is validated on detection accuracy. Whether a fund manager could profit from these signals is a second, much harder question, and this page now documents why the answer is not yet demonstrated.

This page describes the trading algorithm derived from backtesting 303 signals (2014-2026) against real market data via yfinance, using an adversarial LLM-based exit system. The algorithm is real and runs in paper trading. Its edge is not established.

Correction (2026-08-25): the exit system does not beat a random exit

This page previously led with “Key Finding: Adversarial Exit Beats Mechanical Rules” — mean P&L +7.98% against +4.86% for a fixed hold, and an estimated ~22% p.a. That comparison was not a control, and the claim is withdrawn.

Beating a fixed hold is the wrong test. A debate that exits early to cut a loss beats a fixed hold partly by having a stop, which says nothing about whether it picked a good day. The control that answers the actual question is:

given that a trade was exited on day D, is D better than a random day drawn from the same distribution of realised exit days?

That arm was run on 2026-08-25 over 116 trades, recomputed from the price cache:

Exit policy Median return Win rate
Adversarial debate exit +8.44% 70.7%
Random exit, same day distribution +9.67% 78.4%

Edge: −1.23pp. Only 2 of 5 categories with n≥8 beat their own random-exit control. Across the full available range of exit days, the debate captured 34% of the span between the best and worst achievable exit; a random exit captured 37%.

The debate’s exit timing is not adding information. The per-category “alpha vs hold” table that stood here is a comparison against the weaker alternative and has been removed rather than annotated.

Six other execution-layer claims have failed their own controls (base-rate and date-shift placebo tests), including a withdrawn 24.5% CAGR portfolio simulation, the commodity strangle (39.3% win rate against a 50.6% base rate), and the central-bank strangle (0 wins in 16). The detection results elsewhere on this site are unaffected — they are measured against labelled outcomes, not P&L.

What this does not change: detection precision holds ~0.75 out of sample across 12 years and five macro regimes with no look-ahead, and commodity detection reads 0.974 precision on 39 signals. The signal is real. Converting it into return is the open problem.

Entry Timing Algorithm

Entry timing is category-specific. Fast-repricing events need immediate entry; slow-building events benefit from confirmation.

graph TD DETECT["🔍 Event Detected
Score ≥ 70"] --> ROUTE{"Category?"} ROUTE -->|"central_bank
currency_peg
geopolitical
real_estate"| IMM["⚡ IMMEDIATE ENTRY
Next market open"] ROUTE -->|"sovereign_debt"| MOM["📈 MOMENTUM CONFIRM
Wait for 2 consecutive
favorable-direction days"] ROUTE -->|"commodity"| WAIT["⏳ WAIT 3 DAYS
Let initial volatility
settle"] IMM --> SIZE["Position Size
Score 90+ → 100%
Score 80-89 → 75%
Score 70-79 → 50%"] MOM --> SIZE WAIT --> SIZE SIZE --> STOP["Set Stop-Loss
(category-specific)"] style DETECT fill:#1d4ed8,stroke:#153ca8,color:#ffffff style ROUTE fill:#f0f9ff,stroke:#0284c7,color:#0c4a6e style IMM fill:#dcfce7,stroke:#16a34a,color:#14532d style MOM fill:#fef3c7,stroke:#d97706,color:#78350f style WAIT fill:#fee2e2,stroke:#dc2626,color:#7f1d1d style SIZE fill:#e0e7ff,stroke:#4f46e5,color:#312e81 style STOP fill:#f8fafc,stroke:#94a3b8,color:#0f2b57

Category-specific entry timing — derived from backtest of 4 strategies on each category

Entry Rules by Category

Category Entry Trigger Rationale Backtested Win Rate
Sovereign Debt 2 consecutive favorable days Counter-move (disbelief rally) common in first 1-5 days; momentum confirmation filters false starts 75% (vs 64% immediate)
Central Bank Immediate (day 0) Shock reprices markets in hours. Waiting 3 days = -3.7% avg (move already done) 57%
Commodity Wait 3 days Extreme initial volatility (-10.7% DD). After 3 days, dust settles, DD drops to -5.3% 40%
Geopolitical Immediate (day 0) Crisis escalates from detection. Small drawdown (-2.7%). Delay = worse 50%
Real Estate Immediate (day 0) Slow grind; entry timing matters less than exit timing 33%
Currency Peg Immediate (day 0) Peak at day 6. Any delay loses the entire move 33%

What Does NOT Help for Entry Timing

Tested and rejected:

Position Management Algorithm

graph TD ENTRY["📍 ENTRY
Set initial stop-loss"] --> D5{"Day 5:
Profitable?"} D5 -->|"Yes"| TIGHT["Tighten stop
to breakeven"] D5 -->|"No"| HOLD1["Hold with
original stop"] TIGHT --> SIG1{"First exit
signal?"} HOLD1 --> SIG1 SIG1 -->|"Yes"| RED1["Reduce 30%
of position"] SIG1 -->|"No"| PEAK{"Peak day
reached?"} RED1 --> CLUST{"Signal
cluster?
(2+ signals
in 3 days)"} CLUST -->|"Yes"| RED2["Reduce another
30%"] CLUST -->|"No"| PEAK RED2 --> PEAK PEAK -->|"Yes"| CLOSE["CLOSE
remaining position"] PEAK -->|"No"| SIG1 style ENTRY fill:#1d4ed8,stroke:#153ca8,color:#ffffff style D5 fill:#fef3c7,stroke:#d97706,color:#78350f style TIGHT fill:#dcfce7,stroke:#16a34a,color:#14532d style HOLD1 fill:#f8fafc,stroke:#94a3b8,color:#0f2b57 style SIG1 fill:#fef3c7,stroke:#d97706,color:#78350f style RED1 fill:#fee2e2,stroke:#dc2626,color:#7f1d1d style CLUST fill:#fef3c7,stroke:#d97706,color:#78350f style RED2 fill:#fee2e2,stroke:#dc2626,color:#7f1d1d style PEAK fill:#e0e7ff,stroke:#4f46e5,color:#312e81 style CLOSE fill:#7f1d1d,stroke:#450a0a,color:#ffffff

Position management: time-based exit with headline-driven partial profit-taking

Category Parameters

Category Stop-Loss Peak Day Hold Period Reward:Risk
Sovereign Debt -6% Day 25 3-4 weeks 2.1:1
Commodity -7% Day 29 3-4 weeks 2.9:1
Central Bank -7% Day 19 2-3 weeks 1.7:1
Geopolitical -5% Day 22 3 weeks 2.5:1
Real Estate -8% Day 18 2-3 weeks 0.8:1
Currency Peg -6% Day 6 1 week 0.8:1

Adversarial Exit System

The exit system is an LLM-based weekly check that asks: “is the narrative-reality gap that justified this trade still open?”

graph TD ENTRY["📍 Position Entered"] --> WEEK{"Weekly Check:
Gap still open?"} WEEK -->|"gap_still_open"| HOLD["Hold Position
(check again next week)"] WEEK -->|"gap_closed / reversed"| EXIT["Exit Position"] HOLD --> WEEK STOP{"Stop-loss hit?
(per-category threshold)"} -->|"Yes"| FORCE["Force Exit"] ENTRY --> STOP style ENTRY fill:#1d4ed8,stroke:#153ca8,color:#ffffff style WEEK fill:#fef3c7,stroke:#d97706,color:#78350f style HOLD fill:#dcfce7,stroke:#16a34a,color:#14532d style EXIT fill:#fee2e2,stroke:#dc2626,color:#7f1d1d style STOP fill:#f8fafc,stroke:#94a3b8,color:#0f2b57 style FORCE fill:#7f1d1d,stroke:#450a0a,color:#ffffff

Adversarial exit: LLM weekly check replaces mechanical time-based exits

How it works

Each week, the exit detector receives:

  1. The original signal (thesis, category, direction, gap summary)
  2. Current news headlines from that week
  3. Current price data for the instrument

It then decides whether the gap is still exploitable. This produces two key behaviors:

Exit verdict distribution (303 signals)

Verdict Count Meaning
gap_still_open 258 Held to maturity — gap persisted
stop_loss 45 Exited early on stop-loss or gap closure

The rationale for adversarial exit — and what testing it showed

The design argument was that mechanical exits (fixed hold + stop-loss) fail in two ways:

  1. Exit too early on winners where the thesis is still playing out (commodity supply disruptions can last months)
  2. Exit too late on losers where the gap has already closed (central bank successfully defended)

An LLM exit check should solve both, because it reasons about whether the thesis is still valid rather than only whether price moved.

Measured, it does not. Against a random exit drawn from the same distribution of realised exit days, the debate exit is 1.23pp worse on median return (see the correction at the top of this page). The reasoning is plausible and the mechanism does fire — 45 of 303 signals exited early — but the days it chooses are not better than chance. The argument above is why the system was built this way, not evidence that it works.

Instrument Selection

The system uses a 3-layer instrument selector:

  1. Disk cache — previously validated ticker assignments (living map, updated as results come in)
  2. Static registry — category × region → default instruments (e.g., sovereign_debt + Europe → EUFN, TLT)
  3. LLM fallback — Sonnet adjudicates the best tradeable expression for novel signals, with regression testing before cache update

Category instruments

Category Primary Instruments
Commodity CL=F (WTI), BZ=F (Brent), NG=F (Nat Gas)
Currency Peg USDRUB=X, USDTRY=X, USDBRL=X, USDCNY=X
Sovereign Debt TLT, EMB, IGLT.L, DX-Y.NYB
Geopolitical GC=F (Gold), EWZ, country ETFs
Central Bank FX pairs, TLT, IEF
Real Estate VNQ, GBPUSD=X, country ETFs

The per-category “avg P&L” column that stood here (commodity +32.8%, currency peg +16.8%, and so on) is the same uncontrolled exit-vs-hold measurement corrected at the top of this page, so it has been removed rather than restated. Each of those figures is an average against no null; where a base rate has since been computed, the edge disappeared — the commodity strangle reads 39.3% win rate against a 50.6% base rate.

Implementation

The adversarial exit backtest is implemented in tests/backtest_adversarial_exit.py:

# Run the full backtest
python -u tests/backtest_adversarial_exit.py --workers 5 --label v10

# Key components:
# - Adversarial exit detector: detectors/adversarial_exit_detector.py
# - Instrument selector: shared/instrument_selector.py (3-layer with cache)
# - Signal store: shared/signal_store.py (635 signals, append-only)

The entry timing algorithm is implemented in shared/entry_timing.py:

from shared.entry_timing import get_entry_recommendation

rec = get_entry_recommendation(
    category="sovereign_debt",
    score=85,
    direction="short",
    pre_move_pct=0.0,
)

# Returns: EntryRecommendation(
#   entry_type="momentum_confirm",
#   momentum_days=2,
#   stop_loss_pct=-6.0,
#   position_size=0.75,
#   hold_days=23,
#   peak_day=25,
# )

All metrics derived from feed-driven backtest on real news data (2014-2026), validated against yfinance market prices. 303 signals backtested with adversarial LLM exit system. No hand-crafted test events.