Operator call: no per-strategy configurability for exit pacing — it added
config fields, UI and plumbing nobody wanted. Back to plain constants in
auto_trader_throttle.go, now set to the replay-validated values instead
of the original guesses (4154 cycles, 3-fold robust search over only the
7 exit params, everything else fixed at the live config):
- min hold 90m, noise-close window 3h, noise band -2%..+3%,
bypasses -3%/+8% (all inside the searched top-20 ranges)
- re-entry cooldown 4h — the one clear signal: top-20 configs cluster
tightly at 3.8-4.0h; re-entering a just-closed symbol was a consistent
loss source
Removes the 7 RiskControlConfig fields + accessors, the Strategy Studio
'exit pacing' row, the frontend type fields, and the fields from stored
strategy configs in data/data.db. Prompt guidance is static text again,
matching the constants.
The anti-churn exit gates (min hold, noise-close window, re-entry
cooldown, bypass and noise-band thresholds) were hardcoded constants in
auto_trader_throttle.go — every flat-ish position was forced to hold 8h+
and changing the pacing meant a code change and redeploy.
- RiskControlConfig gains 7 exit-gate fields (minutes / signed price-%),
zero = built-in default; accessor methods centralize fallbacks and are
hot-reloaded from the DB like the rest of the strategy config
- Throttle reads the gates from the strategy; prompt hold/exit guidance
is now rendered from the same values so the AI is told exactly what
the code will enforce
- Defaults softened: min hold 4h -> 1.5h, noise window 8h -> 3h,
re-entry 3h -> 1.5h, bypasses -5/+12 -> -3/+8, noise band -4..+6 ->
-2..+3 (price-basis). A +-2-3% move is 15-20x round-trip fees — no
longer 'noise' worth locking
- Strategy Studio gets an 'exit pacing' row (min hold / flat-close
window / re-entry cooldown); thresholds editable via strategy JSON
- Live strategy updated in data/data.db with the softened values
Live decomposition of the losing streak: 23% win rate with avg win +$1.23 /
avg loss -$1.04 on ~0.3-0.5% price moves, where the ~0.14% round-trip fee ate
30-50% of every tiny winner. Death by small-move grinding. The AI was closing
positions on ±0.5% noise after the 60m min-hold, capping winners at ~0.86%.
Redesign to 'few big positions, held for big moves':
- Throttle: min hold 60m->4h, noise-close window 90m->8h, reentry 30m->3h,
opens/hour 30->3, opens/cycle 6->2. Noise band widened -1%..+2% -> -4%..+6%
so small moves can no longer trigger a close.
- Exits: stop bypass -2.5% -> -5%, take-profit bypass +5% -> +12% (wide,
asymmetric — let winners run, cut losers only on a real move).
- Leverage 20x -> 5x: a -5% stop at 20x is instant liquidation; at 5x it is
-25% of margin, survivable. 2 positions x 2.5x = 5x total (full margin,
~20% cushion) instead of 4x5x=20x.
- Prompt now instructs the AI to set wide stops (~-5%) and distant targets
(~+10-12%), hold multi-hour, and never scalp 0.5% moves.
Live strategy updated (maxPos=2, lev=5, ratio=2.5).
Analysis of 410 live closed trades found the edge is real but was being
destroyed by execution: gross +$267 vs $245 fees; trades held <1h were net
negative (the <15m bucket alone: -$48 on $66 fees) while 1h+ holds carried
+$78; shorts lost $72 while longs made $94 — and both the prompt and the
engine were manufacturing those losers.
Changes, each tied to the data:
- Prompt: removed the 'MUST open at least one long AND one short every
cycle' mandate (forced weak-signal shorts); direction is now data-driven
with 'never open just to balance the book'. Added fee-awareness (round
trip ≈ 0.1% notional, require expected move ≥ 3x cost) and aligned the
hold discipline with the backend throttle.
- Forced book-balance opens now require |board z-score| ≥ 0.75 — the engine
previously force-opened full-size 10x positions on near-neutral signals
with hardcoded confidence 70. DirectionalCandidates now carries scores.
- Min AI-managed hold raised 45m → 60m (the 15-60m bucket still bled after
the earlier throttle landed).
- Legacy prompt hygiene: vergex path drops long-only-era custom prompts and
zh-era configs fall back wholesale to built-in English sections — fixes
the two long-failing kernel prompt tests.
- New Edge Profile dashboard panel: net after fees by hold-time bucket and
side, computed from recent closed trades, with an automatic takeaway line
— the fee/churn regression detector, always visible. Fixed the
HistoricalPosition timestamp types (epoch ms, not strings).
The strategy prompt the LLM saw for a Chinese-language single-symbol US
stock trader was an incoherent zh/en patchwork — schema in Chinese,
role definition in English, hard constraints in English, custom prompt
back in Chinese — with crypto-flavored BTC/ETH vs Altcoin labelling that
made no sense for ARM-USDC. The LLM responded by being conservative and
boring. When it finally tried to open, the validator rejected the order
because the validator classified the stock as an altcoin (1x equity cap
= 112 USDT max) while the prompt said 5x cap (= 559 USDT).
- kernel/engine_prompt.go (BuildSystemPrompt): all eight prompt sections
now respect e.GetLanguage() consistently. For single-symbol
Hyperliquid XYZ assets (US stocks, commodities, forex) we additionally
force the language to English regardless of the strategy's stored
language — US-equity reasoning lands better in English and prevents
the language-mix incoherence. The Hard Constraints section drops the
BTC/ETH vs Altcoin two-tier split when the strategy trades a single
instrument and shows one Position Value Limit line tagged with the
actual symbol. The JSON example uses that symbol instead of the
legacy BTCUSDT/ETHUSDT. The legacy stored custom_prompt (which was
Chinese for stock quick-creates) is replaced for XYZ assets by
buildXYZStockCustomPrompt — a built-in English long-only stock
briefing that includes a Flat-Account Rule: when Current Positions
is None, the agent MUST open a long this cycle (size 40-60% probing
if technicals are mixed, 80-100% on a confirmed breakout). This is
the "be in the market, not on the sidelines" stance the quick-trade
flow needed; wait/hold are reserved for when a position already
exists.
- kernel/engine_position.go + trader/auto_trader_risk.go + agent/trade.go:
Hyperliquid XYZ assets now use the BTC/ETH higher tier rather than
the altcoin tier in all three position-value enforcement points. A
shared isMajorAsset / isMajorTradeSymbol helper treats BTC/ETH crypto
perps AND any IsXyzDexAsset symbol as the higher tier. With 5x
equity cap, the AI's confident-open decisions on US stocks now pass
validation instead of erroring out with "altcoin single coin position
value cannot exceed 112 USDT".
Net result: on a flat US-stock single-symbol trader, the agent opens
a sized position with stop-loss and take-profit on the very first
flat cycle, manages it (trail / partial / cut), and reports honestly
to the user. The "agent does nothing" complaint is closed.