Skip to content

EV metrics + EV-weighted evolution + stop-loss cooldown + pool-history hard gate#94

Open
hadhaz wants to merge 3 commits into
yunus-0x:mainfrom
hadhaz:reconcile/ev-cooldown
Open

EV metrics + EV-weighted evolution + stop-loss cooldown + pool-history hard gate#94
hadhaz wants to merge 3 commits into
yunus-0x:mainfrom
hadhaz:reconcile/ev-cooldown

Conversation

@hadhaz

@hadhaz hadhaz commented Jun 18, 2026

Copy link
Copy Markdown

Why

Win rate alone hides exit asymmetry — small wins, rare catastrophic losses ("picking pennies in front of a steamroller"). Measured on prod data: 62% win rate but EV ≈ 0 (payoff 0.55:1, gross -$19.79 over 274 closed positions). This PR makes the agent measure EV, stops auto-tuning from optimizing win-frequency, and hard-gates redeploys into pools its own memory already flagged as bad.

Commits

1. EV/risk-reward metrics + EV-weighted threshold evolution (ee4bfca)

  • computeEdge(): EV per position (% + USD), avg win/loss, payoff ratio, worst loss, steamroller flag — wired into getPerformanceSummary + getPerformanceHistory
  • evolveThresholds split into pure deriveThresholdChanges(); fee/organic floors weighted by |pnl_pct| so penny-wins stop validating low-fee zones
  • briefing: EV line + steamroller warning
  • test/test-ev.js: 7 checks

2. Stop-loss cooldown + skip-screening-on-startup + briefing HTML escaping (6821c12)

  • stopLossCooldownHours (default 12): cooldown pool + base-mint after a stop-loss close
  • SCREEN_ON_START gate: skip redundant immediate screening on restart
  • briefing: escapeHtml() on lesson rules

3. Pool-history hard gate in deploy_position safety checks (a9a8d2d)

  • The agent kept redeploying into pools its memory flagged as bad. Example: glippy-SOL showed 67% raw win rate / +2.26% avg PnL, but adjusted_win_rate was 0% over 0 clean closes — all 3 deploys left the range (OOR/pump), pure price variance, never a real in-range earner. The signal was LLM-visible but overridable; it rationalized past it and went OOR 55s after deploy.
  • getPoolMemory now returns oor_exclusion_rate
  • evaluatePoolHistoryGate() (pure): rejects range-unstable (oor_exclusion_rate >= maxPoolExclusionRate) or in-range loser (adjusted_win_rate < minPoolAdjustedWinRate, ≥2 clean closes)
  • enforced in runSafetyChecksnon-LLM-overridable
  • config.screening: minPoolDeploysForGate (3), maxPoolExclusionRate (0.6), minPoolAdjustedWinRate (20) — tunable via update_config
  • test/test-pool-gate.js: 6 checks incl. the real glippy case

Verification

  • npm test (full-repo syntax) passes
  • node test/test-ev.js → 7/7, node test/test-pool-gate.js → 6/6 (pass on server node too)
  • branch rebased cleanly onto current main

🤖 Generated with Claude Code

hadhaz and others added 3 commits June 18, 2026 09:46
Win rate alone hides exit asymmetry (small wins, rare catastrophic losses
— 'picking pennies in front of a steamroller'). Add EV measurement and make
auto-tuning weight positions by magnitude instead of win-frequency.

- computeEdge(): EV per position (% + USD), avg win/loss, payoff ratio,
  worst loss, steamroller flag; wired into getPerformanceSummary +
  getPerformanceHistory
- evolveThresholds split into pure deriveThresholdChanges(); fee/organic
  floors now weighted by |pnl_pct| so penny-wins stop validating low-fee
  zones (the 'naikin win rate doang' trap)
- briefing: EV line + steamroller warning
- test/test-ev.js: 7 unit checks (no runner/server data needed)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…escaping

Consolidates direct-on-server/local hotfixes that never reached origin:
- stopLossCooldownHours (default 12): after a stop-loss close, set pool +
  base-mint cooldown so we don't immediately re-enter a token that just cost
  a realized loss (config + update_config mapping + pool-memory enforcement)
- SCREEN_ON_START gate: skip the redundant immediate screening run on restart
  (cron already schedules it) to save tokens; set SCREEN_ON_START=true to force
- briefing: escapeHtml() on lesson rules to prevent broken Telegram HTML

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The agent kept redeploying into pools its own memory flagged as bad (e.g.
glippy-SOL: 67% raw win rate / +2.26% avg PnL looked fine, but adjusted_win_rate
was 0% over 0 clean closes — all 3 deploys left the range via OOR/pump, pure
price variance, never a real in-range earner). The signal was visible to the
LLM but overridable, and it rationalized past it.

- getPoolMemory now returns oor_exclusion_rate (frac of past deploys that closed
  OOR/pumped vs clean in-range)
- evaluatePoolHistoryGate(): pure, two reject signatures — range-unstable
  (oor_exclusion_rate >= maxPoolExclusionRate) or in-range loser
  (adjusted_win_rate < minPoolAdjustedWinRate with >= 2 clean closes)
- enforced in runSafetyChecks deploy_position → non-LLM-overridable
- config.screening: minPoolDeploysForGate (3), maxPoolExclusionRate (0.6),
  minPoolAdjustedWinRate (20); all tunable via update_config
- test/test-pool-gate.js: 6 checks incl. the real glippy case

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@hadhaz hadhaz changed the title EV/risk-reward metrics + EV-weighted evolution + stop-loss cooldown EV metrics + EV-weighted evolution + stop-loss cooldown + pool-history hard gate Jun 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant