feat: Add interactive trade-ui CLI command#1352
Closed
Conversation
Rich-based TUI that displays the strategy's trading universe with balances, lets the user interactively pick a pair, amount and trade mode, then executes the test trade via the existing make_test_trade() path. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Verify the open+close round-trip: buy is a buy, sell is a sell, same pair, position is closed, reserves still have balance. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
No need to start a separate Anvil fork — the simulate flag handles it via create_web3_config(). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…allet log format - Use getattr() with default in universe_model.py so strategies without required_history_period don't crash - Update check_wallet logging to show "Hot wallet reserve balance" and "Vault reserve balance" labels with token names Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace choose_single_chain() with configure_default_chain() so the command works when multiple JSON_RPC_* env vars are set - Update docstring example to use hyper-ai-test.py strategy Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Copy strategies/hyper-ai.py to strategies/test_only/hyper-ai-tui-test.py for use as the trade-ui example and integration test strategy - Update docstring example to use the new test strategy - Use configure_default_chain() instead of choose_single_chain() to fix crash when multiple JSON_RPC_* env vars are set Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- HypercoreVaultPricing.get_mid_price() now returns approximate share prices from the data pipeline candle universe instead of always 1.0 - Extensively document the pricing model hacks: 1:1 execution pricing, approximate candle prices, post-deposit API valuation - Wire candle_universe through ethereum_protocol_adapters into the pricing model - Add Hypercore->Hyperliquid connection fallback in web3config - Upgrade TUI to full-screen Textual app with DataTable, modal trade dialog, status bar, TVL-sorted pairs, and share price column - Add textual dependency for Rich-based TUI framework - Add 7 unit tests for candle-based pricing and TUI price display Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Non-vault pairs trigger RPC calls that retry endlessly on Anvil forks. Only fetch prices for vault pairs (candle-based, no RPC needed). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- default_supported_routers() now only creates routing for exchanges that have actual loaded pairs, preventing RPC errors when vault metadata includes exchanges from other chains (e.g. Uniswap on Ethereum appearing in a HyperEVM-only vault universe) - Gate SUPPORTING_PAIRS in hyper-ai-tui-test.py to empty list in live trading mode since Uniswap does not exist on HyperEVM Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Hypercore vaults use exchange_type=erc_4626_vault in metadata but are NOT ERC-4626 contracts. When Hypercore vault routing is detected, skip the ERC-4626 vault routing to prevent empty 0x RPC responses from calling ERC-4626 methods on Hypercore vault addresses. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Update all erc_4626_vault type checks to handle the new hypercore_vault exchange type from the trading-strategy submodule: - default_supported_routers skips hypercore_vault exchanges cleanly - trading_strategy_universe uses correct type for Hypercore pairs - dex_data_translation recognises hypercore_vault as vault kind - reverse_universe uses correct dex_type string Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Old cached vault data uses erc_4626_vault exchange type for Hypercore vaults. default_supported_routers() was creating ERC-4626 routing for these, causing RPC calls to non-existent contracts on HyperEVM. Fix: skip erc_4626_vault exchanges that belong to known Hypercore vaults (by exchange_id or chain_id fallback). Genuine ERC-4626 vaults on other chains are preserved — mixed universes work correctly. Also fix pre-existing typo: vault_done -> vaults_done flag name. Add 4 test cases for default_supported_routers covering: - Hypercore-only universe (no ERC-4626 routing) - Missing vault_protocol metadata (chain-based fallback) - Mixed Hypercore + ERC-4626 universe (both routing types) - New hypercore_vault exchange type Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…smatch Root cause: Vault.export_as_exchange() checked protocol_slug == 'hypercore' but the API returns 'hyperliquid', so all Hypercore vaults were exported as erc_4626_vault. This caused default_supported_routers to create ERC-4626 routing which makes RPC calls to non-existent contracts on HyperEVM. Fix in trading-strategy submodule: match both 'hypercore' and 'hyperliquid'. Fix in default_supported_routers: detect Hypercore vaults by chain_id (9999/999) as fallback for stale cached data, instead of relying on other_data.vault_protocol which doesn't exist in vault pair exports. Add test_hypercore_vault_load.py: integration tests with real API data verifying export types and routing. Add test_trade_ui_hypercore.py: CLI integration test for trade-ui with Hypercore strategy. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tection
Replace all other_data.get("vault_protocol") == "hypercore" checks with
the new is_hyperliquid_vault() method that detects by chain_id. The
other_data field doesn't carry vault_protocol for vault-exported pairs,
so the old detection never fired.
Also:
- Skip value_func creation in hot_wallet mode (no vault object)
- Relax assert to warning in create_hypercore_vault_adapter when no
value_func (allows candle-only pricing for display)
- Guard tx_builder.vault access with hasattr check
- Add unit_testing mode to trade-ui: auto-selects first pair, skips trade
- Working CLI integration test for trade-ui with Hypercore strategy
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Both chain IDs are needed: - 9999 (hypercore): synthetic ID for vault-universe-exported pairs - 999 (hyperliquid): HyperEVM, used by manually created vault pairs in live Lagoon deployments where contracts live on-chain Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The test was using LOG_LEVEL=info which floods CI output with thousands of lines from data loading. Set to warning and simplify assertions — command completion without timeout proves success. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
These tests had LOG_LEVEL=info left over from debugging, flooding CI output with thousands of lines from data loading and RPC calls. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Hyperliquid silently rejects vault deposits below 5 USDC — no error, no event, the USDC just stays in the escrow. Add an early assertion in _create_deposit_or_withdraw_txs() using MINIMUM_VAULT_DEPOSIT from eth_defi.hyperliquid.core_writer (5_000_000 raw, 6 decimals) to fail fast with a clear error message. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. _get_share_price_from_candles() now uses the caller's ts instead of hard-coding native_datetime_utc_now(). Historical valuation and visualisation paths now get the correct price for their timestamp. New test verifies a far-past timestamp falls back to 1.0. 2. Add close_only parameter to make_test_trade(). The TUI's "Sell only" mode now correctly maps to close_only=True, which skips the buy and only closes an existing position. Raises RuntimeError if no open position exists, instead of silently opening a new one. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Chain 999 (HyperEVM) is the actual L1 where EVM contracts live — it does NOT host Hypercore vaults. Only chain 9999 (our synthetic ID for native Hyperliquid) should match. Fix create_hypercore_vault_pair() to re-home both base and quote tokens to chain 9999 so the pair's cross-chain assertion passes and is_hyperliquid_vault() detects it correctly. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Fix trade_mode string inconsistency: unit_testing path used "open_only" but TUI produces "open". Now both use "open". - Replace broad except (AttributeError, AssertionError) with a pre-check for tx_builder.vault presence. AssertionError catch was too broad and would suppress legitimate failures. - Pass single timestamp to _get_price() loop instead of calling native_datetime_utc_now() per pair during TUI init. - Move native_datetime_utc_now import to module level in trade_ui_tui.py. - Fix misleading docstring: _auto_discover_hypercore_vault only matches chain 9999, not "9999 or 999". Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- test_allocation: add is_hyperliquid_vault() to DummyPair mock - test_hyper_ai_allocation_lockup: use ChainId.hypercore and TradingPairKind.vault so is_hyperliquid_vault() detects the pairs - test_lagoon_e2e: set UNIT_TESTING=false for trade-ui test so the mock selection runs and trade execution isn't skipped Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.
Why
The trade executor needed an interactive CLI command for test trading - selecting pairs, choosing buy/sell direction, and specifying amounts - without manually constructing long CLI invocations. Additionally, Hypercore vault strategies were crashing at startup because the routing system could not correctly identify Hypercore vaults vs ERC-4626 vaults.
Lessons learnt
protocol_slug=hyperliquidfor Hypercore vaults, butexport_as_exchange()checked forhypercore. Always verify actual API data before writing string comparisons.vault_protocolinother_data. Chain ID is the reliable discriminator - addedTradingPairIdentifier.is_hyperliquid_vault()to centralise this logic.--simulateis set, all configured JSON-RPC env vars spawn Anvil forks. Strategies that only need one chain must filter to their required chain before forking.warningordisabledunless they specifically assert on log messages.Summary
trade-uiCLI command with Textual-based full-screen TUI for interactive test trade pair selectionTradingPairIdentifier.is_hyperliquid_vault()helper, replace 10+ manualother_data.vault_protocolchecks across the codebaseHypercoreVaultPricing.candle_universesupport for displaying approximate share pricesprotocol_slugmismatch in trading-strategy submodule (hyperliquid vs hypercore)default_supported_routers: detect Hypercore vaults by chain_id as fallback for stale cached datacreate_hypercore_vault_adapteragainst hot_wallet mode (no vault object)hyper-ai-tui-test.pytest strategy for Hypercore vault TUI testingtest_default_supported_routers,test_hypercore_vault_load,test_hypercore_vault_pricing_candles,test_trade_ui_hypercore