Skip to content

v0.2.2: scale-in, trailing stop, pnl tracker, backtest#3

Merged
Hiksang merged 1 commit intomainfrom
feat/v0.2.2-trading-tools
Mar 10, 2026
Merged

v0.2.2: scale-in, trailing stop, pnl tracker, backtest#3
Hiksang merged 1 commit intomainfrom
feat/v0.2.2-trading-tools

Conversation

@Hiksang
Copy link
Copy Markdown
Collaborator

@Hiksang Hiksang commented Mar 10, 2026

Summary

  • trade scale-in <symbol> <side> — Place multiple limit orders at different price levels for gradual position building (분할매수). Specify --levels "65000:30,63000:30,60000:40" with --size-usd or --size.
  • trade trailing-stop <symbol> — Client-side trailing stop that monitors price and closes position when price drops by X% from peak. Supports --trail <pct>, --activation <price>, and --background (tmux) mode.
  • trade pnl-track — Live terminal dashboard showing real-time PnL for open positions. Supports --interval and --symbol filter.
  • backtest funding-arb — Backtest funding rate arbitrage strategy on historical data with configurable spread entry/close thresholds and exchange pairs.
  • backtest grid — Backtest grid trading strategy on historical klines with configurable upper/lower bounds and grid count.
  • New src/strategies/trailing-stop.ts module for the trailing stop logic.
  • New run trailing-stop subcommand for background execution.
  • Version bumped to 0.2.2.

Examples

# Scale into a BTC long across 3 levels
perp trade scale-in BTC buy --levels "65000:30,63000:30,60000:40" --size-usd 1000

# Trailing stop: close when price drops 3% from peak
perp trade trailing-stop BTC --trail 3

# Trailing stop with activation price, running in background
perp trade trailing-stop ETH --trail 5 --activation 4000 --background

# Live PnL dashboard
perp trade pnl-track

# Backtest funding arb over 30 days
perp backtest funding-arb --symbol BTC --days 30 --size-usd 5000

# Backtest grid trading
perp backtest grid --symbol ETH --upper 4000 --lower 3000 --grids 20 --days 14

Test plan

  • trade scale-in --help displays correct usage
  • trade trailing-stop --help displays correct usage
  • trade pnl-track --help displays correct usage
  • backtest --help shows subcommands
  • backtest funding-arb --help displays correct options
  • backtest grid --help displays correct options
  • --dry-run trade scale-in parses arguments correctly
  • --dry-run trade trailing-stop parses arguments correctly

🤖 Generated with Claude Code

- Add `trade scale-in`: place multiple limit orders at different price
  levels for gradual position building (분할매수)
- Add `trade trailing-stop`: client-side trailing stop with --trail pct,
  --activation price, and --background mode
- Add `trade pnl-track`: live terminal dashboard for position PnL
- Add `backtest funding-arb`: simulate funding rate arb on historical data
- Add `backtest grid`: simulate grid trading on historical klines
- Add trailing-stop strategy module and run subcommand for background mode
- Bump version to 0.2.2

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Hiksang Hiksang merged commit 53a2dc8 into main Mar 10, 2026
@Hiksang Hiksang deleted the feat/v0.2.2-trading-tools branch March 10, 2026 07:48
Hiksang added a commit that referenced this pull request Apr 11, 2026
Port the screening + rotation logic from outcome/src/hip3_mm.py into
perp-cli as a standalone pure-TypeScript utility module.

The research bot's core MM lesson: don't statically pick a symbol to
market-make — screen the entire HIP-3 universe every ~5 minutes, rank
each orderbook by spread × sqrt(depth), and rotate MM activity into
whichever markets currently clear a minimum quality bar.

