# EN.1 twtest: one ruler for every test (DC Engine)

## READ THIS FIRST
- 7 Oct 11:31 Bangkok, **v1.4**. New since v1.1:
  - **Chain clock is the default** (lesson 19). The $250k time and the alumni $1M time now come from the chain, not the launch file. On the chain clock Lane F is dead (15 picks, A -$17 | B -$57 a day at $100), matching A2's KILL. Old behaviour: `TW_T250=launch TW_ALUMNI=launch`.
  - **EN.3 feature store:** every feature frozen per coin per stage (T1 at +0, +15 min, +1 h, +4 h; ALL; T4; T4_6h), labels kept in a separate table. Tests read the store: about 4 s instead of 20 s. Analysts add columns by dropping `/opt/tw/engine/data/fs/cols/<name>.csv` (token, universe, stage, new columns); they show up as `x_<name>_<col>`.
  - **Continuous labels on every run:** $ per trade, median best multiple in the horizon, share reaching 2x, plus `max_mult`, `min_mult`, `t_max_min`, `pulled_h` per trade in `--trades`.
  - **EN.4 nightly loop:** cron 00:15 Bangkok on research-box (`/etc/cron.d/tw-engine`, flock + timeout 2 h + nice + ionice). Rebuilds tape and store, reruns every rule file with a dc-prereg.md line (KILL lines skipped), backtest halves plus a forward half from the prereg day, flags TURNED NEGATIVE, GO-LIVE CANDIDATE, and LIVE CANDIDATE (3 net-positive forward days in a row). Output: `/opt/tw/engine/pub/flags.md` and `nightly.csv`.
  - **SCAN rules:** a rule can fire at the FIRST trade where a condition holds (`UNIVERSE = "SCAN"`, `def fire(a)` over per-trade arrays: dip, net15, net1h, net6h, buy1h, age_s, cap). Random baseline for SCAN rules = random entry times on the same coins. `--horizon 15m` gives the T15 exit.
  - KILLED rules print `prereg: KILLED in dc-prereg.md`.
- **Limit that blocks the loop's last step:** research-box cannot write to the main public folder (no key), so flags.md and nightly.csv stay on research-box until someone copies them. See Needs Ben in the status.
- EN.5 result (A4 rules): http://159.223.88.168/hx-c9ois/dc/dc-en-5-an4.md

## Earlier (v1.1, 11:05)
- 7 Oct 11:05 Bangkok, v1.1. **The engine now runs on research-box (server rules), moved off thirdwindow.** One command, about 20 s a test.
- **Job 1: A2 vs Auditor on Lane F.** Same idea, three numbers. Engine reruns all of them from the same tape:

| Setup (5x, 7 d, no cluster, $500, 30 s fill) | A $/day | B $/day | Beat random A \| B |
|---|---|---|---|
| A2 v3 (look at T1) | +2,020 | +1,263 | 100% \| 98% |
| **Engine, A2's v3 features** | **+1,676** | **+1,204** | 100% \| 98.5% |
| Engine, its own features | +1,398 | +1,470 | 99.9% \| 99.2% |
| Auditor (look at T1) | | +503 | \| 84% |
| Look at T1 + 30 s, fill 20 s later: A2 / Auditor / **engine** | +285 / +931 / **+933** | +870 / +1,209 / **+822** | engine 99.5% \| 97.2% |

- **Where the A2 gap comes from (half A, -$272 a day, 3 lines):**
  1. **VIBE `0xf521fb86607de90dbf1fb1ce79f107b0461ba7f1`**: A2 counts a 5x hit that came AFTER the pool was pulled (trading restarted later). A2's hit check has no pull filter (`hit = fut & sellable & px >= 5x`). The ruler says pull = 0. Engine: -$500, A2: +$1,924. **-$346 a day.**
  2. **Dynamic fee coins (AGNTS x2):** A2 reads v4 fee 8388608 as 8.39 (839%). That flag means "hook sets the fee". Engine uses 1%. **+$116 a day for the engine.**
  3. **Depth:** A2's reserve estimator also counts buy then sell pairs, so it sees deeper pools (about 1.5 to 2x). About **-$5 per hit**, -$40 a day.
- **The Auditor's +$503 does not reproduce.** I tried 6 price definitions at T1 (last trade before, at, after the trigger swap, high to +30 s, look at +30 s, entry price). None gives it; the closest are +$1,204 to +$1,741. $503 a day is exactly 8 hits and 24 misses on a flat payoff; the engine and A2 both find 10 hits in the same 32 coins. **Ask: Auditor to publish the script.**
- **Official numbers (engine, official rulers: 3x or 48 h, pull = 0, one per cluster a day, $100 ticket):**

