feat(margin): M3b buy-in stress mode (deterministic, default-off)#2017
Conversation
Deterministic short-side buy-in stress-path mode: when armed, every held short that is hard-to-borrow at its current mark is force-covered at the next weekly (Friday) close — the worst-case upper bound on buy-in cost for the M4 promotion-grid stress cells. No RNG (stress-path, not probabilistic). - New pure module Short_buyin (trading/trading/simulation/lib), mirror of the M2 Long_maintenance runner; buyin_stress exit tag; Friday cadence. - Margin_config gains short_buyin_stress_mode [@sexp.default false] + short_buyin_htb_price_below [@sexp.default 0.0] + is_buyin_htb helper. Placed on Margin_config (already threaded to Margin_runner.tick) → zero new simulator/panel_runner threading; bit-equal at defaults (R1). - Margin_runner.tick appends buy-in covers; a short flagged by both the maintenance check and buy-in mode is covered once (margin_call wins). - R2: both fields Overlay_validator-expressible; axis-expansion tests. - Closes two M3a #2016 QC drive-bys: symmetric short_borrow_rate_tiers axis test; borrow-fee parity wording "bit-for-bit" -> "numerically identical (1e-12)" (M3a per-position reassociation). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Reviewed SHA: ef5659f Structural QC — M3b buy-in stress modeHard Deterministic Gates
Generic Structural Checks (P1–P5)
Project-Specific Architecture Rules (P6, A1–A3)
Experiment Flag Discipline (R1, R2, R3)R1 — Default-off on merge: Both new config fields carry
At defaults, R2 — An axis the day it lands: Both fields are real Margin_config record fields, searchable via Overlay_validator:
R3 — No default-on without ACCEPT: This PR adds new flags default-off; does not flip any existing defaults. R3 not applicable. ✓ Summary
VerdictAPPROVED — with A1 FLAG routed to qc-behavioral Code is structurally sound. The margin-config modification (A1 FLAG) routes to qc-behavioral for generalizability judgment per established margin-seam precedent (M1b-2, M2, M3a). All hard gates pass; H3 deferred to CI which is authoritative for linter suite. CI checks status:
Merge gate: Do not merge until (1) CI green and (2) qc-behavioral APPROVED. |
|
Reviewed SHA: ef5659f Behavioral QC — margin M3b buy-in stress modeSelf-authored PR: verdict posted as an issue comment (cannot Contract Pinning Checklist
Behavioral Checklist (Weinstein S*/L*/C*/T*)NA — pure margin-realism infrastructure; no stage/screener/stop/domain logic. Spine sanity-check (per
Contract-by-contract (dispatch list)
Quality Score3 — Clean, well-documented, honestly-scoped implementation; R1/R2, HTB boundary, cadence, and tag all pinned. The sole defect is a coverage gap, not a logic error: the newly-introduced buy-in↔margin_call collision guard (a documented, crash-preventing seam) has no test, and (Does not affect verdict.) VerdictNEEDS_REWORK NEEDS_REWORK ItemsCP4(a): buy-in ↔ margin_call collision guard is untested (blocking)
CP4(b): "longs never touched" / non-Holding skip is untested (minor)
|
…ollision + long-skip guards - test_margin_runner.ml: new tick-level test test_buyin_collides_with_margin_call. Constructs a short that is simultaneously maintenance-breached AND HTB on the same Friday (COLLIDE, entry $10 / mark $15) plus a second HTB-only short (BUYONLY, mark $5). Asserts tick emits exactly ONE cover for COLLIDE tagged margin_call (the buy-in duplicate dropped by _drop_buyins_colliding_with_covers) and one buyin_stress cover for BUYONLY — pinning the internal-dedup half of the tick .mli contract (strategy-vs-margin dedup already pinned by T5). - test_short_buyin.ml: parametrized the position builder by side and added test_long_below_threshold_never_covered — a long marked below the HTB threshold is never a buy-in candidate (the _holding_of_position projection skips non-short positions). Tests only; no production-code change. Both suites green (test_short_buyin 9, test_margin_runner 12). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Reviewed SHA: 532bd86 Behavioral QC (re-review after rework) — margin M3b buy-in stress modeSelf-authored PR: verdict posted as an issue comment (cannot Re-review scope: the test-only rework commit The two rework tests pin exactly what the findings demandedCP4(a) → resolved — CP4(b) → resolved — Both grounded in production behavior; test-only, no source change, so all APPROVED rows below are unaffected by regression risk. Contract Pinning Checklist (final)
Behavioral Checklist (Weinstein S*/L*/C*/T*)NA — pure margin-realism infrastructure. Spine sanity-check carried: mechanism force-covers only already-
Quality Score4 — All checks pass; clean, honestly-scoped implementation. The rework tests are well-constructed: the collision test grounds the dedup in a real (Does not affect verdict.) VerdictAPPROVED Merge gate reminder: this verdict is behavioral only. Merge additionally requires (1) CI green at |
|
[Re-pinned at SHA 532bd86 — behavioral-QC rework landed] Reviewed SHA: 532bd86 Structural verdict STANDS: APPROVED (with A1 FLAG to qc-behavioral). Second Commit (532bd86): Test-Only Rework — P6 VerifiedChanges: +174/−3 lines, 2 test files only; no production-code changes. New tests:
P6 conformance: Both new tests follow proper matcher patterns; no List.exists/unasserted-results/bare-match violations. ✓ All Rows Carry Over
VerdictAPPROVED at 532bd86 — behavioral-QC rework adds conformant test coverage. All structural constraints met. Merge gate: (1) CI green, (2) qc-behavioral APPROVED (already signaled per coordinator). |
Automated daily orchestrator run (run-1 of 2026-07-20, GHA run 29719142253). Zero-dispatch full pass. Main GREEN on `b4ef7900` (clean-tree `dune build` + `dune runtest` both exit 0; fmt_check/magic_numbers OK; integrity + index_size exit 0). One open PR #2009 (maintainer LOCAL, deferred per collision-avoidance); every other track deep-warehouse-data-gated / human-gated / active-LOCAL. Reconciled resistance-v2 (#2013 merged + lever f #2015) and margin-realism (M3a/M3b #2016/#2017) rows. See `dev/daily/2026-07-20.md` for the full summary. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: claude-orchestrator <noreply@github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: GitHub Actions Bot <bot@github-actions>
margin M3b — buy-in stress mode (deterministic stress-path, default-off)
Closes the remaining half of M3 (short-side squeeze robustness) from
dev/plans/levered-longshort-margin-realism-2026-07-14.md. Builds on M3a (#2016).What it does — the mechanism
Models the worst-case squeeze cost for a levered long-short config: when a short
is hard-to-borrow (HTB), the lender can recall the borrowed shares, forcing a
buy-in. When armed, every held short that is HTB at its current mark is
force-covered at the next weekly (Friday) close — a deterministic upper bound
on buy-in cost for the M4 promotion-grid stress cells.
New pure module
Short_buyin(trading/trading/simulation/lib/short_buyin.{ml,mli}),the short-side mirror of the M2
Long_maintenancerunner:select_buyins— pure HTB filter over marked short holdings.buyin_stress_transitions— Friday-gatedTriggerExitbuilder; each cover istagged
StrategySignal { label = "buyin_stress" }at the mark, so forensicsseparate buy-ins from strategy exits, short maintenance covers (
margin_call)and long reduces (
maintenance_reduce).Deterministic by design
Chose the deterministic stress-path branch over the probabilistic
forced-cover: the M4 grid wants the single worst-case path (every HTB borrow
recalled), not sampled paths, and every analysis function must stay
pure/reproducible (CLAUDE.md). No RNG anywhere — same portfolio + config always
yield the same covers.
HTB definition — dedicated threshold
A short marked strictly below a positive
short_buyin_htb_price_belowis HTB(
Margin_config.is_buyin_htb ~price). Chose a dedicated threshold over reusing anM3a tier band because buy-in (share recall) is a distinct broker event from a
maintenance breach — a lender can recall a name comfortably above its maintenance
requirement — so the stress cell's "which shorts get bought in" is decoupled from
the leverage/maintenance dials and the M4 grid can vary them orthogonally. That
low-priced names are the HTB ones mirrors the M3a price-tier philosophy.
R1 (default-off)
Margin_configgainsshort_buyin_stress_mode : bool [@sexp.default false]+short_buyin_htb_price_below : float [@sexp.default 0.0]. Placing them onMargin_config(already threaded toMargin_runner.tick) needs zero newsimulator/panel_runner threading. At the defaults nothing is ever HTB (mode
off, and no positive mark is below 0.0), so
tickstays bit-equal — goldensunchanged, no re-pin.
R2 (searchable)
Both fields resolve through
Overlay_validatorvia the nestedmargin_config.*overlay keys; axis-expansion tests
test_short_buyin_stress_mode_axis_expandsand
test_short_buyin_htb_price_below_axis_expandsintest_variant_matrix.ml.Wiring + collision handling
Margin_runner.tickappends buy-in covers alongside the short force-cover and M2long-reduce (same Friday cadence +
dedup_strategy_exits_for_marginseam). Ashort flagged by both the maintenance check and the buy-in mode is covered once —
_drop_buyins_colliding_with_coverskeeps themargin_call(richer detail),drops the duplicate
buyin_stress.Bar-cadence caveat
Documented in
short_buyin.mli+ theMargin_configfield docs: daily-closemarks cannot see an intraweek gap-through-recall; a Monday-to-Thursday squeeze is
only covered at Friday's close — M4 stress-path gap scenarios extend this.
M3a QC drive-bys closed (both non-blocking observations from #2016)
test_short_borrow_rate_tiers_axis_expands(the M3a axiswas proven only via its structurally-identical
short_maintenance_tierssibling).
"numerically identical (1e-12)" in
portfolio_margin.mli+ the renamedtest_borrow_fee_empty_tiers_numerically_identical_flat. The M3a per-positionreassociation
(Σnᵢ)·r → Σ(nᵢ·r)is not IEEE-bit-identical; goldens hold.Test plan
test_short_buyin.ml(8) — R1 default/disarmed no-ops, armed selects only HTB,zero-threshold no-op, Friday-armed tagged cover at mark, weekly-cadence Monday
no-op, unmarked-short skip, no-positions no-op.
test_margin_accounting.ml(+1is_buyin_htbgate; round-trip extended to thebuy-in fields).
test_variant_matrix.ml(+3 axis-expansion tests).dune build(exit 0),dune build @fmt(clean, nodiff),
dune runtest trading/simulation/test trading/portfolio/test trading/backtest/walk_forward/test(exit 0 — the three suites touching thischange: portfolio +39, simulation incl
test_short_buyin+8, walk_forwardaxis tests), and
linter_file_length(exit 0). Magic-number scan of the newsource is clean (all named constants / semantic zeros;
short_buyin.mlhas nonumeric literals). Goldens unchanged (default-off, bit-equal at defaults).
dune runtest+ fulldevtools/checkswere CPU-starved by a livelocal sweep chain and not completed locally — CI is authoritative for the
full surface.
Not in scope
M4 (validation protocol — parity gates, squeeze stress cells, leverage surface
via experiment-gap-closing + confirmation grid). No default flips and no levered
number quoted here.
🤖 Generated with Claude Code