This is Option C from the earlier plan — standalone screener with no
changes to existing strategy files. Self-BBO detection (Option B #3) is
prepared via the MmHooks.isSelfOrder scaffold so a future HIP-3 MM
strategy can plug in without further surgery.

Module exports (src/bot/screeners/hip3-screener.ts):
  - Types:  Hip3Candidate, BookScore, ScoredMarket, OrderbookSnapshot,
            ScreenerConfig, RotationConfig, RotationDelta, MmHooks,
            FetchBook, ScreenInput
  - Config: DEFAULT_SCREENER_CONFIG (minScore=500 matching outcome
            production floor), DEFAULT_ROTATION_CONFIG, resolveScreenerConfig
  - Pure:   computeBookScore (matches hip3_mm.py::compute_book_score formula)
  - Async:  screenHip3Markets, discoverHip3Candidates, screenWithAdapter
  - Class:  Hip3MarketRotation (update, activeMarkets)

Design highlights:
  - fetchBook is injected, not direct — unit tests mock it, production
    uses adapter.getOrderbook; zero network calls in the test suite.
  - discoverHip3Candidates reuses src/dex-asset-map.ts fetchAllDexAssets
    which already handles allPerpMetas + metaAndAssetCtxs + cache, so
    no duplicate HL API plumbing.
  - Hip3MarketRotation.update tracks excludedThisPass to prevent a
    freshly exited market from being re-entered inside the same pass
    (caught during implementation, fixed via Set<string>).
  - No side effects apart from the optional hook invocations; multiple
    strategies can share one rotation instance.

Outcome Market bots (mm_bot_v2.py, arb_hedge_bot.py, Greeks engines)
are intentionally out of scope — perp-cli is perp-only.

Tests (src/__tests__/hip3-screener.test.ts): 30 new cases covering
computeBookScore (8), resolveScreenerConfig (2), screenHip3Markets (10,
including budget accounting on fetchBook throw), and Hip3MarketRotation
(9, including the isSelfOrder scaffold signature check and default-
config maxActive fallback).

Verification:
  pnpm build → tsc exits 0 clean
  pnpm test  → 45 files, 971 tests all green (+30 vs main baseline 941)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Hiksang added a commit that referenced this pull request May 1, 2026
- New `docs/SSOT_RULES.md` codifies Single Secret Source rule alongside
  Rule #2 (no fallback). All cryptographic secrets live in exactly one
  persistent location with one consistent format.
- Lighter L2 slot private key migrates from `~/.perp/.env LIGHTER_API_KEY`
  plaintext to AES-256-GCM-encrypted keystore at
  `~/.perp/lighter-agents/<account>-<slot>.json` (mode 0600).
  New module `src/agent-wallet/lighter-keystore.ts` (save/load/delete +
  one-time `migrateFromEnvIfPresent` for legacy users).
- Adapter init reads via `loadLighterKey()`; constructor no longer reads
  any LIGHTER_* env vars. Migration helper auto-clears legacy `.env`
  entries on first run.
- `wallet show --json` now exposes `owsActive: { name, evmAddress,
  solanaAddress }` so agents can discover the master EVM/Solana address
  without env-derived fallbacks. Closes the friction surfaced by
  trader-persona-alpha v1.
- `src/index.ts` removes the no-arg `dotenv.config()` call that
  silently auto-loaded any CWD `.env`. Only `~/.perp/.env` loads now,
  eliminating a Rule #3 violation surface where stray dev keys polluted
  master-address resolution.
- Tests: 1230 -> 1249 (+19 keystore tests). Build green. Live signed-read
  smoke on all 4 DEXs (HL/PAC/LT/Aster) confirms keystore-driven
  Lighter signer initializes end-to-end.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hiksang added a commit that referenced this pull request May 1, 2026
Aggregates SSOT Rule #3 application + referral system overhaul:
- 1b44a42 feat(ssot-rule-3): Lighter L2 keystore + wallet show OWS-aware + docs
- 908e9ed fix(referral): drop catch-as-success — only mark applied on real success
- 7fa28ba fix(referral): apply Lighter ref via agent path (L2-signed)
- a573b47 feat(referral): make codes mandatory (remove opt-out)

Breaking changes for end users:
- `~/.perp/.env LIGHTER_API_KEY` is no longer read; auto-migrated to
  `~/.perp/lighter-agents/<account>-<slot>.json` on first run.
- `perp settings referrals on/off` command removed; referrals now always on.
- `settings.referrals` field silently ignored on load.
- CWD `.env` no longer auto-loaded (only `~/.perp/.env`).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hiksang added a commit that referenced this pull request May 1, 2026
3 atomic commits aggregated from HypurrQuant_FE reference comparison +
Codex v0.12.11 re-review:

- 889d044 fix(aster): require agent for Tier 2/3 — venue rejects master self-signing
- 461f856 fix(aster): restore 429 retry loop on signed GET/DELETE
- adab00d fix(alerts): include ASTER_PRIVATE_KEY in env passthrough list

Tests 1281 → 1282 (+1). Build green.

The Aster Tier 2/3 throw is the actual root cause of "Signature check
failed" observed all session — venue requires registered agent as
signer. Master self-signing was never valid per V3 spec, but our
code attempted it anyway. Reference: HypurrQuant_FE AsterPerpAdapter.ts.

HL portfolio non-USDC collateral math (Codex re-review #3 PARTIAL)
deferred to a future change — current stderr warning surfaces the
limitation without silently undercounting.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hiksang added a commit that referenced this pull request May 1, 2026
_signedRequestWithRetry had MAX_ATTEMPTS = 3 but the third attempt
threw without sleeping, so the documented 8s backoff was never
reachable in practice. Bump to MAX_ATTEMPTS = 4 (initial + 3 retries
with 2s/4s/8s waits) to match the comment and the intended rate-limit
recovery curve.

Codex v0.12.12 final QA #3.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hiksang added a commit that referenced this pull request May 1, 2026
Aggregates 4 commits closing Codex final QA findings on v0.12.12:

- 8616472 fix(hyperliquid): standard/default mode portfolio accounting
- f25ebe2 fix(errors): preserve PerpError code + remediation in JSON envelope
- 0669295 fix(aster): retry loop reaches all 3 documented backoffs (2s/4s/8s)
- 94fb610 fix(mcp-server): align with v0.12.x — 4-DEX support

Tests 1282 → 1301 (+19). Build green.

Both BLOCKERS from Codex v0.12.12 final QA verdict are closed:
1. HL standard/default mode no longer silently undercounts spot USDC
2. PerpError code + remediation preserved in JSON envelope (no more
   downgrade to FATAL/SIGNATURE_FAILED for typed errors)

This is the stable release target. After publish, the v0.12 series
(SSOT Rule #3 + Lighter L2 keystore + 4-DEX agent flows + account
abstraction mode + Aster agent-required + MCP 4-DEX) is feature-complete
and production-ready.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hiksang added a commit that referenced this pull request May 3, 2026
Adds new asset class: HL outcome markets (binary/range contracts, fully
collateralized, no leverage, no liquidation, USDH-quoted, $10 min order).
Currently 1 live market: BTC binary daily settling at 06:00 UTC.

New surface:
  perp outcome list                              # active markets
  perp outcome book <outcome> <side> [--depth N] # orderbook
  perp outcome positions                         # holdings
  perp outcome orders                            # open orders
  perp outcome buy <outcome> <side> <usd>        # IoC by default, --limit for GTC
  perp outcome sell <outcome> <side> <usd>
  perp outcome cancel <outcome> <side> <oid>

Key facts (verified end-to-end against mainnet):
- Asset id formula: 100,000,000 + (10 * outcome + side)
- Coin name: '#<enc>' (l2Book/candle/allMids), '+<enc>' (spot balance)
- Universe: POST /info {type:"outcomeMeta"}
- Positions: filter spotClearinghouseState for '+<enc>' coins
- Order/cancel actions identical to spot, only assetId differs
- Quote token = USDH (NOT USDC) — outcome trades draw from spot USDH balance
- Min notional: price * size >= 10 USDH
- Probe scripts: scripts/probe-outcome-{ws,order}.ts (manual mainnet verify)

Adapter (HyperliquidOutcomeAdapter) composes with HyperliquidAdapter for
signing. Bypasses HL's cached spot state on getPositions() to surface
fresh balances after fills (cache TTL would be stale).

CLI uses optsWithGlobals() so the parent program's --dry-run flag is not
shadowed by the subcommand's local options (commander v13 behavior).

Tests: +10 unit tests covering encoding, coin formatting, description
parsing. Total: 1307 → 1317.

SSOT compliance:
- Rule #2: unknown outcome/side throws SYMBOL_NOT_FOUND/INVALID_PARAMS;
  notional below $10 throws INVALID_PARAMS with remediation.
- Rule #3: no new env vars, reuses existing HL agent.

Out of scope for this commit (deferred):
- Portfolio aggregation of outcome holdings
- Landing page outcome line
- close subcommand (use sell with --limit + notional for now)
- HIP-4 builder/deployer mechanics

Plan reference: .omc/plans/v0.13.0-outcome.md (local).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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