Add PAPER trading mode + fix partial-fill close orphaning positions - #1
Open
Freecey wants to merge 3 commits into
Open
Add PAPER trading mode + fix partial-fill close orphaning positions#1Freecey wants to merge 3 commits into
Freecey wants to merge 3 commits into
Conversation
New mode between OFF and LIVE: the full pipeline (scan, TA, AI research, risk gates, DSL exits) runs unchanged against live data, but every authenticated exchange call routes to a simulated book (client/paper_engine.py): - fills at the live L2 touch + paper_slippage_bps, taker fees at paper_fee_bps, position netting with realized PnL - reduce-only clamps to the live size (never flips), pre-trade margin check - virtual SL/TP triggers evaluated against live mids on every account read - state persisted atomically to .paper-state.json across restarts - fetch_account_state returns the virtual book in HL's exact clearinghouseState shape, so gates/DSL/dashboard need no changes - no HYPERLIQUID_* env vars required (resolve_user_address -> "paper") Loop startup now logs the real configured mode (was hardcoded "LIVE"). Covered by tests/test_paper.py (14 offline tests). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lience - close_position_market: an IOC reduce-only close can PARTIALLY fill on a thin book; the code deregistered the DSL tracker on ok=True without checking totalSz, orphaning the residual position with no stop/floor/ timeout. Now reconciles totalSz vs requested, retries the residual up to 3x (fresh size + price each pass), keeps the tracker and returns ok=False + partial details if any size remains (next DSL tick re-fires). Realized PnL uses the size-weighted fill price across all fills. - rehydrate_from_exchange: synthesized trackers stamped entry_time=now, re-arming hard_timeout_minutes from scratch on every restart. Now looks up the real open time from the account's fill history (most recent open-from-flat fill), falling back to now when unavailable. - backup SL/TP triggers: placement is retried once (typical failure is a transient meta-cache/429 flake) and a persistent SL failure now emits an error event to the session feed instead of only a log line. - gate inputs: open-position notional now uses HL's positionValue (live mark) instead of size x the stale analysis entry price. - place_hl_trigger_order callers pass is_long_position= explicitly (the positional is_buy only worked because entry direction == position side). - maybe_execute no longer requires HYPERLIQUID_PRIVATE_KEY in PAPER mode. Covered by tests/test_close_and_rehydrate_fixes.py (6 regression tests). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The FastAPI server (dashboard + operator endpoints that place/close real trades behind a single static token) listened on 0.0.0.0 unconditionally. Default is now 127.0.0.1, overridable via HERMES_HOST. Containerized deploys keep their behavior: HERMES_HOST=0.0.0.0 is set in the Dockerfile, fly.toml and the k8s configmap, where the platform provides the network isolation. Dockerfile also pins HERMES_PAPER_STATE_FILE onto the /data volume alongside the other state files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Merged
Julian-dev28
added a commit
that referenced
this pull request
Jul 12, 2026
…lidated Pre-registered honest implementations of all 7 visible '25/25 leaderboard' strategy families, our data (90 coins daily + 40 coins hourly 208d), net 25bps+funding, frozen thresholds, matched nulls >=2000, Bonferroni 0.0056: 6 REFUTED, 1 UNDERSAMPLED (dominance_transition, n=20). Best null p anywhere: 0.215. Their #1 (claimed Sharpe 7.07 / 2,311%) earns -0.57%/trade OOS here and loses to random same-coin timing in 2000/2000 resamples; their claimed n for dominance signals is arithmetically impossible (9-21 fires in 5.5y). W-Q verdict upgrades: presumptively overfit -> empirically contradicted. Nothing ships, no recorder owed. 12MB hourly cache gitignored. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Julian-dev28
added a commit
that referenced
this pull request
Jul 22, 2026
…piece #1 W-MATH2: we run ~2.87 effective bets, not 15; the 4 xyz-short books are ~1.28 bets held four ways (mean pairwise corr 0.83), and 7 xyz shorts stopped TOGETHER for -$8.59 on 07-21 exactly as the correlation predicts. W-MATH3 independently promoted a per-sector short cap as THE fix (not momentum timing). - xyz_short_concentration_gate: caps concurrent DISTINCT xyz-equity short names (<=3) AND their combined notional (<=25% equity). Name cap is the hard control; notional cap is best-effort (skipped if positions carry no value field, so a missing field never wrongly blocks). Only gates NEW xyz-equity shorts. - wired into eval_all_gates NOT carveout-exempt — the whole point is the correlated BOOK cluster, so strategy books obey it too. - config: max_xyz_short_names=3, max_xyz_short_notional_pct=0.25 (W-MATH2's number; was ~7 names / ~124% equity on overnight). - 4 tests (name cap, notional cap, ignores longs/crypto/missing-value, wired + not-carveout-exempt). 27 book-path + wiring tests green, no collision. Honest caveat (W-MATH2): nothing live is edge-proven yet (n<8); this cap is risk-control, and the allocation is variance-driven until books hit n>=8 (~1-2wk). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PsychoLogicAu
referenced
this pull request
in PsychoLogicAu/hermes-trader
Aug 20, 2026
…nked) 7e63882 dedented the TA-filter + LLM research + execute block out of the for perception in results: loop, so only the last (lowest-ranked) trigger was ever researched per scan. The top-ranked trigger was silently skipped all cycle - e.g. LINK ranked #1 for 34 straight scans (scores 35-45) but was first researched only when ACE briefly out-scored it at the top of LINK's +8.8% spike, producing the 2026-08-15 late-chase entry. Re-indent the block back into the loop so all confirmed triggers are researched per cycle in score order. sleep/progress timestamp stay outside the loop (once per cycle). Restores pre-7e63882 structure plus the newer PASS/Chronos logging.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three changes in three commits (happy to split into separate PRs if you prefer):
1.
feat(paper): PAPER mode — simulated fills against live market pricesThere is currently no step between
OFF(observe only) andLIVE(real money). This adds"mode": "PAPER": the full pipeline (scan → TA filter → AI research → risk gates → DSL exits) runs unchanged against live market data, but every authenticated exchange call routes to a simulated book (client/paper_engine.py):paper_slippage_bps, taker fees atpaper_fee_bps.paper-state.json(survives daemon restarts, same pattern as.dsl-state.json)fetch_account_statereturns the virtual book in HL's exactclearinghouseStateshape, so the gates, DSL engine, dashboard andstatus.pywork without modificationHYPERLIQUID_*env vars — useful for new users evaluating a config before funding a walletKnown approximations are documented in the module docstring and README: orders always fill in full (no book-depth exhaustion) and triggers fill at their trigger price (real markets gap) — so paper results are slightly optimistic by construction.
2.
fix(exits): partial-fill close could orphan a position with no stopThe important one. In
close_position_market, the DSL tracker was deregistered as soon as the reduce-only IOC returnedok=True, without checkingtotalSzagainst the requested size. On a thin book, a partial fill left the residual position live on the exchange with no stop, no floor, no timeout — exactly the failure mode this engine exists to prevent.Now:
totalSzis reconciled against the requested size, the residual is retried up to 3× (fresh size and price each pass), and if any size still remains the tracker is kept and the call returnsok=Falsewithpartial/remaining_szdetails so the next DSL tick re-fires the close. Realized PnL uses the size-weighted fill price across all fills.Also in this commit:
rehydrate_from_exchangestamped synthesized trackers withentry_time=now, re-arminghard_timeout_minutesfrom scratch on every restart (a 2h50m-old position got a fresh 3h lease). It now looks up the real open time from the account's fill history (most recent open-from-flat fill), falling back tonowwhen unavailable.errorevent to the session feed instead of only a log line — the position is otherwise running with the 60s DSL loop as its only stop and nobody knows.positionValue(live mark) instead of|szi| ×the stale analysis entry price.place_hl_trigger_ordercallers passis_long_position=as an explicit keyword — the positionalis_buyonly worked because entry direction happens to equal position side.3.
fix(security): bind the API server to localhost by defaultThe FastAPI server (whose operator endpoints place/close real trades behind a single static token) listened on
0.0.0.0unconditionally. Default is now127.0.0.1, overridable viaHERMES_HOST; the Dockerfile,fly.tomland the k8s configmap setHERMES_HOST=0.0.0.0so containerized deploys behave exactly as before.Testing
tests/test_paper.py(14 tests: fills, netting, reduce-only clamp, margin check, trigger firing, persistence, exchange-layer routing) +tests/test_close_and_rehydrate_fixes.py(6 regression tests: partial close keeps the tracker, residual retry, weighted fill price, dust handling, open-time from fill history, API-failure fallback).🤖 Generated with Claude Code