| Rule | $/day A \| B | $1,000 ticket A \| B | Trades | Beat random | Best of 50 random |
|---|---|---|---|---|---|
| Lane F at T1 | +162 \| +261 | +1,215 \| +2,111 | 19 \| 19 | 96.6% \| **89.1%** | **20% \| 0%** |
| Lane F, look +30 s, fill +20 s | +165 \| +222 | +1,227 \| +1,736 | 23 \| 18 | 99.1% \| **90.5%** | |
| Buy every T1 | -201 \| +86 | -3,221 \| -173 | 121 \| 76 | | |
| Buy every T4 survivor | -404 \| -378 | | 60 \| 45 | not trustworthy (tape too short) | |

- **Verdict: Lane F is positive but is NOT an edge on the rulers.** It fails beat random 95% in B in every version, and fails the many-tries check hard. Forward paper only (as decided).
- Cost: 0 credits, $0, about 0.8 h total.

## How to use it (any team member)
- `ssh -T -i ~/kookwatch/id_kookwatch root@152.42.241.219`, put your rule in `/opt/tw/engine/rules/`, then:
- `twtest /opt/tw/engine/rules/myrule.py --universe T1 --entry-delay 30 --ticket 100,1000`
- The wrapper already adds `timeout 30m nice -n 10 ionice -c3`. Inputs are read only copies.
- A rule file:
```
ID = "DC2.1-F"      # must match the test id in dc-prereg.md
UNIVERSE = "T1"
def rule(f):
    return f["close_high"] <= 0.784 and f["alumni_share"] >= 0.053
```
- Options: `--tp 3`, `--stop 0.3`, `--horizon 48h`, `--look 30` (read features 30 s after the trigger), `--tries 50` (best of 50 random), `--no-cluster`, `--trades out.csv`, `--universe T1|T4|T4_6h|ALL`.
- Each run appends one line to `/opt/tw/engine/pub/dc-results.csv`, mirrored at http://159.223.88.168/hx-c9ois/dc/en/dc-results.csv
- No dc-prereg.md line for the ID: the run prints **NOT PRE-REGISTERED**.

## Features a rule can read (only swaps up to the decision moment)
- `cap`, `close_high` (checked never above 1.0), `age_min`, `t_since_250k_min`
- `buyers` (wallets only, no-wallet swaps excluded), `n_buys`, `n_sells`, `bs_ratio`, `netflow15`, `churn`
- `holders`, `top10`, `alumni`, `alumni_share` (A2 definition: first 30 min buyers of an earlier coin, counted after its launch-file $1M time)
- `creator_sold_eth`, `hfam`, `fam`, `sym`, `creator`, `crew`, `fee_pool`
- On T1: A2's v3 columns as `a2_<name>`.

## The rulers, built in
- T1 = launch file sellable $250k time AND 100 unique buyer wallets. T4 = $250k and not pulled at +2 h (T4_6h: +6 h). ALL = every $250k coin.
- Entry: first swap at or after decision + delay (none within 10 min = no fill). Fill at estimated depth, pool fee each way, dynamic fee = 1%.
- Exit: take profit on a sellable print ($100+ sell). Pull before exit = 0. Else last price at the horizon.
- Coverage: trades whose horizon ends after the data are dropped and counted.
- One trade per cluster per day (ticker, creator or crew). Halves: A before 28 Sep, B from 28 Sep; covered days only.
- Beat random: 2,000 draws, same size, same half, same exits, same cluster rule. New $: P&L before the coin's first sellable $1M.

## Limits (stated on every run)
- Tape = PP wash.db v4 swaps, 21 Sep to 5 Oct 05:57 Bangkok. Stops at the pull, and about 30 h after launch for coins never pulled (`trunc`). **T4 needs a longer tape.**
- 51% of swaps have no wallet (Auditor): buyers and alumni see only half the crowd.
- **Public router rule NOT enforced:** no PP table keeps the router.
- v4 only. Depth estimated from price moves.

## Next (v1.2, by 8 Oct 10:00 Bangkok)
1. T4 tail from PP day DB bars (research box), so survivors are valued to 48 h.
2. Exact depth from day DB swaps (sqrt price + amounts).
3. Router rule as soon as PP stores the swap sender.

Version: v1.4, 7 Oct 2026 11:31 Bangkok, DC Engine. Latest: http://159.223.88.168/hx-c9ois/dc/dc-en-1-engine.md
